Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-f…
Browse files Browse the repository at this point in the history
…or-linus

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
  lguest: struct device - replace bus_id with dev_name()
  lguest: move the initial guest page table creation code to the host
  kvm-s390: implement config_changed for virtio on s390
  virtio_console: support console resizing
  virtio: add PCI device release() function
  virtio_blk: fix type warning
  virtio: block: dynamic maximum segments
  virtio: set max_segment_size and max_sectors to infinite.
  virtio: avoid implicit use of Linux page size in balloon interface
  virtio: hand virtio ring alignment as argument to vring_new_virtqueue
  virtio: use KVM_S390_VIRTIO_RING_ALIGN instead of relying on pagesize
  virtio: use LGUEST_VRING_ALIGN instead of relying on pagesize
  virtio: Don't use PAGE_SIZE for vring alignment in virtio_pci.
  virtio: rename 'pagesize' arg to vring_init/vring_size
  virtio: Don't use PAGE_SIZE in virtio_pci.c
  virtio: struct device - replace bus_id with dev_name(), dev_set_name()
  virtio-pci queue allocation not page-aligned
  • Loading branch information
Linus Torvalds committed Dec 31, 2008
2 parents 14a3c4a + bda53cd commit ab70537
Show file tree
Hide file tree
Showing 20 changed files with 253 additions and 135 deletions.
66 changes: 9 additions & 57 deletions Documentation/lguest/lguest.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,51 +481,6 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
/* We return the initrd size. */
return len;
}

/* Once we know how much memory we have we can construct simple linear page
* tables which set virtual == physical which will get the Guest far enough
* into the boot to create its own.
*
* We lay them out of the way, just below the initrd (which is why we need to
* know its size here). */
static unsigned long setup_pagetables(unsigned long mem,
unsigned long initrd_size)
{
unsigned long *pgdir, *linear;
unsigned int mapped_pages, i, linear_pages;
unsigned int ptes_per_page = getpagesize()/sizeof(void *);

mapped_pages = mem/getpagesize();

/* Each PTE page can map ptes_per_page pages: how many do we need? */
linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;

/* We put the toplevel page directory page at the top of memory. */
pgdir = from_guest_phys(mem) - initrd_size - getpagesize();

/* Now we use the next linear_pages pages as pte pages */
linear = (void *)pgdir - linear_pages*getpagesize();

/* Linear mapping is easy: put every page's address into the mapping in
* order. PAGE_PRESENT contains the flags Present, Writable and
* Executable. */
for (i = 0; i < mapped_pages; i++)
linear[i] = ((i * getpagesize()) | PAGE_PRESENT);

/* The top level points to the linear page table pages above. */
for (i = 0; i < mapped_pages; i += ptes_per_page) {
pgdir[i/ptes_per_page]
= ((to_guest_phys(linear) + i*sizeof(void *))
| PAGE_PRESENT);
}

verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
mapped_pages, linear_pages, to_guest_phys(linear));

/* We return the top level (guest-physical) address: the kernel needs
* to know where it is. */
return to_guest_phys(pgdir);
}
/*:*/

/* Simple routine to roll all the commandline arguments together with spaces
Expand All @@ -548,13 +503,13 @@ static void concat(char *dst, char *args[])

/*L:185 This is where we actually tell the kernel to initialize the Guest. We
* saw the arguments it expects when we looked at initialize() in lguest_user.c:
* the base of Guest "physical" memory, the top physical page to allow, the
* top level pagetable and the entry point for the Guest. */
static int tell_kernel(unsigned long pgdir, unsigned long start)
* the base of Guest "physical" memory, the top physical page to allow and the
* entry point for the Guest. */
static int tell_kernel(unsigned long start)
{
unsigned long args[] = { LHREQ_INITIALIZE,
(unsigned long)guest_base,
guest_limit / getpagesize(), pgdir, start };
guest_limit / getpagesize(), start };
int fd;

verbose("Guest: %p - %p (%#lx)\n",
Expand Down Expand Up @@ -1030,7 +985,7 @@ static void update_device_status(struct device *dev)
/* Zero out the virtqueues. */
for (vq = dev->vq; vq; vq = vq->next) {
memset(vq->vring.desc, 0,
vring_size(vq->config.num, getpagesize()));
vring_size(vq->config.num, LGUEST_VRING_ALIGN));
lg_last_avail(vq) = 0;
}
} else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
Expand Down Expand Up @@ -1211,7 +1166,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
void *p;

/* First we need some memory for this virtqueue. */
pages = (vring_size(num_descs, getpagesize()) + getpagesize() - 1)
pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1)
/ getpagesize();
p = get_pages(pages);

