Skip to content

Commit f2d3b9a

Browse files
Saravana KannanRussell King (Oracle)
authored andcommitted
ARM: 9220/1: amba: Remove deferred device addition
The uevents generated for an amba device need PID and CID information that's available only when the amba device is powered on, clocked and out of reset. So, if those resources aren't available, the information can't be read to generate the uevents. To workaround this requirement, if the resources weren't available, the device addition was deferred and retried periodically. However, this deferred addition retry isn't based on resources becoming available. Instead, it's retried every 5 seconds and causes arbitrary probe delays for amba devices and their consumers. Also, maintaining a separate deferred-probe like mechanism is maintenance headache. With this commit, instead of deferring the device addition, we simply defer the generation of uevents for the device and probing of the device (because drivers needs PID and CID to match) until the PID and CID information can be read. This allows us to delete all the amba specific deferring code and also avoid the arbitrary probing delays. Cc: Rob Herring <[email protected]> Cc: Ulf Hansson <[email protected]> Cc: Saravana Kannan <[email protected]> Cc: Linus Walleij <[email protected]> Cc: Sudeep Holla <[email protected]> Cc: Nicolas Saenz Julienne <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: Marek Szyprowski <[email protected]> Cc: Kefeng Wang <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: [email protected] Signed-off-by: Saravana Kannan <[email protected]> Tested-by: Marek Szyprowski <[email protected]> Tested-by: Kefeng Wang <[email protected]> Tested-by: Sudeep Holla <[email protected]> Signed-off-by: Russell King (Oracle) <[email protected]>
1 parent fe52063 commit f2d3b9a

File tree

1 file changed

+145
-168
lines changed

1 file changed

+145
-168
lines changed

drivers/amba/bus.c

Lines changed: 145 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,100 @@ static struct attribute *amba_dev_attrs[] = {
130130
};
131131
ATTRIBUTE_GROUPS(amba_dev);
132132

