Skip to content

Commit 8e58006

Browse files
asherkarivchessturo
authored andcommitted
swiotlb, hyperv: add dedicated swiotlb pool for Hyper-V VPCI devices
Add swiotlb_create_pool(), a new API that creates a standalone swiotlb bounce buffer pool backed by a caller-specified physical memory region. This is similar to CONFIG_DMA_RESTRICTED_POOL but does not require Device Tree or OF support. Use this in the Hyper-V PCI frontend driver (pci-hyperv) to allow dedicating a specific RAM region for streaming DMA bounce buffering of all VPCI devices. This is useful when VPCI devices can only DMA via a specific portion of guest RAM determined at boot time. The pool is configured via the hv_pci module parameter 'swiotlb', and the corresponding memory must be reserved so the kernel does not use it for general allocations. This is done with a command line parameter as shown in the example below. The 'swiotlb=force' is added to enable the use of swiotlb. Sample kernel command line: swiotlb=force hv_pci_swiotlb=0x100000000,64M This reserves 64MB at the 4GB mark and directs the Hyper-V PCI driver to create a swiotlb pool there. All VPCI devices will then bounce their streaming DMA through that region. Coherent DMA allocations (dma_alloc_coherent) are not affected and continue to use normal memory.
1 parent 7d0a66e commit 8e58006

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

drivers/pci/controller/pci-hyperv.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
#include <linux/acpi.h>
5353
#include <linux/sizes.h>
5454
#include <linux/of_irq.h>
55+
#include <linux/swiotlb.h>
56+
#include <linux/memblock.h>
5557
#include <asm/mshyperv.h>
5658

5759
/*
@@ -468,6 +470,22 @@ struct pci_eject_response {
468470

469471
static int pci_ring_size = VMBUS_RING_SIZE(SZ_16K);
470472

473+
static phys_addr_t hv_pci_swiotlb_base;
474+
static size_t hv_pci_swiotlb_size;
475+
476+
static int __init early_hv_pci_swiotlb(char *p)
477+
{
478+
hv_pci_swiotlb_base = memparse(p, &p);
479+
if (*p == ',')
480+
hv_pci_swiotlb_size = memparse(p + 1, NULL);
481+
if (hv_pci_swiotlb_base && hv_pci_swiotlb_size)
482+
memblock_reserve(hv_pci_swiotlb_base, hv_pci_swiotlb_size);
483+
return 0;
484+
}
485+
early_param("hv_pci_swiotlb", early_hv_pci_swiotlb);
486+
487+
static struct io_tlb_mem *hv_pci_swiotlb_pool;
488+
471489
/*
472490
* Driver specific state.
473491
*/
@@ -2502,6 +2520,25 @@ static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
25022520
}
25032521
}
25042522

