5353#include <linux/sizes.h>
5454#include <linux/of_irq.h>
5555#include <linux/swiotlb.h>
56- #include <linux/memblock.h>
5756#include <asm/mshyperv.h>
5857
5958/*
@@ -472,17 +471,37 @@ static int pci_ring_size = VMBUS_RING_SIZE(SZ_16K);
472471
473472static phys_addr_t hv_pci_swiotlb_base ;
474473static size_t hv_pci_swiotlb_size ;
474+ static bool hv_pci_swiotlb_published ;
475475
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+ */
476483static int __init early_hv_pci_swiotlb (char * p )
477484{
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 ;
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 ;
484502}
485503early_param ("hv_pci_swiotlb" , early_hv_pci_swiotlb );
504+ #endif /* !MODULE */
486505
487506static struct io_tlb_mem * hv_pci_swiotlb_pool ;
488507
@@ -4233,10 +4252,52 @@ static struct hv_driver hv_pci_drv = {
42334252 .resume = hv_pci_resume ,
42344253};
42354254
4255+ /* Publish swiotlb_{base,size} so userspace can forward the GPA to the host. */
4256+ static ssize_t swiotlb_base_show (struct device_driver * drv , char * buf )
4257+ {
4258+ return sysfs_emit (buf , "0x%llx\n" ,
4259+ (unsigned long long )hv_pci_swiotlb_base );
4260+ }
4261+ static DRIVER_ATTR_RO (swiotlb_base );
4262+
4263+ static ssize_t swiotlb_size_show (struct device_driver * drv , char * buf )
4264+ {
4265+ return sysfs_emit (buf , "%zu\n" , hv_pci_swiotlb_size );
4266+ }
4267+ static DRIVER_ATTR_RO (swiotlb_size );
4268+
4269+ static void hv_pci_swiotlb_unpublish (void )
4270+ {
4271+ if (!hv_pci_swiotlb_published )
4272+ return ;
4273+ driver_remove_file (& hv_pci_drv .driver , & driver_attr_swiotlb_size );
4274+ driver_remove_file (& hv_pci_drv .driver , & driver_attr_swiotlb_base );
4275+ hv_pci_swiotlb_published = false;
4276+ }
4277+
4278+ static void hv_pci_swiotlb_publish (void )
4279+ {
4280+ if (driver_create_file (& hv_pci_drv .driver , & driver_attr_swiotlb_base ))
4281+ goto warn ;
4282+ if (driver_create_file (& hv_pci_drv .driver , & driver_attr_swiotlb_size )) {
4283+ driver_remove_file (& hv_pci_drv .driver , & driver_attr_swiotlb_base );
4284+ goto warn ;
4285+ }
4286+ hv_pci_swiotlb_published = true;
4287+ return ;
4288+
4289+ warn :
4290+ pr_warn ("hv_pci: failed to publish swiotlb range to sysfs\n" );
4291+ }
4292+
42364293static void __exit exit_hv_pci_drv (void )
42374294{
4295+ hv_pci_swiotlb_unpublish ();
4296+
42384297 vmbus_driver_unregister (& hv_pci_drv );
42394298
4299+ /* No swiotlb_destroy_pool() exists, so the backing pages are leaked. */
4300+
42404301 hvpci_block_ops .read_block = NULL ;
42414302 hvpci_block_ops .write_block = NULL ;
42424303 hvpci_block_ops .reg_blk_invalidate = NULL ;
@@ -4252,17 +4313,6 @@ static int __init init_hv_pci_drv(void)
42524313 if (hv_root_partition () && !hv_nested )
42534314 return - ENODEV ;
42544315
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-
42664316 ret = hv_pci_irqchip_init ();
42674317 if (ret )
42684318 return ret ;
@@ -4275,8 +4325,83 @@ static int __init init_hv_pci_drv(void)
42754325 hvpci_block_ops .write_block = hv_write_config_block ;
42764326 hvpci_block_ops .reg_blk_invalidate = hv_register_block_invalidate ;
42774327
4278- return vmbus_driver_register (& hv_pci_drv );
4328+ ret = vmbus_driver_register (& hv_pci_drv );
4329+ if (ret )
4330+ return ret ;
4331+
4332+ if (hv_pci_swiotlb_pool )
4333+ hv_pci_swiotlb_publish ();
4334+
4335+ return 0 ;
4336+ }
4337+
4338+ #ifndef MODULE
4339+ /*
4340+ * The dedicated swiotlb pool feature is built-in only: the cmdline parser
4341+ * uses early_param (unavailable in modules) and the allocation runs as a
4342+ * core_initcall so the buddy allocator hands us a 64 MiB DMA32 contiguous
4343+ * range with minimal fragmentation risk. In module builds
4344+ * hv_pci_swiotlb_size stays 0 and the rest of the file's pool plumbing
4345+ * (probe, publish, exit) is naturally inert.
4346+ */
4347+ #ifdef CONFIG_CONTIG_ALLOC
4348+ /*
4349+ * Reserve the hv_pci swiotlb pool from the buddy allocator. __GFP_DMA32
4350+ * keeps the range below 4 GiB; kernel ownership keeps Hyper-V page
4351+ * reporting from yanking the backing. Gated on CONFIG_CONTIG_ALLOC.
4352+ */
4353+ static int __init hv_pci_swiotlb_alloc_pool (void )
4354+ {
4355+ phys_addr_t end ;
4356+ unsigned long nr_pages ;
4357+ struct page * pages ;
4358+
4359+ if (!hv_pci_swiotlb_size )
4360+ return 0 ;
4361+
4362+ nr_pages = hv_pci_swiotlb_size >> PAGE_SHIFT ;
4363+
4364+ /* UMA on WSL; first_online_node biases nothing in practice. */
4365+ pages = alloc_contig_pages (nr_pages ,
4366+ GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO ,
4367+ first_online_node , & node_online_map );
4368+ if (!pages ) {
4369+ pr_warn ("hv_pci: failed to allocate %zu-byte swiotlb pool below 4G; feature disabled\n" ,
4370+ hv_pci_swiotlb_size );
4371+ hv_pci_swiotlb_size = 0 ;
4372+ return 0 ;
4373+ }
4374+
4375+ hv_pci_swiotlb_base = page_to_phys (pages );
4376+ end = hv_pci_swiotlb_base + hv_pci_swiotlb_size ;
4377+
4378+ pr_info ("hv_pci: reserved swiotlb pool [%pa..%pa)\n" ,
4379+ & hv_pci_swiotlb_base , & end );
4380+
4381+ hv_pci_swiotlb_pool = swiotlb_create_pool (hv_pci_swiotlb_base ,
4382+ hv_pci_swiotlb_size ,
4383+ "hv-pci-swiotlb" );
4384+ if (IS_ERR (hv_pci_swiotlb_pool )) {
4385+ pr_err ("hv_pci: failed to create swiotlb pool: %ld\n" ,
4386+ PTR_ERR (hv_pci_swiotlb_pool ));
4387+ hv_pci_swiotlb_pool = NULL ;
4388+ free_contig_range (page_to_pfn (pages ), nr_pages );
4389+ hv_pci_swiotlb_base = 0 ;
4390+ hv_pci_swiotlb_size = 0 ;
4391+ }
4392+
4393+ return 0 ;
42794394}
4395+ #else
4396+ static int __init hv_pci_swiotlb_alloc_pool (void )
4397+ {
4398+ if (hv_pci_swiotlb_size )
4399+ pr_warn ("hv_pci: CONFIG_CONTIG_ALLOC disabled; hv_pci_swiotlb= ignored\n" );
4400+ return 0 ;
4401+ }
4402+ #endif
4403+ core_initcall (hv_pci_swiotlb_alloc_pool );
4404+ #endif /* !MODULE */
42804405
42814406module_init (init_hv_pci_drv );
42824407module_exit (exit_hv_pci_drv );
0 commit comments