133+
static int amba_read_periphid(struct amba_device *dev)
134+
{
135+
struct reset_control *rstc;
136+
u32 size, pid, cid;
137+
void __iomem *tmp;
138+
int i, ret;
139+
140+
ret = dev_pm_domain_attach(&dev->dev, true);
141+
if (ret) {
142+
dev_dbg(&dev->dev, "can't get PM domain: %d\n", ret);
143+
goto err_out;
144+
}
145+
146+
ret = amba_get_enable_pclk(dev);
147+
if (ret) {
148+
dev_dbg(&dev->dev, "can't get pclk: %d\n", ret);
149+
goto err_pm;
150+
}
151+
152+
/*
153+
* Find reset control(s) of the amba bus and de-assert them.
154+
*/
155+
rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node);
156+
if (IS_ERR(rstc)) {
157+
ret = PTR_ERR(rstc);
158+
if (ret != -EPROBE_DEFER)
159+
dev_err(&dev->dev, "can't get reset: %d\n", ret);
160+
goto err_clk;
161+
}
162+
reset_control_deassert(rstc);
163+
reset_control_put(rstc);
164+
165+
size = resource_size(&dev->res);
166+
tmp = ioremap(dev->res.start, size);
167+
if (!tmp) {
168+
ret = -ENOMEM;
169+
goto err_clk;
170+
}
171+
172+
/*
173+
* Read pid and cid based on size of resource
174+
* they are located at end of region
175+
*/
176+
for (pid = 0, i = 0; i < 4; i++)
177+
pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
178+
for (cid = 0, i = 0; i < 4; i++)
179+
cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
180+
181+
if (cid == CORESIGHT_CID) {
182+
/* set the base to the start of the last 4k block */
183+
void __iomem *csbase = tmp + size - 4096;
184+
185+
dev->uci.devarch = readl(csbase + UCI_REG_DEVARCH_OFFSET);
186+
dev->uci.devtype = readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff;
187+
}
188+
189+
if (cid == AMBA_CID || cid == CORESIGHT_CID) {
190+
dev->periphid = pid;
191+
dev->cid = cid;
192+
}
193+
194+
if (!dev->periphid)
195+
ret = -ENODEV;
196+
197+
iounmap(tmp);
198+
199+
err_clk:
200+
amba_put_disable_pclk(dev);
201+
err_pm:
202+
dev_pm_domain_detach(&dev->dev, true);
203+
err_out:
204+
return ret;
205+
}
206+
133207
static int amba_match(struct device *dev, struct device_driver *drv)
134208
{
135209
struct amba_device *pcdev = to_amba_device(dev);
136210
struct amba_driver *pcdrv = to_amba_driver(drv);
137211

212+
if (!pcdev->periphid) {
213+
int ret = amba_read_periphid(pcdev);
214+
215+
/*
216+
* Returning any error other than -EPROBE_DEFER from bus match
217+
* can cause driver registration failure. So, if there's a
218+
* permanent failure in reading pid and cid, simply map it to
219+
* -EPROBE_DEFER.
220+
*/
221+
if (ret)
222+
return -EPROBE_DEFER;
223+
dev_set_uevent_suppress(dev, false);
224+
kobject_uevent(&dev->kobj, KOBJ_ADD);
225+
}
226+
138227
/* When driver_override is set, only bind to the matching driver */
139228
if (pcdev->driver_override)
140229
return !strcmp(pcdev->driver_override, drv->name);
@@ -368,6 +457,42 @@ static int __init amba_init(void)
368457

369458
postcore_initcall(amba_init);
370459

460+
static int amba_proxy_probe(struct amba_device *adev,
461+
const struct amba_id *id)
462+
{
463+
WARN(1, "Stub driver should never match any device.\n");
464+
return -ENODEV;
465+
}
466+
467+
static const struct amba_id amba_stub_drv_ids[] = {
468+
{ 0, 0 },
469+
};
470+
471+
static struct amba_driver amba_proxy_drv = {
472+
.drv = {
473+
.name = "amba-proxy",
474+
},
475+
.probe = amba_proxy_probe,
476+
.id_table = amba_stub_drv_ids,
477+
};
478+
479+
static int __init amba_stub_drv_init(void)
480+
{
481+
if (!IS_ENABLED(CONFIG_MODULES))
482+
return 0;
483+
484+
/*
485+
* The amba_match() function will get called only if there is at least
486+
* one amba driver registered. If all amba drivers are modules and are
487+
* only loaded based on uevents, then we'll hit a chicken-and-egg
488+
* situation where amba_match() is waiting on drivers and drivers are
489+
* waiting on amba_match(). So, register a stub driver to make sure
490+
* amba_match() is called even if no amba driver has been registered.
491+
*/
492+
return amba_driver_register(&amba_proxy_drv);
493+
}
494+
late_initcall_sync(amba_stub_drv_init);
495+
371496
/**
372497
* amba_driver_register - register an AMBA device driver
373498
* @drv: amba device driver structure
@@ -410,156 +535,6 @@ static void amba_device_release(struct device *dev)
410535
kfree(d);
411536
}
412537

413-
static int amba_read_periphid(struct amba_device *dev)
414-
{
415-
struct reset_control *rstc;
416-
u32 size, pid, cid;
417-
void __iomem *tmp;
418-
int i, ret;
419-
420-
ret = dev_pm_domain_attach(&dev->dev, true);
421-
if (ret)
422-
goto err_out;
423-
424-
ret = amba_get_enable_pclk(dev);
425-
if (ret)
426-
goto err_pm;
427-
428-
/*
429-
* Find reset control(s) of the amba bus and de-assert them.
430-
*/
431-
rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node);
432-
if (IS_ERR(rstc)) {
433-
ret = PTR_ERR(rstc);
434-
if (ret != -EPROBE_DEFER)
435-
dev_err(&dev->dev, "can't get reset: %d\n", ret);
436-
goto err_clk;
437-
}
438-
reset_control_deassert(rstc);
439-
reset_control_put(rstc);
440-
441-
size = resource_size(&dev->res);
442-
tmp = ioremap(dev->res.start, size);
443-
if (!tmp) {
444-
ret = -ENOMEM;
445-
goto err_clk;
446-
}
447-
448-
/*
449-
* Read pid and cid based on size of resource
450-
* they are located at end of region
451-
*/
452-
for (pid = 0, i = 0; i < 4; i++)
453-
pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8);
454-
for (cid = 0, i = 0; i < 4; i++)
455-
cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8);
456-
457-
if (cid == CORESIGHT_CID) {
458-
/* set the base to the start of the last 4k block */
459-
void __iomem *csbase = tmp + size - 4096;
460-
461-
dev->uci.devarch = readl(csbase + UCI_REG_DEVARCH_OFFSET);
462-
dev->uci.devtype = readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff;
463-
}
464-
465-
if (cid == AMBA_CID || cid == CORESIGHT_CID) {
466-
dev->periphid = pid;
467-
dev->cid = cid;
468-
}
469-
470-
if (!dev->periphid)
471-
ret = -ENODEV;
472-
473-
iounmap(tmp);
474-
475-
err_clk:
476-
amba_put_disable_pclk(dev);
477-
err_pm:
478-
dev_pm_domain_detach(&dev->dev, true);
479-
err_out:
480-
return ret;
481-
}
482-
483-
static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
484-
{
485-
int ret;
486-
487-
ret = request_resource(parent, &dev->res);
488-
if (ret)
489-
goto err_out;
490-
491-
/* Hard-coded primecell ID instead of plug-n-play */
492-
if (dev->periphid != 0)
493-
goto skip_probe;
494-
495-
ret = amba_read_periphid(dev);
496-
if (ret)
497-
goto err_release;
498-
499-
skip_probe:
500-
ret = device_add(&dev->dev);
501-
err_release:
502-
if (ret)
503-
release_resource(&dev->res);
504-
err_out:
505-
return ret;
506-
}
507-
508-
/*
509-
* Registration of AMBA device require reading its pid and cid registers.
510-
* To do this, the device must be turned on (if it is a part of power domain)
511-
* and have clocks enabled. However in some cases those resources might not be
512-
* yet available. Returning EPROBE_DEFER is not a solution in such case,
513-
* because callers don't handle this special error code. Instead such devices
514-
* are added to the special list and their registration is retried from
515-
* periodic worker, until all resources are available and registration succeeds.
516-
*/
517-
struct deferred_device {
518-
struct amba_device *dev;
519-
struct resource *parent;
520-
struct list_head node;
521-
};
522-
523-
static LIST_HEAD(deferred_devices);
524-
static DEFINE_MUTEX(deferred_devices_lock);
525-
526-
static void amba_deferred_retry_func(struct work_struct *dummy);
527-
static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func);
528-
529-
#define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000))
530-
531-
static int amba_deferred_retry(void)
532-
{
533-
struct deferred_device *ddev, *tmp;
534-
535-
mutex_lock(&deferred_devices_lock);
536-
537-
list_for_each_entry_safe(ddev, tmp, &deferred_devices, node) {
538-
int ret = amba_device_try_add(ddev->dev, ddev->parent);
539-
540-
if (ret == -EPROBE_DEFER)
541-
continue;
542-
543-
list_del_init(&ddev->node);
544-
amba_device_put(ddev->dev);
545-
kfree(ddev);
546-
}
547-
548-
mutex_unlock(&deferred_devices_lock);
549-
550-
return 0;
551-
}
552-
late_initcall(amba_deferred_retry);
553-
554-
static void amba_deferred_retry_func(struct work_struct *dummy)
555-
{
556-
amba_deferred_retry();
557-
558-
if (!list_empty(&deferred_devices))
559-
schedule_delayed_work(&deferred_retry_work,
560-
DEFERRED_DEVICE_TIMEOUT);
561-
}
562-
563538
/**
564539
* amba_device_add - add a previously allocated AMBA device structure
565540
* @dev: AMBA device allocated by amba_device_alloc
@@ -571,28 +546,30 @@ static void amba_deferred_retry_func(struct work_struct *dummy)
571546
*/
572547
int amba_device_add(struct amba_device *dev, struct resource *parent)
573548
{
574-
int ret = amba_device_try_add(dev, parent);
575-
576-
if (ret == -EPROBE_DEFER) {
577-
struct deferred_device *ddev;
578-
579-
ddev = kmalloc(sizeof(*ddev), GFP_KERNEL);
580-
if (!ddev)
581-
return -ENOMEM;
549+
int ret;
582550

583-
ddev->dev = dev;
584-
ddev->parent = parent;
585-
ret = 0;
551+
ret = request_resource(parent, &dev->res);
552+
if (ret)
553+
return ret;
586554

587-
mutex_lock(&deferred_devices_lock);
555+
/* If primecell ID isn't hard-coded, figure it out */
556+
if (!dev->periphid) {
557+
/*
558+
* AMBA device uevents require reading its pid and cid
559+
* registers. To do this, the device must be on, clocked and
560+
* out of reset. However in some cases those resources might
561+
* not yet be available. If that's the case, we suppress the
562+
* generation of uevents until we can read the pid and cid
563+
* registers. See also amba_match().
564+
*/
565+
if (amba_read_periphid(dev))
566+
dev_set_uevent_suppress(&dev->dev, true);
567+
}
588568

589-
if (list_empty(&deferred_devices))
590-
schedule_delayed_work(&deferred_retry_work,
591-
DEFERRED_DEVICE_TIMEOUT);
592-
list_add_tail(&ddev->node, &deferred_devices);
569+
ret = device_add(&dev->dev);
570+
if (ret)
571+
release_resource(&dev->res);
593572

594-
mutex_unlock(&deferred_devices_lock);
595-
}
596573
return ret;
597574
}
598575
EXPORT_SYMBOL_GPL(amba_device_add);

0 commit comments

Comments
 (0)