Expand All @@ -1228,7 +1183,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
vq->config.pfn = to_guest_phys(p) / getpagesize();

/* Initialize the vring. */
vring_init(&vq->vring, num_descs, p, getpagesize());
vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);

/* Append virtqueue to this device's descriptor. We use
* device_config() to get the end of the device's current virtqueues;
Expand Down Expand Up @@ -1941,7 +1896,7 @@ int main(int argc, char *argv[])
{
/* Memory, top-level pagetable, code startpoint and size of the
* (optional) initrd. */
unsigned long mem = 0, pgdir, start, initrd_size = 0;
unsigned long mem = 0, start, initrd_size = 0;
/* Two temporaries and the /dev/lguest file descriptor. */
int i, c, lguest_fd;
/* The boot information for the Guest. */
Expand Down Expand Up @@ -2040,9 +1995,6 @@ int main(int argc, char *argv[])
boot->hdr.type_of_loader = 0xFF;
}

/* Set up the initial linear pagetables, starting below the initrd. */
pgdir = setup_pagetables(mem, initrd_size);

/* The Linux boot header contains an "E820" memory map: ours is a
* simple, single region. */
boot->e820_entries = 1;
Expand All @@ -2064,7 +2016,7 @@ int main(int argc, char *argv[])

/* We tell the kernel to initialize the Guest: this returns the open
* /dev/lguest file descriptor. */
lguest_fd = tell_kernel(pgdir, start);
lguest_fd = tell_kernel(start);

/* We clone off a thread, which wakes the Launcher whenever one of the
* input file descriptors needs attention. We call this the Waker, and
Expand Down
4 changes: 4 additions & 0 deletions arch/s390/include/asm/kvm_virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ struct kvm_vqconfig {
#define KVM_S390_VIRTIO_RESET 1
#define KVM_S390_VIRTIO_SET_STATUS 2

/* The alignment to use between consumer and producer parts of vring.
* This is pagesize for historical reasons. */
#define KVM_S390_VIRTIO_RING_ALIGN 4096

#ifdef __KERNEL__
/* early virtio console setup */
#ifdef CONFIG_S390_GUEST
Expand Down
15 changes: 0 additions & 15 deletions arch/x86/lguest/i386_head.S
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,6 @@ ENTRY(lguest_entry)
movl $lguest_data - __PAGE_OFFSET, %edx
int $LGUEST_TRAP_ENTRY

/* The Host put the toplevel pagetable in lguest_data.pgdir. The movsl
* instruction uses %esi implicitly as the source for the copy we're
* about to do. */
movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi

/* Copy first 32 entries of page directory to __PAGE_OFFSET entries.
* This means the first 128M of kernel memory will be mapped at
* PAGE_OFFSET where the kernel expects to run. This will get it far
* enough through boot to switch to its own pagetables. */
movl $32, %ecx
movl %esi, %edi
addl $((__PAGE_OFFSET >> 22) * 4), %edi
rep
movsl

/* Set up the initial stack so we can run C code. */
movl $(init_thread_union+THREAD_SIZE),%esp

Expand Down
41 changes: 28 additions & 13 deletions drivers/block/virtio_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <linux/virtio_blk.h>
#include <linux/scatterlist.h>

#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS)
#define PART_BITS 4

static int major, index;
Expand All @@ -26,8 +25,11 @@ struct virtio_blk

mempool_t *pool;

/* What host tells us, plus 2 for header & tailer. */
unsigned int sg_elems;

/* Scatterlist: can be too big for stack. */
struct scatterlist sg[VIRTIO_MAX_SG];
struct scatterlist sg[/*sg_elems*/];
};

struct virtblk_req
Expand Down Expand Up @@ -97,8 +99,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
if (blk_barrier_rq(vbr->req))
vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;

/* This init could be done at vblk creation time */
sg_init_table(vblk->sg, VIRTIO_MAX_SG);
sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
Expand Down Expand Up @@ -130,7 +130,7 @@ static void do_virtblk_request(struct request_queue *q)

while ((req = elv_next_request(q)) != NULL) {
vblk = req->rq_disk->private_data;
BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);

/* If this request fails, stop queue and wait for something to
finish to restart it. */
Expand Down Expand Up @@ -196,12 +196,22 @@ static int virtblk_probe(struct virtio_device *vdev)
int err;
u64 cap;
u32 v;
u32 blk_size;
u32 blk_size, sg_elems;

if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC;

vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
/* We need to know how many segments before we allocate. */
err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
offsetof(struct virtio_blk_config, seg_max),
&sg_elems);
if (err)
sg_elems = 1;