2523+
/**
2524+
* hv_pci_assign_swiotlb() - assign dedicated swiotlb pool to bus devices
2525+
* @bus: PCI bus whose devices should use the pool
2526+
*
2527+
* If a dedicated swiotlb pool was configured via hv_pci_swiotlb=,
2528+
* assign it to every device on the bus so their DMA bounce buffering
2529+
* uses the restricted region.
2530+
*/
2531+
static void hv_pci_assign_swiotlb(struct pci_bus *bus)
2532+
{
2533+
struct pci_dev *dev;
2534+
2535+
if (!hv_pci_swiotlb_pool)
2536+
return;
2537+
2538+
list_for_each_entry(dev, &bus->devices, bus_list)
2539+
dev->dev.dma_io_tlb_mem = hv_pci_swiotlb_pool;
2540+
}
2541+
25052542
/**
25062543
* create_root_hv_pci_bus() - Expose a new root PCI bus
25072544
* @hbus: Root PCI bus, as understood by this driver
@@ -2525,6 +2562,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
25252562
hv_pci_assign_numa_node(hbus);
25262563
pci_bus_assign_resources(bridge->bus);
25272564
hv_pci_assign_slots(hbus);
2565+
hv_pci_assign_swiotlb(bridge->bus);
25282566
pci_bus_add_devices(bridge->bus);
25292567
pci_unlock_rescan_remove();
25302568
hbus->state = hv_pcibus_installed;
@@ -2795,6 +2833,7 @@ static void pci_devices_present_work(struct work_struct *work)
27952833
pci_scan_child_bus(hbus->bridge->bus);
27962834
hv_pci_assign_numa_node(hbus);
27972835
hv_pci_assign_slots(hbus);
2836+
hv_pci_assign_swiotlb(hbus->bridge->bus);
27982837
pci_unlock_rescan_remove();
27992838
break;
28002839

@@ -4213,6 +4252,17 @@ static int __init init_hv_pci_drv(void)
42134252
if (hv_root_partition() && !hv_nested)
42144253
return -ENODEV;
42154254

4255+
if (hv_pci_swiotlb_base && hv_pci_swiotlb_size) {
4256+
hv_pci_swiotlb_pool = swiotlb_create_pool(hv_pci_swiotlb_base,
4257+
hv_pci_swiotlb_size,
4258+
"hv-pci-swiotlb");
4259+
if (IS_ERR(hv_pci_swiotlb_pool)) {
4260+
pr_err("hv_pci: failed to create swiotlb pool: %ld\n",
4261+
PTR_ERR(hv_pci_swiotlb_pool));
4262+
hv_pci_swiotlb_pool = NULL;
4263+
}
4264+
}
4265+
42164266
ret = hv_pci_irqchip_init();
42174267
if (ret)
42184268
return ret;

include/linux/swiotlb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ bool is_swiotlb_active(struct device *dev);
185185
void __init swiotlb_adjust_size(unsigned long size);
186186
phys_addr_t default_swiotlb_base(void);
187187
phys_addr_t default_swiotlb_limit(void);
188+
struct io_tlb_mem *swiotlb_create_pool(phys_addr_t base, size_t size,
189+
const char *name);
188190
#else
189191
static inline void swiotlb_init(bool addressing_limited, unsigned int flags)
190192
{

kernel/dma/swiotlb.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,3 +1881,67 @@ static int __init rmem_swiotlb_setup(struct reserved_mem *rmem)
18811881

18821882
RESERVEDMEM_OF_DECLARE(dma, "restricted-dma-pool", rmem_swiotlb_setup);
18831883
#endif /* CONFIG_DMA_RESTRICTED_POOL */
1884+
1885+
/**
1886+
* swiotlb_create_pool() - create a swiotlb pool from a physical memory region
1887+
* @base: Physical base address of the region.
1888+
* @size: Size of the region in bytes.
1889+
* @name: Name for debugfs (may be NULL).
1890+
*
1891+
* Allocates and initializes an io_tlb_mem with its default pool backed by the
1892+
* caller-provided physical memory. The region must already be reserved (e.g.
1893+
* via memblock_reserve or firmware memory map) and within the linear mapping.
1894+
*
1895+
* The returned pool has force_bounce set so that streaming DMA is bounced
1896+
* through this region. Assign it to dev->dma_io_tlb_mem to direct a device's
1897+
* DMA bounce buffering into this region. Coherent DMA allocations
1898+
* (dma_alloc_coherent) are not affected and will use normal memory.
1899+
*
1900+
* Return: pointer to a new io_tlb_mem on success, ERR_PTR on failure.
1901+
*/
1902+
struct io_tlb_mem *swiotlb_create_pool(phys_addr_t base, size_t size,
1903+
const char *name)
1904+
{
1905+
struct io_tlb_mem *mem;
1906+
struct io_tlb_pool *pool;
1907+
unsigned long nslabs = size >> IO_TLB_SHIFT;
1908+
unsigned int nareas = 1;
1909+
1910+
if (PageHighMem(pfn_to_page(PHYS_PFN(base))))
1911+
return ERR_PTR(-EINVAL);
1912+
1913+
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
1914+
if (!mem)
1915+
return ERR_PTR(-ENOMEM);
1916+
pool = &mem->defpool;
1917+
1918+
pool->slots = kcalloc(nslabs, sizeof(*pool->slots), GFP_KERNEL);
1919+
if (!pool->slots) {
1920+
kfree(mem);
1921+
return ERR_PTR(-ENOMEM);
1922+
}
1923+
1924+
pool->areas = kcalloc(nareas, sizeof(*pool->areas), GFP_KERNEL);
1925+
if (!pool->areas) {
1926+
kfree(pool->slots);
1927+
kfree(mem);
1928+
return ERR_PTR(-ENOMEM);
1929+
}
1930+
1931+
set_memory_decrypted((unsigned long)phys_to_virt(base),
1932+
size >> PAGE_SHIFT);
1933+
swiotlb_init_io_tlb_pool(pool, base, nslabs, false, nareas);
1934+
mem->force_bounce = true;
1935+
mem->for_alloc = false;
1936+
#ifdef CONFIG_SWIOTLB_DYNAMIC
1937+
spin_lock_init(&mem->lock);
1938+
INIT_LIST_HEAD_RCU(&mem->pools);
1939+
#endif
1940+
add_mem_pool(mem, pool);
1941+
swiotlb_create_debugfs_files(mem, name ?: "swiotlb-pool");
1942+
1943+
pr_info("created restricted pool at %pa, size %zuMiB\n",
1944+
&base, size / SZ_1M);
1945+
return mem;
1946+
}
1947+
EXPORT_SYMBOL_GPL(swiotlb_create_pool);

0 commit comments

Comments
 (0)