Skip to content

Commit 5f1f670

Browse files
committed
Merge feature/swiotlb-pool/6.18 into v6.18.33
* commit '372aaab4b6fd2031a90cc04d7417223839479db1': PCI: hv: Reserve hv_pci swiotlb from buddy and publish via sysfs swiotlb, hyperv: add dedicated swiotlb pool for Hyper-V VPCI devices
2 parents 85f951f + 372aaab commit 5f1f670

3 files changed

Lines changed: 242 additions & 1 deletion

File tree

drivers/pci/controller/pci-hyperv.c

Lines changed: 176 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <linux/acpi.h>
5353
#include <linux/sizes.h>
5454
#include <linux/of_irq.h>
55+
#include <linux/swiotlb.h>
5556
#include <asm/mshyperv.h>
5657

5758
/*
@@ -468,6 +469,42 @@ struct pci_eject_response {
468469

469470
static int pci_ring_size = VMBUS_RING_SIZE(SZ_16K);
470471

472+
static phys_addr_t hv_pci_swiotlb_base;
473+
static size_t hv_pci_swiotlb_size;
474+
static bool hv_pci_swiotlb_published;
475+
476+
#ifndef MODULE
477+
/*
478+
* Parse hv_pci_swiotlb=<size>; the base is picked when the driver
479+
* initializes. early_param is only available in built-in builds, so the
480+
* dedicated pool feature is effectively built-in only; module builds fall
481+
* back to the default swiotlb pool.
482+
*/
483+
static int __init early_hv_pci_swiotlb(char *p)
484+
{
485+
char *end;
486+
487+
if (!*p)
488+
return 0;
489+
490+
hv_pci_swiotlb_size = memparse(p, &end);
491+
if (*end != '\0') {
492+
pr_warn("hv_pci: ignoring hv_pci_swiotlb=%s; expected hv_pci_swiotlb=<size>\n",
493+
p);
494+
hv_pci_swiotlb_size = 0;
495+
return 0;
496+
}
497+
498+
if (hv_pci_swiotlb_size)
499+
hv_pci_swiotlb_size = ALIGN(hv_pci_swiotlb_size, SZ_2M);
500+
501+
return 0;
502+
}
503+
early_param("hv_pci_swiotlb", early_hv_pci_swiotlb);
504+
#endif /* !MODULE */
505+
506+
static struct io_tlb_mem *hv_pci_swiotlb_pool;
507+
471508
/*
472509
* Driver specific state.
473510
*/
@@ -2510,6 +2547,25 @@ static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
25102547
}
25112548
}
25122549

