diff mbox series

[v4,2/2] usb: host: xhci-plat: add support for multi memory regions

Message ID 20240308095320.1961469-3-howardyen@google.com (mailing list archive)
State Superseded
Headers show
Series Add support for multiple coherent memory regions | expand

Commit Message

Howard Yen March 8, 2024, 9:53 a.m. UTC
The reason why it needs multiple regions is that in my system there is
an always-on subsystem which includes a small size memory, and several
functions need to run and occupy the memory from the small memory if
they need to run on the always-on subsystem. These functions must
allocate the memory from the small memory region, so that they can get
benefit from the always-on subsystem. So the small memory is split for
multiple functions which are satisfied with their generic use cases.
But in specific use cases, like USB3 devices which support the stream
trasnsfer or multiple devices connect to the host, they required more
memory than their pre-allocated memory region, so I tried to propose
this patch to give it the ability to get the memory from the other
larger memory to solve the issue.

Signed-off-by: Howard Yen <howardyen@google.com>
---
 drivers/usb/host/xhci-plat.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

Comments

Andy Shevchenko March 8, 2024, 1:43 p.m. UTC | #1
On Fri, Mar 08, 2024 at 09:53:20AM +0000, Howard Yen wrote:
> The reason why it needs multiple regions is that in my system there is
> an always-on subsystem which includes a small size memory, and several
> functions need to run and occupy the memory from the small memory if
> they need to run on the always-on subsystem. These functions must
> allocate the memory from the small memory region, so that they can get
> benefit from the always-on subsystem. So the small memory is split for
> multiple functions which are satisfied with their generic use cases.
> But in specific use cases, like USB3 devices which support the stream
> trasnsfer or multiple devices connect to the host, they required more
> memory than their pre-allocated memory region, so I tried to propose
> this patch to give it the ability to get the memory from the other
> larger memory to solve the issue.

...

> +	count = of_property_count_elems_of_size(sysdev->of_node, "memory-region",
> +						sizeof(u32));

Open coded of_property_count_u32_elems().
kernel test robot March 10, 2024, 6:16 a.m. UTC | #2
Hi Howard,

