diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 11:06:20 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-27 11:06:20 -0800 |
commit | 9a3d7fd275be4559277667228902824165153c80 (patch) | |
tree | 09e74ef51c6388ac42b6123ad789ebc5b6ad8ed6 /drivers/base/platform.c | |
parent | 0dd09bc02c1bad55e92306ca83b38b3cf48b9f40 (diff) | |
parent | 0e4a459f56c32d3e52ae69a4b447db2f48a65f44 (diff) | |
download | blackbird-op-linux-9a3d7fd275be4559277667228902824165153c80.tar.gz blackbird-op-linux-9a3d7fd275be4559277667228902824165153c80.zip |
Merge tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH:
"Here is the "big" set of driver core patches for 5.5-rc1
There's a few minor cleanups and fixes in here, but the majority of
the patches in here fall into two buckets:
- debugfs api cleanups and fixes
- driver core device link support for boot dependancy issues
The debugfs api cleanups are working to slowly refactor the debugfs
apis so that it is even harder to use incorrectly. That work has been
happening for the past few kernel releases and will continue over
time, it's a long-term project/goal
The driver core device link support missed 5.4 by just a bit, so it's
been sitting and baking for many months now. It's from Saravana Kannan
to help resolve the problems that DT-based systems have at boot time
with dependancy graphs and kernel modules. Turns out that no one has
actually tried to build a generic arm64 kernel with loads of modules
and have it "just work" for a variety of platforms (like a distro
kernel). The big problem turned out to be a lack of dependency
information between different areas of DT entries, and the work here
resolves that problem and now allows devices to boot properly, and
quicker than a monolith kernel.
All of these patches have been in linux-next for a long time with no
reported issues"
* tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (68 commits)
tracing: Remove unnecessary DEBUG_FS dependency
of: property: Add device link support for interrupt-parent, dmas and -gpio(s)
debugfs: Fix !DEBUG_FS debugfs_create_automount
of: property: Add device link support for "iommu-map"
of: property: Fix the semantics of of_is_ancestor_of()
i2c: of: Populate fwnode in of_i2c_get_board_info()
drivers: base: Fix Kconfig indentation
firmware_loader: Fix labels with comma for builtin firmware
driver core: Allow device link operations inside sync_state()
driver core: platform: Declare ret variable only once
cpu-topology: declare parse_acpi_topology in <linux/arch_topology.h>
crypto: hisilicon: no need to check return value of debugfs_create functions
driver core: platform: use the correct callback type for bus_find_device
firmware_class: make firmware caching configurable
driver core: Clarify documentation for fwnode_operations.add_links()
mailbox: tegra: Fix superfluous IRQ error message
net: caif: Fix debugfs on 64-bit platforms
mac80211: Use debugfs_create_xul() helper
media: c8sectpfe: no need to check return value of debugfs_create functions
of: property: Add device link support for iommus, mboxes and io-channels
...
Diffstat (limited to 'drivers/base/platform.c')
-rw-r--r-- | drivers/base/platform.c | 393 |
1 files changed, 69 insertions, 324 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index b230beb6ccb4..7c532548b0a6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -60,6 +60,7 @@ struct resource *platform_get_resource(struct platform_device *dev, } EXPORT_SYMBOL_GPL(platform_get_resource); +#ifdef CONFIG_HAS_IOMEM /** * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform * device @@ -68,7 +69,6 @@ EXPORT_SYMBOL_GPL(platform_get_resource); * resource management * @index: resource index */ -#ifdef CONFIG_HAS_IOMEM void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index) { @@ -78,9 +78,63 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, return devm_ioremap_resource(&pdev->dev, res); } EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); + +/** + * devm_platform_ioremap_resource_wc - write-combined variant of + * devm_platform_ioremap_resource() + * + * @pdev: platform device to use both for memory resource lookup as well as + * resource management + * @index: resource index + */ +void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, + unsigned int index) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, index); + return devm_ioremap_resource_wc(&pdev->dev, res); +} + +/** + * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for + * a platform device, retrieve the + * resource by name + * + * @pdev: platform device to use both for memory resource lookup as well as + * resource management + * @name: name of the resource + */ +void __iomem * +devm_platform_ioremap_resource_byname(struct platform_device *pdev, + const char *name) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + return devm_ioremap_resource(&pdev->dev, res); +} +EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname); #endif /* CONFIG_HAS_IOMEM */ -static int __platform_get_irq(struct platform_device *dev, unsigned int num) +/** + * platform_get_irq_optional - get an optional IRQ for a device + * @dev: platform device + * @num: IRQ number index + * + * Gets an IRQ for a platform device. Device drivers should check the return + * value for errors so as to not pass a negative integer value to the + * request_irq() APIs. This is the same as platform_get_irq(), except that it + * does not print an error message if an IRQ can not be obtained. + * + * Example: + * int irq = platform_get_irq_optional(pdev, 0); + * if (irq < 0) + * return irq; + * + * Return: IRQ number on success, negative error number on failure. + */ +int platform_get_irq_optional(struct platform_device *dev, unsigned int num) { #ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ @@ -89,9 +143,9 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num) return dev->archdata.irqs[num]; #else struct resource *r; - if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { - int ret; + int ret; + if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { ret = of_irq_get(dev->dev.of_node, num); if (ret > 0 || ret == -EPROBE_DEFER) return ret; @@ -100,8 +154,6 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num) r = platform_get_resource(dev, IORESOURCE_IRQ, num); if (has_acpi_companion(&dev->dev)) { if (r && r->flags & IORESOURCE_DISABLED) { - int ret; - ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r); if (ret) return ret; @@ -134,8 +186,7 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num) * allows a common code path across either kind of resource. */ if (num == 0 && has_acpi_companion(&dev->dev)) { - int ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num); - + ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num); /* Our callers expect -ENXIO for missing IRQs. */ if (ret >= 0 || ret == -EPROBE_DEFER) return ret; @@ -144,6 +195,7 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num) return -ENXIO; #endif } +EXPORT_SYMBOL_GPL(platform_get_irq_optional); /** * platform_get_irq - get an IRQ for a device @@ -165,7 +217,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) { int ret; - ret = __platform_get_irq(dev, num); + ret = platform_get_irq_optional(dev, num); if (ret < 0 && ret != -EPROBE_DEFER) dev_err(&dev->dev, "IRQ index %u not found\n", num); @@ -174,29 +226,6 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) EXPORT_SYMBOL_GPL(platform_get_irq); /** - * platform_get_irq_optional - get an optional IRQ for a device - * @dev: platform device - * @num: IRQ number index - * - * Gets an IRQ for a platform device. Device drivers should check the return - * value for errors so as to not pass a negative integer value to the - * request_irq() APIs. This is the same as platform_get_irq(), except that it - * does not print an error message if an IRQ can not be obtained. - * - * Example: - * int irq = platform_get_irq_optional(pdev, 0); - * if (irq < 0) - * return irq; - * - * Return: IRQ number on success, negative error number on failure. - */ -int platform_get_irq_optional(struct platform_device *dev, unsigned int num) -{ - return __platform_get_irq(dev, num); -} -EXPORT_SYMBOL_GPL(platform_get_irq_optional); - -/** * platform_irq_count - Count the number of IRQs a platform device uses * @dev: platform device * @@ -206,7 +235,7 @@ int platform_irq_count(struct platform_device *dev) { int ret, nr = 0; - while ((ret = __platform_get_irq(dev, nr)) >= 0) + while ((ret = platform_get_irq_optional(dev, nr)) >= 0) nr++; if (ret == -EPROBE_DEFER) @@ -245,10 +274,9 @@ static int __platform_get_irq_byname(struct platform_device *dev, const char *name) { struct resource *r; + int ret; if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { - int ret; - ret = of_irq_get_byname(dev->dev.of_node, name); if (ret > 0 || ret == -EPROBE_DEFER) return ret; @@ -1278,6 +1306,11 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); +static inline int __platform_match(struct device *dev, const void *drv) +{ + return platform_match(dev, (struct device_driver *)drv); +} + /** * platform_find_device_by_driver - Find a platform device with a given * driver. @@ -1288,7 +1321,7 @@ struct device *platform_find_device_by_driver(struct device *start, const struct device_driver *drv) { return bus_find_device(&platform_bus_type, start, drv, - (void *)platform_match); + __platform_match); } EXPORT_SYMBOL_GPL(platform_find_device_by_driver); @@ -1296,8 +1329,6 @@ int __init platform_bus_init(void) { int error; - early_platform_cleanup(); - error = device_register(&platform_bus); if (error) { put_device(&platform_bus); @@ -1309,289 +1340,3 @@ int __init platform_bus_init(void) of_platform_register_reconfig_notifier(); return error; } - -static __initdata LIST_HEAD(early_platform_driver_list); -static __initdata LIST_HEAD(early_platform_device_list); - -/** - * early_platform_driver_register - register early platform driver - * @epdrv: early_platform driver structure - * @buf: string passed from early_param() - * - * Helper function for early_platform_init() / early_platform_init_buffer() - */ -int __init early_platform_driver_register(struct early_platform_driver *epdrv, - char *buf) -{ - char *tmp; - int n; - - /* Simply add the driver to the end of the global list. - * Drivers will by default be put on the list in compiled-in order. - */ - if (!epdrv->list.next) { - INIT_LIST_HEAD(&epdrv->list); - list_add_tail(&epdrv->list, &early_platform_driver_list); - } - - /* If the user has specified device then make sure the driver - * gets prioritized. The driver of the last device specified on - * command line will be put first on the list. - */ - n = strlen(epdrv->pdrv->driver.name); - if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { - list_move(&epdrv->list, &early_platform_driver_list); - - /* Allow passing parameters after device name */ - if (buf[n] == '\0' || buf[n] == ',') - epdrv->requested_id = -1; - else { - epdrv->requested_id = simple_strtoul(&buf[n + 1], - &tmp, 10); - - if (buf[n] != '.' || (tmp == &buf[n + 1])) { - epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; - n = 0; - } else - n += strcspn(&buf[n + 1], ",") + 1; - } - - if (buf[n] == ',') - n++; - - if (epdrv->bufsize) { - memcpy(epdrv->buffer, &buf[n], - min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); - epdrv->buffer[epdrv->bufsize - 1] = '\0'; - } - } - - return 0; -} - -/** - * early_platform_add_devices - adds a number of early platform devices - * @devs: array of early platform devices to add - * @num: number of early platform devices in array - * - * Used by early architecture code to register early platform devices and - * their platform data. - */ -void __init early_platform_add_devices(struct platform_device **devs, int num) -{ - struct device *dev; - int i; - - /* simply add the devices to list */ - for (i = 0; i < num; i++) { - dev = &devs[i]->dev; - - if (!dev->devres_head.next) { - pm_runtime_early_init(dev); - INIT_LIST_HEAD(&dev->devres_head); - list_add_tail(&dev->devres_head, - &early_platform_device_list); - } - } -} - -/** - * early_platform_driver_register_all - register early platform drivers - * @class_str: string to identify early platform driver class - * - * Used by architecture code to register all early platform drivers - * for a certain class. If omitted then only early platform drivers - * with matching kernel command line class parameters will be registered. - */ -void __init early_platform_driver_register_all(char *class_str) -{ - /* The "class_str" parameter may or may not be present on the kernel - * command line. If it is present then there may be more than one - * matching parameter. - * - * Since we register our early platform drivers using early_param() - * we need to make sure that they also get registered in the case - * when the parameter is missing from the kernel command line. - * - * We use parse_early_options() to make sure the early_param() gets - * called at least once. The early_param() may be called more than - * once since the name of the preferred device may be specified on - * the kernel command line. early_platform_driver_register() handles - * this case for us. - */ - parse_early_options(class_str); -} - -/** - * early_platform_match - find early platform device matching driver - * @epdrv: early platform driver structure - * @id: id to match against - */ -static struct platform_device * __init -early_platform_match(struct early_platform_driver *epdrv, int id) -{ - struct platform_device *pd; - - list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) - if (platform_match(&pd->dev, &epdrv->pdrv->driver)) - if (pd->id == id) - return pd; - - return NULL; -} - -/** - * early_platform_left - check if early platform driver has matching devices - * @epdrv: early platform driver structure - * @id: return true if id or above exists - */ -static int __init early_platform_left(struct early_platform_driver *epdrv, - int id) -{ - struct platform_device *pd; - - list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) - if (platform_match(&pd->dev, &epdrv->pdrv->driver)) - if (pd->id >= id) - return 1; - - return 0; -} - -/** - * early_platform_driver_probe_id - probe drivers matching class_str and id - * @class_str: string to identify early platform driver class - * @id: id to match against - * @nr_probe: number of platform devices to successfully probe before exiting - */ -static int __init early_platform_driver_probe_id(char *class_str, - int id, - int nr_probe) -{ - struct early_platform_driver *epdrv; - struct platform_device *match; - int match_id; - int n = 0; - int left = 0; - - list_for_each_entry(epdrv, &early_platform_driver_list, list) { - /* only use drivers matching our class_str */ - if (strcmp(class_str, epdrv->class_str)) - continue; - - if (id == -2) { - match_id = epdrv->requested_id; - left = 1; - - } else { - match_id = id; - left += early_platform_left(epdrv, id); - - /* skip requested id */ - switch (epdrv->requested_id) { - case EARLY_PLATFORM_ID_ERROR: - case EARLY_PLATFORM_ID_UNSET: - break; - default: - if (epdrv->requested_id == id) - match_id = EARLY_PLATFORM_ID_UNSET; - } - } - - switch (match_id) { - case EARLY_PLATFORM_ID_ERROR: - pr_warn("%s: unable to parse %s parameter\n", - class_str, epdrv->pdrv->driver.name); - /* fall-through */ - case EARLY_PLATFORM_ID_UNSET: - match = NULL; - break; - default: - match = early_platform_match(epdrv, match_id); - } - - if (match) { - /* - * Set up a sensible init_name to enable - * dev_name() and others to be used before the - * rest of the driver core is initialized. - */ - if (!match->dev.init_name && slab_is_available()) { - if (match->id != -1) - match->dev.init_name = - kasprintf(GFP_KERNEL, "%s.%d", - match->name, - match->id); - else - match->dev.init_name = - kasprintf(GFP_KERNEL, "%s", - match->name); - - if (!match->dev.init_name) - return -ENOMEM; - } - - if (epdrv->pdrv->probe(match)) - pr_warn("%s: unable to probe %s early.\n", - class_str, match->name); - else - n++; - } - - if (n >= nr_probe) - break; - } - - if (left) - return n; - else - return -ENODEV; -} - -/** - * early_platform_driver_probe - probe a class of registered drivers - * @class_str: string to identify early platform driver class - * @nr_probe: number of platform devices to successfully probe before exiting - * @user_only: only probe user specified early platform devices - * - * Used by architecture code to probe registered early platform drivers - * within a certain class. For probe to happen a registered early platform - * device matching a registered early platform driver is needed. - */ -int __init early_platform_driver_probe(char *class_str, - int nr_probe, - int user_only) -{ - int k, n, i; - - n = 0; - for (i = -2; n < nr_probe; i++) { - k = early_platform_driver_probe_id(class_str, i, nr_probe - n); - - if (k < 0) - break; - - n += k; - - if (user_only) - break; - } - - return n; -} - -/** - * early_platform_cleanup - clean up early platform code - */ -void __init early_platform_cleanup(void) -{ - struct platform_device *pd, *pd2; - - /* clean up the devres list used to chain devices */ - list_for_each_entry_safe(pd, pd2, &early_platform_device_list, - dev.devres_head) { - list_del(&pd->dev.devres_head); - memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); - } -} - |