Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

virtio_balloon: add support for MMIO devices #2081

Merged
merged 6 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ status virtio_register_config_change_handler(vtdev dev, thunk handler)
{
switch (dev->transport) {
case VTIO_TRANSPORT_MMIO:
return timm("status", "not implemented");
return vtmmio_register_config_change_handler((vtmmio)dev, handler);
case VTIO_TRANSPORT_PCI:
return vtpci_register_config_change_handler((vtpci)dev, handler);
default:
Expand Down
33 changes: 29 additions & 4 deletions src/virtio/virtio_balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#define VIRTIO_BALLOON_PAGE_ORDER PAGELOG

/* These are units that we allocate from the physical heap. */
#define VIRTIO_BALLOON_ALLOC_ORDER 21
/* The maximum number of pages supported by AWS Firecracker in a single inflate descriptor is 256,
* which corresponds to 1 MB of memory, and the balloon allocation unit is sized accordingly. */
#define VIRTIO_BALLOON_ALLOC_ORDER 20
#define VIRTIO_BALLOON_ALLOC_SIZE U64_FROM_BIT(VIRTIO_BALLOON_ALLOC_ORDER)
#define VIRTIO_BALLOON_PAGES_PER_ALLOC U64_FROM_BIT(VIRTIO_BALLOON_ALLOC_ORDER - \
VIRTIO_BALLOON_PAGE_ORDER)
Expand Down Expand Up @@ -86,6 +88,8 @@ struct virtio_balloon_config {
#define VIRTIO_BALLOON_R_NUM_PAGES (offsetof(struct virtio_balloon_config *, num_pages))
#define VIRTIO_BALLOON_R_ACTUAL (offsetof(struct virtio_balloon_config *, actual))

#define VIRTIO_BALLOON_DRV_FEATURES (VIRTIO_BALLOON_F_STATS_VQ | VIRTIO_BALLOON_F_MUST_TELL_HOST)

static inline boolean balloon_must_tell_host(void)
{
return (virtio_balloon.dev->features & VIRTIO_BALLOON_F_MUST_TELL_HOST) != 0;
Expand Down Expand Up @@ -406,14 +410,35 @@ closure_function(3, 1, boolean, vtpci_balloon_probe,

virtio_balloon_debug(" attaching\n", __func__);
vtdev v = (vtdev)attach_vtpci(bound(general), bound(backed), d,
(VIRTIO_BALLOON_F_STATS_VQ |
VIRTIO_BALLOON_F_MUST_TELL_HOST));
VIRTIO_BALLOON_DRV_FEATURES);
return virtio_balloon_attach(bound(general), bound(backed), bound(physical), v);
}

closure_function(3, 1, void, vtmmio_balloon_probe,
heap, general, backed_heap, backed, id_heap, physical,
vtmmio dev)
{
virtio_balloon_debug("MMIO probe\n", func_ss);
if ((vtmmio_get_u32(dev, VTMMIO_OFFSET_DEVID) != VIRTIO_ID_BALLOON) ||
(dev->memsize < VTMMIO_OFFSET_CONFIG + sizeof(struct virtio_balloon_config)))
return;
heap general = bound(general);
backed_heap backed = bound(backed);
if (attach_vtmmio(general, backed, dev, VIRTIO_BALLOON_DRV_FEATURES))
virtio_balloon_attach(general, backed, bound(physical), &dev->virtio_dev);
}

void init_virtio_balloon(kernel_heaps kh)
{
virtio_balloon_debug("%s\n", func_ss);
heap h = heap_locked(kh);
register_pci_driver(closure(h, vtpci_balloon_probe, h, heap_linear_backed(kh), heap_physical(kh)), 0);
backed_heap backed = heap_linear_backed(kh);
id_heap physical = heap_physical(kh);
pci_probe probe = closure(h, vtpci_balloon_probe, h, backed, physical);
if (probe == INVALID_ADDRESS) {
msg_err("%s: out of memory", func_ss);
return;
}
register_pci_driver(probe, 0);
vtmmio_probe_devs(stack_closure(vtmmio_balloon_probe, h, backed, physical));
}
37 changes: 28 additions & 9 deletions src/virtio/virtio_mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ closure_function(1, 1, void, vtmmio_new_dev,
dev->vbase += page_offset;
dev->irq_vector = 0;
dev->vq_handlers = allocate_vector(h, 2);
dev->cfg_chg_handler = 0;
assert(dev->vq_handlers != INVALID_ADDRESS);
vtmmio_set_status(dev, VIRTIO_CONFIG_STATUS_RESET);
list_push_back(&vtmmio_devices, &dev->l);
Expand Down Expand Up @@ -184,6 +185,23 @@ closure_func_basic(thunk, void, vtmmio_irq)
apply(vq_handler);
}
}
if (status & VTMMIO_INT_CONFIG) {
thunk handler = dev->cfg_chg_handler;
if (handler)
apply(handler);
}
}