kernel test robot noticed the following build errors:

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on usb/usb-next usb/usb-linus char-misc/char-misc-testing char-misc/char-misc-next char-misc/char-misc-linus driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus linus/master v6.8-rc7 next-20240308]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Howard-Yen/dma-coherent-add-support-for-multi-coherent-rmems-per-dev/20240308-175649
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link:    https://lore.kernel.org/r/20240308095320.1961469-3-howardyen%40google.com
patch subject: [PATCH v4 2/2] usb: host: xhci-plat: add support for multi memory regions
config: riscv-defconfig (https://download.01.org/0day-ci/archive/20240310/202403101417.3D62qONB-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 503c55e17037436dcd45ac69dea8967e67e3f5e8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240310/202403101417.3D62qONB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202403101417.3D62qONB-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from drivers/usb/host/xhci-plat.c:12:
   In file included from include/linux/dma-mapping.h:11:
   In file included from include/linux/scatterlist.h:8:
   In file included from include/linux/mm.h:2188:
   include/linux/vmstat.h:522:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     522 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
>> drivers/usb/host/xhci-plat.c:201:9: error: call to undeclared function 'of_reserved_mem_device_init_by_idx'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     201 |                 ret = of_reserved_mem_device_init_by_idx(sysdev, sysdev->of_node, i);
         |                       ^
>> drivers/usb/host/xhci-plat.c:205:5: error: call to undeclared function 'of_reserved_mem_device_release'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     205 |                                 of_reserved_mem_device_release(sysdev);
         |                                 ^
   drivers/usb/host/xhci-plat.c:169:42: warning: shift count >= width of type [-Wshift-count-overflow]
     169 |         ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
         |                                                 ^~~~~~~~~~~~~~~~
   include/linux/dma-mapping.h:77:54: note: expanded from macro 'DMA_BIT_MASK'
      77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                                                      ^ ~~~
   drivers/usb/host/xhci-plat.c:409:46: warning: shift count >= width of type [-Wshift-count-overflow]
     409 |                 ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
         |                                                            ^~~~~~~~~~~~~~~~
   include/linux/dma-mapping.h:77:54: note: expanded from macro 'DMA_BIT_MASK'
      77 | #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
         |                                                      ^ ~~~
   drivers/usb/host/xhci-plat.c:449:2: error: call to undeclared function 'of_reserved_mem_device_release'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     449 |         of_reserved_mem_device_release(hcd->self.sysdev);
         |         ^
   3 warnings and 3 errors generated.


vim +/of_reserved_mem_device_init_by_idx +201 drivers/usb/host/xhci-plat.c

  > 12	#include <linux/dma-mapping.h>
    13	#include <linux/module.h>
    14	#include <linux/pci.h>
    15	#include <linux/of.h>
    16	#include <linux/of_device.h>
    17	#include <linux/platform_device.h>
    18	#include <linux/usb/phy.h>
    19	#include <linux/slab.h>
    20	#include <linux/acpi.h>
    21	#include <linux/usb/of.h>
    22	#include <linux/reset.h>
    23	
    24	#include "xhci.h"
    25	#include "xhci-plat.h"
    26	#include "xhci-mvebu.h"
    27	
    28	static struct hc_driver __read_mostly xhci_plat_hc_driver;
    29	
    30	static int xhci_plat_setup(struct usb_hcd *hcd);
    31	static int xhci_plat_start(struct usb_hcd *hcd);
    32	
    33	static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
    34		.extra_priv_size = sizeof(struct xhci_plat_priv),
    35		.reset = xhci_plat_setup,
    36		.start = xhci_plat_start,
    37	};
    38	
    39	static void xhci_priv_plat_start(struct usb_hcd *hcd)
    40	{
    41		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
    42	
    43		if (priv->plat_start)
    44			priv->plat_start(hcd);
    45	}
    46	
    47	static int xhci_priv_init_quirk(struct usb_hcd *hcd)
    48	{
    49		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
    50	
    51		if (!priv->init_quirk)
    52			return 0;
    53	
    54		return priv->init_quirk(hcd);
    55	}
    56	
    57	static int xhci_priv_suspend_quirk(struct usb_hcd *hcd)
    58	{
    59		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
    60	
    61		if (!priv->suspend_quirk)
    62			return 0;
    63	
    64		return priv->suspend_quirk(hcd);
    65	}
    66	
    67	static int xhci_priv_resume_quirk(struct usb_hcd *hcd)
    68	{
    69		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
    70	
    71		if (!priv->resume_quirk)
    72			return 0;
    73	
    74		return priv->resume_quirk(hcd);
    75	}
    76	
    77	static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
    78	{
    79		struct xhci_plat_priv *priv = xhci_to_priv(xhci);
    80	
    81		xhci->quirks |= priv->quirks;
    82	}
    83	
    84	/* called during probe() after chip reset completes */
    85	static int xhci_plat_setup(struct usb_hcd *hcd)
    86	{
    87		int ret;
    88	
    89	
    90		ret = xhci_priv_init_quirk(hcd);
    91		if (ret)
    92			return ret;
    93	
    94		return xhci_gen_setup(hcd, xhci_plat_quirks);
    95	}
    96	
    97	static int xhci_plat_start(struct usb_hcd *hcd)
    98	{
    99		xhci_priv_plat_start(hcd);
   100		return xhci_run(hcd);
   101	}
   102	
   103	#ifdef CONFIG_OF
   104	static const struct xhci_plat_priv xhci_plat_marvell_armada = {
   105		.init_quirk = xhci_mvebu_mbus_init_quirk,
   106	};
   107	
   108	static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
   109		.init_quirk = xhci_mvebu_a3700_init_quirk,
   110	};
   111	
   112	static const struct xhci_plat_priv xhci_plat_brcm = {
   113		.quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS,
   114	};
   115	
   116	static const struct of_device_id usb_xhci_of_match[] = {
   117		{
   118			.compatible = "generic-xhci",
   119		}, {
   120			.compatible = "xhci-platform",
   121		}, {
   122			.compatible = "marvell,armada-375-xhci",
   123			.data = &xhci_plat_marvell_armada,
   124		}, {
   125			.compatible = "marvell,armada-380-xhci",
   126			.data = &xhci_plat_marvell_armada,
   127		}, {
   128			.compatible = "marvell,armada3700-xhci",
   129			.data = &xhci_plat_marvell_armada3700,
   130		}, {
   131			.compatible = "brcm,xhci-brcm-v2",
   132			.data = &xhci_plat_brcm,
   133		}, {
   134			.compatible = "brcm,bcm2711-xhci",
   135			.data = &xhci_plat_brcm,
   136		}, {
   137			.compatible = "brcm,bcm7445-xhci",
   138			.data = &xhci_plat_brcm,
   139		},
   140		{},
   141	};
   142	MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
   143	#endif
   144	
   145	int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const struct xhci_plat_priv *priv_match)
   146	{
   147		const struct hc_driver	*driver;
   148		struct device		*tmpdev;
   149		struct xhci_hcd		*xhci;
   150		struct resource         *res;
   151		struct usb_hcd		*hcd, *usb3_hcd;
   152		int			i, count, ret;
   153		int			irq;
   154		struct xhci_plat_priv	*priv = NULL;
   155		bool			of_match;
   156	
   157		if (usb_disabled())
   158			return -ENODEV;
   159	
   160		driver = &xhci_plat_hc_driver;
   161	
   162		irq = platform_get_irq(pdev, 0);
   163		if (irq < 0)
   164			return irq;
   165	
   166		if (!sysdev)
   167			sysdev = &pdev->dev;
   168	
   169		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
   170		if (ret)
   171			return ret;
   172	
   173		pm_runtime_set_active(&pdev->dev);
   174		pm_runtime_enable(&pdev->dev);
   175		pm_runtime_get_noresume(&pdev->dev);
   176	
   177		hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
   178				       dev_name(&pdev->dev), NULL);
   179		if (!hcd) {
   180			ret = -ENOMEM;
   181			goto disable_runtime;
   182		}
   183	
   184		hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
   185		if (IS_ERR(hcd->regs)) {
   186			ret = PTR_ERR(hcd->regs);
   187			goto put_hcd;
   188		}
   189	
   190		hcd->rsrc_start = res->start;
   191		hcd->rsrc_len = resource_size(res);
   192	
   193		xhci = hcd_to_xhci(hcd);
   194	
   195		xhci->allow_single_roothub = 1;
   196	
   197		count = of_property_count_elems_of_size(sysdev->of_node, "memory-region",
   198							sizeof(u32));
   199	
   200		for (i = 0; i < count; i++) {
 > 201			ret = of_reserved_mem_device_init_by_idx(sysdev, sysdev->of_node, i);
   202			if (ret) {
   203				dev_err(sysdev, "Could not get reserved memory\n");
   204				if (i > 0)
 > 205					of_reserved_mem_device_release(sysdev);
   206	
   207				return ret;
   208			}
   209		}
   210	
   211		/*
   212		 * Not all platforms have clks so it is not an error if the
   213		 * clock do not exist.
   214		 */
   215		xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg");
   216		if (IS_ERR(xhci->reg_clk)) {
   217			ret = PTR_ERR(xhci->reg_clk);
   218			goto put_hcd;
   219		}
   220	
   221		xhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
   222		if (IS_ERR(xhci->clk)) {
   223			ret = PTR_ERR(xhci->clk);
   224			goto put_hcd;
   225		}
   226	
   227		xhci->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
   228		if (IS_ERR(xhci->reset)) {
   229			ret = PTR_ERR(xhci->reset);
   230			goto put_hcd;
   231		}
   232	
   233		ret = reset_control_deassert(xhci->reset);
   234		if (ret)
   235			goto put_hcd;
   236	
   237		ret = clk_prepare_enable(xhci->reg_clk);
   238		if (ret)
   239			goto err_reset;
   240	
   241		ret = clk_prepare_enable(xhci->clk);
   242		if (ret)
   243			goto disable_reg_clk;
   244	
   245		if (priv_match) {
   246			priv = hcd_to_xhci_priv(hcd);
   247			/* Just copy data for now */
   248			*priv = *priv_match;
   249		}
   250	
   251		device_set_wakeup_capable(&pdev->dev, true);
   252	
   253		xhci->main_hcd = hcd;
   254	
   255		/* imod_interval is the interrupt moderation value in nanoseconds. */
   256		xhci->imod_interval = 40000;
   257	
   258		/* Iterate over all parent nodes for finding quirks */
   259		for (tmpdev = &pdev->dev; tmpdev; tmpdev = tmpdev->parent) {
   260	
   261			if (device_property_read_bool(tmpdev, "usb2-lpm-disable"))
   262				xhci->quirks |= XHCI_HW_LPM_DISABLE;
   263	
   264			if (device_property_read_bool(tmpdev, "usb3-lpm-capable"))
   265				xhci->quirks |= XHCI_LPM_SUPPORT;
   266	
   267			if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
   268				xhci->quirks |= XHCI_BROKEN_PORT_PED;
   269	
   270			if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
   271				xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
   272	
   273			device_property_read_u32(tmpdev, "imod-interval-ns",
   274						 &xhci->imod_interval);
   275		}
   276	
   277		/*
   278		 * Drivers such as dwc3 manages PHYs themself (and rely on driver name
   279		 * matching for the xhci platform device).
   280		 */
   281		of_match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
   282		if (of_match) {
   283			hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
   284			if (IS_ERR(hcd->usb_phy)) {
   285				ret = PTR_ERR(hcd->usb_phy);
   286				if (ret == -EPROBE_DEFER)
   287					goto disable_clk;
   288				hcd->usb_phy = NULL;
   289			} else {
   290				ret = usb_phy_init(hcd->usb_phy);
   291				if (ret)
   292					goto disable_clk;
   293			}
   294		}
   295	
   296		hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
   297	
   298		if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
   299			hcd->skip_phy_initialization = 1;
   300	
   301		if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
   302			xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
   303	
   304		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
   305		if (ret)
   306			goto disable_usb_phy;
   307	
   308		if (!xhci_has_one_roothub(xhci)) {
   309			xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
   310							    dev_name(&pdev->dev), hcd);
   311			if (!xhci->shared_hcd) {
   312				ret = -ENOMEM;
   313				goto dealloc_usb2_hcd;
   314			}
   315	
   316			if (of_match) {
   317				xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev,
   318											"usb-phy", 1);
   319				if (IS_ERR(xhci->shared_hcd->usb_phy)) {
   320					xhci->shared_hcd->usb_phy = NULL;
   321				} else {
   322					ret = usb_phy_init(xhci->shared_hcd->usb_phy);
   323					if (ret)
   324						dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n",
   325							__func__, ret);
   326				}
   327			}
   328	
   329			xhci->shared_hcd->tpl_support = hcd->tpl_support;
   330		}
   331	
   332		usb3_hcd = xhci_get_usb3_hcd(xhci);
   333		if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4)
   334			usb3_hcd->can_do_streams = 1;
   335	
   336		if (xhci->shared_hcd) {
   337			ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
   338			if (ret)
   339				goto put_usb3_hcd;
   340		}
   341	
   342		device_enable_async_suspend(&pdev->dev);
   343		pm_runtime_put_noidle(&pdev->dev);
   344	
   345		/*
   346		 * Prevent runtime pm from being on as default, users should enable
   347		 * runtime pm using power/control in sysfs.
   348		 */
   349		pm_runtime_forbid(&pdev->dev);
   350	
   351		return 0;
   352	
   353	
   354	put_usb3_hcd:
   355		usb_put_hcd(xhci->shared_hcd);
   356	
   357	dealloc_usb2_hcd:
   358		usb_remove_hcd(hcd);
   359	
   360	disable_usb_phy:
   361		usb_phy_shutdown(hcd->usb_phy);
   362	
   363	disable_clk:
   364		clk_disable_unprepare(xhci->clk);
   365	
   366	disable_reg_clk:
   367		clk_disable_unprepare(xhci->reg_clk);
   368	
   369	err_reset:
   370		reset_control_assert(xhci->reset);
   371	
   372	put_hcd:
   373		usb_put_hcd(hcd);
   374	
   375	disable_runtime:
   376		pm_runtime_put_noidle(&pdev->dev);
   377		pm_runtime_disable(&pdev->dev);
   378	
   379		return ret;
   380	}
   381	EXPORT_SYMBOL_GPL(xhci_plat_probe);
   382