/* We need an extra sg elements at head and tail. */
sg_elems += 2;
vdev->priv = vblk = kmalloc(sizeof(*vblk) +
sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL);
if (!vblk) {
err = -ENOMEM;
goto out;
Expand All @@ -210,6 +220,8 @@ static int virtblk_probe(struct virtio_device *vdev)
INIT_LIST_HEAD(&vblk->reqs);
spin_lock_init(&vblk->lock);
vblk->vdev = vdev;
vblk->sg_elems = sg_elems;
sg_init_table(vblk->sg, vblk->sg_elems);

/* We expect one virtqueue, for output. */
vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
Expand Down Expand Up @@ -279,19 +291,22 @@ static int virtblk_probe(struct virtio_device *vdev)
}
set_capacity(vblk->disk, cap);

/* We can handle whatever the host told us to handle. */
blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);

/* No real sector limit. */
blk_queue_max_sectors(vblk->disk->queue, -1U);

/* Host can optionally specify maximum segment size and number of
* segments. */
err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
offsetof(struct virtio_blk_config, size_max),
&v);
if (!err)
blk_queue_max_segment_size(vblk->disk->queue, v);

err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
offsetof(struct virtio_blk_config, seg_max),
&v);
if (!err)
blk_queue_max_hw_segments(vblk->disk->queue, v);
else
blk_queue_max_segment_size(vblk->disk->queue, -1U);

/* Host can optionally specify the block size of the device */
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
Expand Down
1 change: 1 addition & 0 deletions drivers/char/hvc_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ void hvc_resize(struct hvc_struct *hp, struct winsize ws)
hp->ws = ws;
schedule_work(&hp->tty_resize);
}
EXPORT_SYMBOL_GPL(hvc_resize);

/*
* This kthread is either polling or interrupt driven. This is determined by
Expand Down
30 changes: 29 additions & 1 deletion drivers/char/virtio_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,34 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
return hvc_instantiate(0, 0, &virtio_cons);
}

/*
* virtio console configuration. This supports:
* - console resize
*/
static void virtcons_apply_config(struct virtio_device *dev)
{
struct winsize ws;

if (virtio_has_feature(dev, VIRTIO_CONSOLE_F_SIZE)) {
dev->config->get(dev,
offsetof(struct virtio_console_config, cols),
&ws.ws_col, sizeof(u16));
dev->config->get(dev,
offsetof(struct virtio_console_config, rows),
&ws.ws_row, sizeof(u16));
hvc_resize(hvc, ws);
}
}

/*
* we support only one console, the hvc struct is a global var
* There is no need to do anything
* We set the configuration at this point, since we now have a tty
*/
static int notifier_add_vio(struct hvc_struct *hp, int data)
{
hp->irq_requested = 1;
virtcons_apply_config(vdev);

return 0;
}

Expand Down Expand Up @@ -234,11 +255,18 @@ static struct virtio_device_id id_table[] = {
{ 0 },
};

static unsigned int features[] = {
VIRTIO_CONSOLE_F_SIZE,
};

static struct virtio_driver virtio_console = {
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
.probe = virtcons_probe,
.config_changed = virtcons_apply_config,
};

static int __init init(void)
Expand Down
2 changes: 1 addition & 1 deletion drivers/lguest/lg.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt);
void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);

/* page_tables.c: */
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
int init_guest_pagetable(struct lguest *lg);
void free_guest_pagetable(struct lguest *lg);
void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
Expand Down
8 changes: 4 additions & 4 deletions drivers/lguest/lguest_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
/* Figure out how many pages the ring will take, and map that memory */
lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
DIV_ROUND_UP(vring_size(lvq->config.num,
PAGE_SIZE),
LGUEST_VRING_ALIGN),
PAGE_SIZE));
if (!lvq->pages) {
err = -ENOMEM;
Expand All @@ -259,8 +259,8 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,

/* OK, tell virtio_ring.c to set up a virtqueue now we know its size
* and we've got a pointer to its pages. */
vq = vring_new_virtqueue(lvq->config.num, vdev, lvq->pages,
lg_notify, callback);
vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
vdev, lvq->pages, lg_notify, callback);
if (!vq) {
err = -ENOMEM;
goto unmap;
Expand All @@ -272,7 +272,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
* the interrupt as a source of randomness: it'd be nice to have that
* back.. */
err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
vdev->dev.bus_id, vq);
dev_name(&vdev->dev), vq);
if (err)
goto destroy_vring;

Expand Down
Loading

0 comments on commit ab70537

Please sign in to comment.