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(-)
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);
--
2.44.0.278.ge034bb2e1d-goog
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
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
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
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
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(). -- With Best Regards, Andy Shevchenko
© 2016 - 2026 Red Hat, Inc.