Skip to content
Draft
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
133 changes: 115 additions & 18 deletions drivers/pci/controller/pci-hyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,15 +472,20 @@ static int pci_ring_size = VMBUS_RING_SIZE(SZ_16K);

static phys_addr_t hv_pci_swiotlb_base;
static size_t hv_pci_swiotlb_size;
static struct page *hv_pci_swiotlb_pages;
static unsigned long hv_pci_swiotlb_nr_pages;

/* Parse hv_pci_swiotlb=<size>; the base is picked at core_initcall time. */
static int __init early_hv_pci_swiotlb(char *p)
{
hv_pci_swiotlb_base = memparse(p, &p);
if (*p == ',')
hv_pci_swiotlb_size = memparse(p + 1, NULL);
if (hv_pci_swiotlb_base && hv_pci_swiotlb_size)
memblock_reserve(hv_pci_swiotlb_base, hv_pci_swiotlb_size);
return 0;
if (!p || !*p)
return 0;

hv_pci_swiotlb_size = memparse(p, NULL);
if (hv_pci_swiotlb_size)
hv_pci_swiotlb_size = ALIGN(hv_pci_swiotlb_size, SZ_2M);

return 0;
}
Comment on lines 479 to 489
Comment on lines 479 to 489
early_param("hv_pci_swiotlb", early_hv_pci_swiotlb);

Expand Down Expand Up @@ -4241,10 +4246,44 @@ static struct hv_driver hv_pci_drv = {
.resume = hv_pci_resume,
};

/* Publish swiotlb_{base,size} so userspace can forward the GPA to the host. */
static ssize_t swiotlb_base_show(struct device_driver *drv, char *buf)
{
return sysfs_emit(buf, "0x%llx\n",
(unsigned long long)hv_pci_swiotlb_base);
}
static DRIVER_ATTR_RO(swiotlb_base);

static ssize_t swiotlb_size_show(struct device_driver *drv, char *buf)
{
return sysfs_emit(buf, "%zu\n", hv_pci_swiotlb_size);
}
static DRIVER_ATTR_RO(swiotlb_size);

static void hv_pci_swiotlb_unpublish(void)
{
driver_remove_file(&hv_pci_drv.driver, &driver_attr_swiotlb_size);
driver_remove_file(&hv_pci_drv.driver, &driver_attr_swiotlb_base);
}

static void hv_pci_swiotlb_publish(void)
{
if (driver_create_file(&hv_pci_drv.driver, &driver_attr_swiotlb_base) ||
driver_create_file(&hv_pci_drv.driver, &driver_attr_swiotlb_size)) {
pr_warn("hv_pci: failed to publish swiotlb range to sysfs\n");
hv_pci_swiotlb_unpublish();
}
}

static void __exit exit_hv_pci_drv(void)
{
if (hv_pci_swiotlb_pool)
Comment on lines +4263 to +4280
hv_pci_swiotlb_unpublish();

vmbus_driver_unregister(&hv_pci_drv);

/* No swiotlb_destroy_pool() exists, so hv_pci_swiotlb_pages is leaked. */

hvpci_block_ops.read_block = NULL;
hvpci_block_ops.write_block = NULL;
hvpci_block_ops.reg_blk_invalidate = NULL;
Expand All @@ -4260,17 +4299,6 @@ static int __init init_hv_pci_drv(void)
if (hv_root_partition() && !hv_nested)
return -ENODEV;

if (hv_pci_swiotlb_base && hv_pci_swiotlb_size) {
hv_pci_swiotlb_pool = swiotlb_create_pool(hv_pci_swiotlb_base,
hv_pci_swiotlb_size,
"hv-pci-swiotlb");
if (IS_ERR(hv_pci_swiotlb_pool)) {
pr_err("hv_pci: failed to create swiotlb pool: %ld\n",
PTR_ERR(hv_pci_swiotlb_pool));
hv_pci_swiotlb_pool = NULL;
}
}

ret = hv_pci_irqchip_init();
if (ret)
return ret;
Expand All @@ -4283,9 +4311,78 @@ static int __init init_hv_pci_drv(void)
hvpci_block_ops.write_block = hv_write_config_block;
hvpci_block_ops.reg_blk_invalidate = hv_register_block_invalidate;

return vmbus_driver_register(&hv_pci_drv);
ret = vmbus_driver_register(&hv_pci_drv);
if (ret)
return ret;

if (hv_pci_swiotlb_pool)
hv_pci_swiotlb_publish();

return 0;
}

#ifdef CONFIG_CONTIG_ALLOC
/*
* Reserve the hv_pci swiotlb pool from the buddy allocator. __GFP_DMA32
* keeps the range below 4 GiB; kernel ownership keeps Hyper-V page
* reporting from yanking the backing. Gated on CONFIG_CONTIG_ALLOC.
*/
static int __init hv_pci_swiotlb_alloc_pool(void)
{
phys_addr_t end;
unsigned long nr_pages;
struct page *pages;

if (!hv_pci_swiotlb_size)
return 0;

nr_pages = hv_pci_swiotlb_size >> PAGE_SHIFT;

/* UMA on WSL; first_online_node biases nothing in practice. */
pages = alloc_contig_pages(nr_pages,
GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO,
first_online_node, &node_online_map);
if (!pages) {
pr_warn("hv_pci: failed to allocate %zu-byte swiotlb pool below 4G; feature disabled\n",
hv_pci_swiotlb_size);
hv_pci_swiotlb_size = 0;
return 0;
}

hv_pci_swiotlb_pages = pages;
hv_pci_swiotlb_nr_pages = nr_pages;
Comment on lines +4352 to +4353
hv_pci_swiotlb_base = page_to_phys(pages);
end = hv_pci_swiotlb_base + hv_pci_swiotlb_size;

pr_info("hv_pci: reserved swiotlb pool [%pa..%pa)\n",
&hv_pci_swiotlb_base, &end);

hv_pci_swiotlb_pool = swiotlb_create_pool(hv_pci_swiotlb_base,
hv_pci_swiotlb_size,
"hv-pci-swiotlb");
if (IS_ERR(hv_pci_swiotlb_pool)) {
pr_err("hv_pci: failed to create swiotlb pool: %ld\n",
PTR_ERR(hv_pci_swiotlb_pool));
hv_pci_swiotlb_pool = NULL;
free_contig_range(page_to_pfn(pages), nr_pages);
hv_pci_swiotlb_pages = NULL;
hv_pci_swiotlb_nr_pages = 0;
hv_pci_swiotlb_base = 0;
hv_pci_swiotlb_size = 0;
}

return 0;
}
#else
static int __init hv_pci_swiotlb_alloc_pool(void)
{
if (hv_pci_swiotlb_size)
pr_warn("hv_pci: CONFIG_CONTIG_ALLOC disabled; hv_pci_swiotlb= ignored\n");
return 0;
}
#endif
core_initcall(hv_pci_swiotlb_alloc_pool);

module_init(init_hv_pci_drv);
module_exit(exit_hv_pci_drv);

Expand Down