kernel test robot March 10, 2024, 6:27 a.m. UTC | #3
Hi Howard,

kernel test robot noticed the following build errors:

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on usb/usb-next usb/usb-linus char-misc/char-misc-testing char-misc/char-misc-next char-misc/char-misc-linus driver-core/driver-core-testing driver-core/driver-core-next driver-core/driver-core-linus linus/master v6.8-rc7 next-20240308]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Howard-Yen/dma-coherent-add-support-for-multi-coherent-rmems-per-dev/20240308-175649
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link:    https://lore.kernel.org/r/20240308095320.1961469-3-howardyen%40google.com
patch subject: [PATCH v4 2/2] usb: host: xhci-plat: add support for multi memory regions
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240310/202403101400.PHmsnLOh-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240310/202403101400.PHmsnLOh-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202403101400.PHmsnLOh-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/usb/host/xhci-plat.c: In function 'xhci_plat_probe':
>> drivers/usb/host/xhci-plat.c:201:23: error: implicit declaration of function 'of_reserved_mem_device_init_by_idx' [-Werror=implicit-function-declaration]
     201 |                 ret = of_reserved_mem_device_init_by_idx(sysdev, sysdev->of_node, i);
         |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/usb/host/xhci-plat.c:205:33: error: implicit declaration of function 'of_reserved_mem_device_release' [-Werror=implicit-function-declaration]
     205 |                                 of_reserved_mem_device_release(sysdev);
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/of_reserved_mem_device_init_by_idx +201 drivers/usb/host/xhci-plat.c

   144	
   145	int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const struct xhci_plat_priv *priv_match)
   146	{
   147		const struct hc_driver	*driver;
   148		struct device		*tmpdev;
   149		struct xhci_hcd		*xhci;
   150		struct resource         *res;
   151		struct usb_hcd		*hcd, *usb3_hcd;
   152		int			i, count, ret;
   153		int			irq;
   154		struct xhci_plat_priv	*priv = NULL;
   155		bool			of_match;
   156	
   157		if (usb_disabled())
   158			return -ENODEV;
   159	
   160		driver = &xhci_plat_hc_driver;
   161	
   162		irq = platform_get_irq(pdev, 0);
   163		if (irq < 0)
   164			return irq;
   165	
   166		if (!sysdev)
   167			sysdev = &pdev->dev;
   168	
   169		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
   170		if (ret)
   171			return ret;
   172	
   173		pm_runtime_set_active(&pdev->dev);
   174		pm_runtime_enable(&pdev->dev);
   175		pm_runtime_get_noresume(&pdev->dev);
   176	
   177		hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
   178				       dev_name(&pdev->dev), NULL);
   179		if (!hcd) {
   180			ret = -ENOMEM;
   181			goto disable_runtime;
   182		}
   183	
   184		hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
   185		if (IS_ERR(hcd->regs)) {
   186			ret = PTR_ERR(hcd->regs);
   187			goto put_hcd;
   188		}
   189	
   190		hcd->rsrc_start = res->start;
   191		hcd->rsrc_len = resource_size(res);
   192	
   193		xhci = hcd_to_xhci(hcd);
   194	
   195		xhci->allow_single_roothub = 1;
   196	
   197		count = of_property_count_elems_of_size(sysdev->of_node, "memory-region",
   198							sizeof(u32));
   199	
   200		for (i = 0; i < count; i++) {
 > 201			ret = of_reserved_mem_device_init_by_idx(sysdev, sysdev->of_node, i);
   202			if (ret) {
   203				dev_err(sysdev, "Could not get reserved memory\n");
   204				if (i > 0)
 > 205					of_reserved_mem_device_release(sysdev);
   206	
   207				return ret;
   208			}
   209		}
   210	
   211		/*
   212		 * Not all platforms have clks so it is not an error if the
   213		 * clock do not exist.
   214		 */
   215		xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg");
   216		if (IS_ERR(xhci->reg_clk)) {
   217			ret = PTR_ERR(xhci->reg_clk);
   218			goto put_hcd;
   219		}
   220	
   221		xhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
   222		if (IS_ERR(xhci->clk)) {
   223			ret = PTR_ERR(xhci->clk);
   224			goto put_hcd;
   225		}
   226	
   227		xhci->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
   228		if (IS_ERR(xhci->reset)) {
   229			ret = PTR_ERR(xhci->reset);
   230			goto put_hcd;
   231		}
   232	
   233		ret = reset_control_deassert(xhci->reset);
   234		if (ret)
   235			goto put_hcd;
   236	
   237		ret = clk_prepare_enable(xhci->reg_clk);
   238		if (ret)
   239			goto err_reset;
   240	
   241		ret = clk_prepare_enable(xhci->clk);
   242		if (ret)
   243			goto disable_reg_clk;
   244	
   245		if (priv_match) {
   246			priv = hcd_to_xhci_priv(hcd);
   247			/* Just copy data for now */
   248			*priv = *priv_match;
   249		}
   250	
   251		device_set_wakeup_capable(&pdev->dev, true);
   252	
   253		xhci->main_hcd = hcd;
   254	
   255		/* imod_interval is the interrupt moderation value in nanoseconds. */
   256		xhci->imod_interval = 40000;
   257	
   258		/* Iterate over all parent nodes for finding quirks */
   259		for (tmpdev = &pdev->dev; tmpdev; tmpdev = tmpdev->parent) {
   260	
   261			if (device_property_read_bool(tmpdev, "usb2-lpm-disable"))
   262				xhci->quirks |= XHCI_HW_LPM_DISABLE;
   263	
   264			if (device_property_read_bool(tmpdev, "usb3-lpm-capable"))
   265				xhci->quirks |= XHCI_LPM_SUPPORT;
   266	
   267			if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
   268				xhci->quirks |= XHCI_BROKEN_PORT_PED;
   269	
   270			if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
   271				xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
   272	
   273			device_property_read_u32(tmpdev, "imod-interval-ns",
   274						 &xhci->imod_interval);
   275		}
   276	
   277		/*
   278		 * Drivers such as dwc3 manages PHYs themself (and rely on driver name
   279		 * matching for the xhci platform device).
   280		 */
   281		of_match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
   282		if (of_match) {
   283			hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
   284			if (IS_ERR(hcd->usb_phy)) {
   285				ret = PTR_ERR(hcd->usb_phy);
   286				if (ret == -EPROBE_DEFER)
   287					goto disable_clk;
   288				hcd->usb_phy = NULL;
   289			} else {
   290				ret = usb_phy_init(hcd->usb_phy);
   291				if (ret)
   292					goto disable_clk;
   293			}
   294		}
   295	
   296		hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
   297	
   298		if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
   299			hcd->skip_phy_initialization = 1;
   300	
   301		if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
   302			xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
   303	
   304		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
   305		if (ret)
   306			goto disable_usb_phy;
   307	
   308		if (!xhci_has_one_roothub(xhci)) {
   309			xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
   310							    dev_name(&pdev->dev), hcd);
   311			if (!xhci->shared_hcd) {
   312				ret = -ENOMEM;
   313				goto dealloc_usb2_hcd;
   314			}
   315	
   316			if (of_match) {
   317				xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev,
   318											"usb-phy", 1);
   319				if (IS_ERR(xhci->shared_hcd->usb_phy)) {
   320					xhci->shared_hcd->usb_phy = NULL;
   321				} else {
   322					ret = usb_phy_init(xhci->shared_hcd->usb_phy);
   323					if (ret)
   324						dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n",
   325							__func__, ret);
   326				}
   327			}
   328	
   329			xhci->shared_hcd->tpl_support = hcd->tpl_support;
   330		}
   331	
   332		usb3_hcd = xhci_get_usb3_hcd(xhci);
   333		if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4)
   334			usb3_hcd->can_do_streams = 1;
   335	
   336		if (xhci->shared_hcd) {
   337			ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
   338			if (ret)
   339				goto put_usb3_hcd;
   340		}
   341	
   342		device_enable_async_suspend(&pdev->dev);
   343		pm_runtime_put_noidle(&pdev->dev);
   344	
   345		/*
   346		 * Prevent runtime pm from being on as default, users should enable
   347		 * runtime pm using power/control in sysfs.
   348		 */
   349		pm_runtime_forbid(&pdev->dev);
   350	
   351		return 0;
   352	
   353	
   354	put_usb3_hcd:
   355		usb_put_hcd(xhci->shared_hcd);
   356	
   357	dealloc_usb2_hcd:
   358		usb_remove_hcd(hcd);
   359	
   360	disable_usb_phy:
   361		usb_phy_shutdown(hcd->usb_phy);
   362	
   363	disable_clk:
   364		clk_disable_unprepare(xhci->clk);
   365	
   366	disable_reg_clk:
   367		clk_disable_unprepare(xhci->reg_clk);
   368	
   369	err_reset:
   370		reset_control_assert(xhci->reset);
   371	
   372	put_hcd:
   373		usb_put_hcd(hcd);
   374	
   375	disable_runtime:
   376		pm_runtime_put_noidle(&pdev->dev);
   377		pm_runtime_disable(&pdev->dev);
   378	
   379		return ret;
   380	}
   381	EXPORT_SYMBOL_GPL(xhci_plat_probe);
   382
