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
@@ -4241,10 +4260,52 @@ static struct hv_driver hv_pci_drv = {
42414260 .resume = hv_pci_resume ,
42424261};
42434262
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+
42444301static void __exit exit_hv_pci_drv (void )
42454302{
4303+ hv_pci_swiotlb_unpublish ();
4304+
42464305 vmbus_driver_unregister (& hv_pci_drv );
42474306
4307+ /* No swiotlb_destroy_pool() exists, so the backing pages are leaked. */
4308+
42484309 hvpci_block_ops .read_block = NULL ;
42494310 hvpci_block_ops .write_block = NULL ;
42504311 hvpci_block_ops .reg_blk_invalidate = NULL ;
@@ -4260,17 +4321,6 @@ static int __init init_hv_pci_drv(void)
42604321 if (hv_root_partition () && !hv_nested )
42614322 return - ENODEV ;
42624323
4263- if (hv_pci_swiotlb_base && hv_pci_swiotlb_size ) {
4264- hv_pci_swiotlb_pool = swiotlb_create_pool (hv_pci_swiotlb_base ,
4265- hv_pci_swiotlb_size ,
4266- "hv-pci-swiotlb" );
4267- if (IS_ERR (hv_pci_swiotlb_pool )) {
4268- pr_err ("hv_pci: failed to create swiotlb pool: %ld\n" ,
4269- PTR_ERR (hv_pci_swiotlb_pool ));
4270- hv_pci_swiotlb_pool = NULL ;
4271- }
4272- }
4273-
42744324 ret = hv_pci_irqchip_init ();
42754325 if (ret )
42764326 return ret ;
@@ -4283,8 +4333,83 @@ static int __init init_hv_pci_drv(void)
42834333 hvpci_block_ops .write_block = hv_write_config_block ;
42844334 hvpci_block_ops .reg_blk_invalidate = hv_register_block_invalidate ;
42854335
4286- 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 ;
42874402}
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 */
42884413
42894414module_init (init_hv_pci_drv );
42904415module_exit (exit_hv_pci_drv );
0 commit comments