USB: use genalloc for USB HCs with local memory
[platform/kernel/linux-starfive.git] / drivers / usb / core / hcd.c
index 94d2255..29b96e5 100644 (file)
@@ -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>
@@ -3039,6 +3041,40 @@ usb_hcd_platform_shutdown(struct platform_device *dev)
 }
 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)