diff mbox series

Patch

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 3d071b875308..79e743aab62e 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -149,7 +149,7 @@  int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
 	struct xhci_hcd		*xhci;
 	struct resource         *res;
 	struct usb_hcd		*hcd, *usb3_hcd;
-	int			ret;
+	int			i, count, ret;
 	int			irq;
 	struct xhci_plat_priv	*priv = NULL;
 	bool			of_match;
@@ -194,6 +194,20 @@  int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
 
 	xhci->allow_single_roothub = 1;
 
+	count = of_property_count_elems_of_size(sysdev->of_node, "memory-region",
+						sizeof(u32));
+
+	for (i = 0; i < count; i++) {
+		ret = of_reserved_mem_device_init_by_idx(sysdev, sysdev->of_node, i);
+		if (ret) {
+			dev_err(sysdev, "Could not get reserved memory\n");
+			if (i > 0)
+				of_reserved_mem_device_release(sysdev);
+
+			return ret;
+		}
+	}
+
 	/*
 	 * Not all platforms have clks so it is not an error if the
 	 * clock do not exist.
@@ -431,6 +445,9 @@  void xhci_plat_remove(struct platform_device *dev)
 	clk_disable_unprepare(clk);
 	clk_disable_unprepare(reg_clk);
 	reset_control_assert(xhci->reset);
+
+	of_reserved_mem_device_release(hcd->self.sysdev);
+
 	usb_put_hcd(hcd);
 
 	pm_runtime_disable(&dev->dev);