diff options
Diffstat (limited to 'debian/patches/bugfix/all/USB-use-genalloc-for-USB-HCs-with-local-memory.patch')
-rw-r--r-- | debian/patches/bugfix/all/USB-use-genalloc-for-USB-HCs-with-local-memory.patch | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/debian/patches/bugfix/all/USB-use-genalloc-for-USB-HCs-with-local-memory.patch b/debian/patches/bugfix/all/USB-use-genalloc-for-USB-HCs-with-local-memory.patch new file mode 100644 index 000000000..88caafd5a --- /dev/null +++ b/debian/patches/bugfix/all/USB-use-genalloc-for-USB-HCs-with-local-memory.patch @@ -0,0 +1,280 @@ +From: Laurentiu Tudor <laurentiu.tudor@nxp.com> +Date: Wed, 29 May 2019 13:28:40 +0300 +Subject: USB: use genalloc for USB HCs with local memory +Origin: https://git.kernel.org/linus/b0310c2f09bbe8aebefb97ed67949a3a7092aca6 + +For HCs that have local memory, replace the current DMA API usage with +a genalloc generic allocator to manage the mappings for these devices. +To help users, introduce a new HCD API, usb_hcd_setup_local_mem() that +will setup up the genalloc backing up the device local memory. It will +be used in subsequent patches. This is in preparation for dropping +the existing "coherent" dma mem declaration APIs. The current +implementation was relying on a short circuit in the DMA API that in +the end, was acting as an allocator for these type of devices. + +Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> +Tested-by: Fredrik Noring <noring@nocrew.org> +Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Christoph Hellwig <hch@lst.de> +--- + drivers/usb/Kconfig | 1 + + drivers/usb/core/buffer.c | 9 +++++++++ + drivers/usb/core/hcd.c | 36 ++++++++++++++++++++++++++++++++++++ + drivers/usb/host/ohci-hcd.c | 23 ++++++++++++++++++----- + drivers/usb/host/ohci-mem.c | 35 +++++++++++++++++++++++++++++++---- + drivers/usb/host/ohci.h | 2 ++ + include/linux/usb/hcd.h | 5 +++++ + 7 files changed, 102 insertions(+), 9 deletions(-) + +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -44,6 +44,7 @@ + config USB + tristate "Support for Host-side USB" + depends on USB_ARCH_HAS_HCD ++ select GENERIC_ALLOCATOR + select USB_COMMON + select NLS # for UTF-8 strings + ---help--- +--- a/drivers/usb/core/buffer.c ++++ b/drivers/usb/core/buffer.c +@@ -16,6 +16,7 @@ + #include <linux/io.h> + #include <linux/dma-mapping.h> + #include <linux/dmapool.h> ++#include <linux/genalloc.h> + #include <linux/usb.h> + #include <linux/usb/hcd.h> + +@@ -128,6 +129,9 @@ + if (size == 0) + return NULL; + ++ if (hcd->localmem_pool) ++ return gen_pool_dma_alloc(hcd->localmem_pool, size, dma); ++ + /* some USB hosts just use PIO */ + if (!IS_ENABLED(CONFIG_HAS_DMA) || + (!is_device_dma_capable(bus->sysdev) && +@@ -156,6 +160,11 @@ + if (!addr) + return; + ++ if (hcd->localmem_pool) { ++ gen_pool_free(hcd->localmem_pool, (unsigned long)addr, size); ++ return; ++ } ++ + if (!IS_ENABLED(CONFIG_HAS_DMA) || + (!is_device_dma_capable(bus->sysdev) && + !(hcd->driver->flags & HCD_LOCAL_MEM))) { +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -29,6 +29,8 @@ + #include <linux/workqueue.h> + #include <linux/pm_runtime.h> + #include <linux/types.h> ++#include <linux/genalloc.h> ++#include <linux/io.h> + + #include <linux/phy/phy.h> + #include <linux/usb.h> +@@ -3025,6 +3027,40 @@ + } + EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); + ++int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, ++ dma_addr_t dma, size_t size) ++{ ++ int err; ++ void *local_mem; ++ ++ hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, PAGE_SHIFT, ++ dev_to_node(hcd->self.sysdev), ++ dev_name(hcd->self.sysdev)); ++ if (IS_ERR(hcd->localmem_pool)) ++ return PTR_ERR(hcd->localmem_pool); ++ ++ local_mem = devm_memremap(hcd->self.sysdev, phys_addr, ++ size, MEMREMAP_WC); ++ if (!local_mem) ++ return -ENOMEM; ++ ++ /* ++ * Here we pass a dma_addr_t but the arg type is a phys_addr_t. ++ * It's not backed by system memory and thus there's no kernel mapping ++ * for it. ++ */ ++ err = gen_pool_add_virt(hcd->localmem_pool, (unsigned long)local_mem, ++ dma, size, dev_to_node(hcd->self.sysdev)); ++ if (err < 0) { ++ dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n", ++ err); ++ return err; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(usb_hcd_setup_local_mem); ++ + /*-------------------------------------------------------------------------*/ + + #if IS_ENABLED(CONFIG_USB_MON) +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -40,6 +40,7 @@ + #include <linux/dmapool.h> + #include <linux/workqueue.h> + #include <linux/debugfs.h> ++#include <linux/genalloc.h> + + #include <asm/io.h> + #include <asm/irq.h> +@@ -514,8 +515,15 @@ + timer_setup(&ohci->io_watchdog, io_watchdog_func, 0); + ohci->prev_frame_no = IO_WATCHDOG_OFF; + +- ohci->hcca = dma_alloc_coherent (hcd->self.controller, +- sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); ++ if (hcd->localmem_pool) ++ ohci->hcca = gen_pool_dma_alloc(hcd->localmem_pool, ++ sizeof(*ohci->hcca), ++ &ohci->hcca_dma); ++ else ++ ohci->hcca = dma_alloc_coherent(hcd->self.controller, ++ sizeof(*ohci->hcca), ++ &ohci->hcca_dma, ++ GFP_KERNEL); + if (!ohci->hcca) + return -ENOMEM; + +@@ -999,9 +1007,14 @@ + remove_debug_files (ohci); + ohci_mem_cleanup (ohci); + if (ohci->hcca) { +- dma_free_coherent (hcd->self.controller, +- sizeof *ohci->hcca, +- ohci->hcca, ohci->hcca_dma); ++ if (hcd->localmem_pool) ++ gen_pool_free(hcd->localmem_pool, ++ (unsigned long)ohci->hcca, ++ sizeof(*ohci->hcca)); ++ else ++ dma_free_coherent(hcd->self.controller, ++ sizeof(*ohci->hcca), ++ ohci->hcca, ohci->hcca_dma); + ohci->hcca = NULL; + ohci->hcca_dma = 0; + } +--- a/drivers/usb/host/ohci-mem.c ++++ b/drivers/usb/host/ohci-mem.c +@@ -36,6 +36,13 @@ + + static int ohci_mem_init (struct ohci_hcd *ohci) + { ++ /* ++ * HCs with local memory allocate from localmem_pool so there's ++ * no need to create the below dma pools. ++ */ ++ if (ohci_to_hcd(ohci)->localmem_pool) ++ return 0; ++ + ohci->td_cache = dma_pool_create ("ohci_td", + ohci_to_hcd(ohci)->self.controller, + sizeof (struct td), +@@ -88,8 +95,12 @@ + { + dma_addr_t dma; + struct td *td; ++ struct usb_hcd *hcd = ohci_to_hcd(hc); + +- td = dma_pool_zalloc (hc->td_cache, mem_flags, &dma); ++ if (hcd->localmem_pool) ++ td = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*td), &dma); ++ else ++ td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma); + if (td) { + /* in case hc fetches it, make it look dead */ + td->hwNextTD = cpu_to_hc32 (hc, dma); +@@ -103,6 +114,7 @@ + td_free (struct ohci_hcd *hc, struct td *td) + { + struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; ++ struct usb_hcd *hcd = ohci_to_hcd(hc); + + while (*prev && *prev != td) + prev = &(*prev)->td_hash; +@@ -110,7 +122,12 @@ + *prev = td->td_hash; + else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) + ohci_dbg (hc, "no hash for td %p\n", td); +- dma_pool_free (hc->td_cache, td, td->td_dma); ++ ++ if (hcd->localmem_pool) ++ gen_pool_free(hcd->localmem_pool, (unsigned long)td, ++ sizeof(*td)); ++ else ++ dma_pool_free(hc->td_cache, td, td->td_dma); + } + + /*-------------------------------------------------------------------------*/ +@@ -121,8 +138,12 @@ + { + dma_addr_t dma; + struct ed *ed; ++ struct usb_hcd *hcd = ohci_to_hcd(hc); + +- ed = dma_pool_zalloc (hc->ed_cache, mem_flags, &dma); ++ if (hcd->localmem_pool) ++ ed = gen_pool_dma_zalloc(hcd->localmem_pool, sizeof(*ed), &dma); ++ else ++ ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma); + if (ed) { + INIT_LIST_HEAD (&ed->td_list); + ed->dma = dma; +@@ -133,6 +154,12 @@ + static void + ed_free (struct ohci_hcd *hc, struct ed *ed) + { +- dma_pool_free (hc->ed_cache, ed, ed->dma); ++ struct usb_hcd *hcd = ohci_to_hcd(hc); ++ ++ if (hcd->localmem_pool) ++ gen_pool_free(hcd->localmem_pool, (unsigned long)ed, ++ sizeof(*ed)); ++ else ++ dma_pool_free(hc->ed_cache, ed, ed->dma); + } + +--- a/drivers/usb/host/ohci.h ++++ b/drivers/usb/host/ohci.h +@@ -385,6 +385,8 @@ + + /* + * memory management for queue data structures ++ * ++ * @td_cache and @ed_cache are %NULL if &usb_hcd.localmem_pool is used. + */ + struct dma_pool *td_cache; + struct dma_pool *ed_cache; +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -211,6 +211,9 @@ + #define HC_IS_RUNNING(state) ((state) & __ACTIVE) + #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND) + ++ /* memory pool for HCs having local memory, or %NULL */ ++ struct gen_pool *localmem_pool; ++ + /* more shared queuing code would be good; it should support + * smarter scheduling, handle transaction translators, etc; + * input size of periodic table to an interrupt scheduler. +@@ -461,6 +464,8 @@ + unsigned int irqnum, unsigned long irqflags); + extern void usb_remove_hcd(struct usb_hcd *hcd); + extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1); ++int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, ++ dma_addr_t dma, size_t size); + + struct platform_device; + extern void usb_hcd_platform_shutdown(struct platform_device *dev); |