2550+
/**
2551+
* hv_pci_assign_swiotlb() - assign dedicated swiotlb pool to bus devices
2552+
* @bus: PCI bus whose devices should use the pool
2553+
*
2554+
* If a dedicated swiotlb pool was configured via hv_pci_swiotlb=,
2555+
* assign it to every device on the bus so their DMA bounce buffering
2556+
* uses the restricted region.
2557+
*/
2558+
static void hv_pci_assign_swiotlb(struct pci_bus *bus)
2559+
{
2560+
struct pci_dev *dev;
2561+
2562+
if (!hv_pci_swiotlb_pool)
2563+
return;
2564+
2565+
list_for_each_entry(dev, &bus->devices, bus_list)
2566+
dev->dev.dma_io_tlb_mem = hv_pci_swiotlb_pool;
2567+
}
2568+
25132569
/**
25142570
* create_root_hv_pci_bus() - Expose a new root PCI bus
25152571
* @hbus: Root PCI bus, as understood by this driver
@@ -2533,6 +2589,7 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
25332589
hv_pci_assign_numa_node(hbus);
25342590
pci_bus_assign_resources(bridge->bus);
25352591
hv_pci_assign_slots(hbus);
2592+
hv_pci_assign_swiotlb(bridge->bus);
25362593
pci_bus_add_devices(bridge->bus);
25372594
pci_unlock_rescan_remove();
25382595
hbus->state = hv_pcibus_installed;
@@ -2803,6 +2860,7 @@ static void pci_devices_present_work(struct work_struct *work)
28032860
pci_scan_child_bus(hbus->bridge->bus);
28042861
hv_pci_assign_numa_node(hbus);
28052862
hv_pci_assign_slots(hbus);
2863+
hv_pci_assign_swiotlb(hbus->bridge->bus);
28062864
pci_unlock_rescan_remove();
28072865
break;
28082866

@@ -4202,10 +4260,52 @@ static struct hv_driver hv_pci_drv = {
42024260
.resume = hv_pci_resume,
42034261
};
42044262

4263+
/* Publish swiotlb_{base,size} so userspace can forward the GPA to the host. */
4264+
static ssize_t swiotlb_base_show(struct device_driver *drv, char *buf)
4265+
{
4266+
return sysfs_emit(buf, "0x%llx\n",
4267+
(unsigned long long)hv_pci_swiotlb_base);
4268+
}
4269+
static DRIVER_ATTR_RO(swiotlb_base);
4270+
4271+
static ssize_t swiotlb_size_show(struct device_driver *drv, char *buf)
4272+
{
4273+
return sysfs_emit(buf, "%zu\n", hv_pci_swiotlb_size);
4274+
}
4275+
static DRIVER_ATTR_RO(swiotlb_size);
4276+
4277+
static void hv_pci_swiotlb_unpublish(void)
4278+
{
4279+
if (!hv_pci_swiotlb_published)
4280+
return;
4281+
driver_remove_file(&hv_pci_drv.driver, &driver_attr_swiotlb_size);
4282+
driver_remove_file(&hv_pci_drv.driver, &driver_attr_swiotlb_base);
4283+
hv_pci_swiotlb_published = false;
4284+
}
4285+
4286+
static void hv_pci_swiotlb_publish(void)
4287+
{
4288+
if (driver_create_file(&hv_pci_drv.driver, &driver_attr_swiotlb_base))
4289+
goto warn;
4290+
if (driver_create_file(&hv_pci_drv.driver, &driver_attr_swiotlb_size)) {
4291+
driver_remove_file(&hv_pci_drv.driver, &driver_attr_swiotlb_base);
4292+
goto warn;
4293+
}
4294+
hv_pci_swiotlb_published = true;
4295+
return;
4296+
4297+
warn:
4298+
pr_warn("hv_pci: failed to publish swiotlb range to sysfs\n");
4299+
}
4300+
42054301
static void __exit exit_hv_pci_drv(void)
42064302
{
4303+
hv_pci_swiotlb_unpublish();
4304+
42074305
vmbus_driver_unregister(&hv_pci_drv);
42084306

4307+
/* No swiotlb_destroy_pool() exists, so the backing pages are leaked. */
4308+
42094309
hvpci_block_ops.read_block = NULL;
42104310
hvpci_block_ops.write_block = NULL;
42114311
hvpci_block_ops.reg_blk_invalidate = NULL;
@@ -4233,8 +4333,83 @@ static int __init init_hv_pci_drv(void)
42334333
hvpci_block_ops.write_block = hv_write_config_block;
42344334
hvpci_block_ops.reg_blk_invalidate = hv_register_block_invalidate;
42354335

4236-
return vmbus_driver_register(&hv_pci_drv);
4336+
ret = vmbus_driver_register(&hv_pci_drv);
4337+
if (ret)
4338+
return ret;
4339+
4340+
if (hv_pci_swiotlb_pool)
4341+
hv_pci_swiotlb_publish();
4342+
4343+
return 0;
4344+
}
4345+
4346+
#ifndef MODULE
4347+
/*
4348+
* The dedicated swiotlb pool feature is built-in only: the cmdline parser
4349+
* uses early_param (unavailable in modules) and the allocation runs as a
4350+
* core_initcall so the buddy allocator hands us a 64 MiB DMA32 contiguous
4351+
* range with minimal fragmentation risk. In module builds
4352+
* hv_pci_swiotlb_size stays 0 and the rest of the file's pool plumbing
4353+
* (probe, publish, exit) is naturally inert.
4354+
*/
4355+
#ifdef CONFIG_CONTIG_ALLOC
4356+
/*
4357+
* Reserve the hv_pci swiotlb pool from the buddy allocator. __GFP_DMA32
4358+
* keeps the range below 4 GiB; kernel ownership keeps Hyper-V page
4359+
* reporting from yanking the backing. Gated on CONFIG_CONTIG_ALLOC.
4360+
*/
4361+
static int __init hv_pci_swiotlb_alloc_pool(void)
4362+
{
4363+
phys_addr_t end;
4364+
unsigned long nr_pages;
4365+
struct page *pages;
4366+
4367+
if (!hv_pci_swiotlb_size)
4368+
return 0;
4369+
4370+
nr_pages = hv_pci_swiotlb_size >> PAGE_SHIFT;
4371+
4372+
/* UMA on WSL; first_online_node biases nothing in practice. */
4373+
pages = alloc_contig_pages(nr_pages,
4374+
GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO,
4375+
first_online_node, &node_online_map);
4376+
if (!pages) {
4377+
pr_warn("hv_pci: failed to allocate %zu-byte swiotlb pool below 4G; feature disabled\n",
4378+
hv_pci_swiotlb_size);
4379+
hv_pci_swiotlb_size = 0;
4380+
return 0;
4381+
}
4382+
4383+
hv_pci_swiotlb_base = page_to_phys(pages);
4384+
end = hv_pci_swiotlb_base + hv_pci_swiotlb_size;
4385+
4386+
pr_info("hv_pci: reserved swiotlb pool [%pa..%pa)\n",
4387+
&hv_pci_swiotlb_base, &end);
4388+
4389+
hv_pci_swiotlb_pool = swiotlb_create_pool(hv_pci_swiotlb_base,
4390+
hv_pci_swiotlb_size,
4391+
"hv-pci-swiotlb");
4392+
if (IS_ERR(hv_pci_swiotlb_pool)) {
4393+
pr_err("hv_pci: failed to create swiotlb pool: %ld\n",
4394+
PTR_ERR(hv_pci_swiotlb_pool));
4395+
hv_pci_swiotlb_pool = NULL;
4396+
free_contig_range(page_to_pfn(pages), nr_pages);
4397+
hv_pci_swiotlb_base = 0;
4398+
hv_pci_swiotlb_size = 0;
4399+
}
4400+
4401+
return 0;
42374402
}
4403+
#else
4404+
static int __init hv_pci_swiotlb_alloc_pool(void)
4405+
{
4406+
if (hv_pci_swiotlb_size)
4407+
pr_warn("hv_pci: CONFIG_CONTIG_ALLOC disabled; hv_pci_swiotlb= ignored\n");
4408+
return 0;
4409+
}
4410+
#endif
4411+
core_initcall(hv_pci_swiotlb_alloc_pool);
4412+
#endif /* !MODULE */
42384413

42394414
module_init(init_hv_pci_drv);
42404415
module_exit(exit_hv_pci_drv);

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
@@ -1898,3 +1898,67 @@ static int __init rmem_swiotlb_setup(struct reserved_mem *rmem)
18981898

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

0 commit comments

Comments
 (0)