static void vtmmio_irq_setup(vtmmio dev, range cpu_affinity)
{
u64 irq_vector = allocate_mmio_interrupt();
assert(irq_vector != INVALID_PHYSICAL);
register_interrupt(irq_vector, init_closure_func(&dev->irq_handler, thunk, vtmmio_irq),
ss("vtmmio"));
dev->irq_vector = irq_vector;
#ifdef __x86_64__
ioapic_set_int(dev->irq, irq_vector, irq_get_target_cpu(cpu_affinity));
#endif
}

status vtmmio_alloc_virtqueue(vtmmio dev, sstring name, int idx, range cpu_affinity,
Expand All @@ -203,15 +221,7 @@ status vtmmio_alloc_virtqueue(vtmmio dev, sstring name, int idx, range cpu_affin
if (!is_ok(s))
return s;
if (!dev->irq_vector) {
dev->irq_vector = allocate_mmio_interrupt();
assert(dev->irq_vector != INVALID_PHYSICAL);
register_interrupt(dev->irq_vector,
init_closure_func(&dev->irq_handler, thunk, vtmmio_irq),
name);
// XXX arm
#ifdef __x86_64__
ioapic_set_int(dev->irq, dev->irq_vector, irq_get_target_cpu(cpu_affinity));
#endif
vtmmio_irq_setup(dev, cpu_affinity);
}
vector_push(dev->vq_handlers, handler);
vtmmio_set_u32(dev, VTMMIO_OFFSET_QUEUENUM, size);
Expand All @@ -222,3 +232,12 @@ status vtmmio_alloc_virtqueue(vtmmio dev, sstring name, int idx, range cpu_affin
*result = vq;
return STATUS_OK;
}

status vtmmio_register_config_change_handler(vtmmio dev, thunk handler)
{
virtio_mmio_debug("registering config change handler %F", handler);
if (!dev->irq_vector)
vtmmio_irq_setup(dev, irangel(0, 0));
dev->cfg_chg_handler = handler;
return STATUS_OK;
}
2 changes: 2 additions & 0 deletions src/virtio/virtio_mmio.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ typedef struct vtmmio_dev {
closure_struct(vtdev_notify, notify);
closure_struct(thunk, irq_handler);
vector vq_handlers;
thunk cfg_chg_handler;
} *vtmmio;

#define vtmmio_get_u8(dev, offset) (*((volatile u8 *)((dev)->vbase + offset)))
Expand Down Expand Up @@ -67,3 +68,4 @@ void vtmmio_set_status(vtmmio dev, u8 status);
boolean attach_vtmmio(heap h, backed_heap page_allocator, vtmmio d, u64 feature_mask);
status vtmmio_alloc_virtqueue(vtmmio dev, sstring name, int idx, range cpu_affinity,
struct virtqueue **result);
status vtmmio_register_config_change_handler(vtmmio dev, thunk handler);
Loading