diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/arch_topology.c | 15 | ||||
-rw-r--r-- | drivers/base/core.c | 93 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 7 | ||||
-rw-r--r-- | drivers/base/swnode.c | 3 | ||||
-rw-r--r-- | drivers/base/test/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/topology.c | 10 |
6 files changed, 97 insertions, 33 deletions
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 43407665918f..fc0836f460fb 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -600,6 +600,11 @@ const struct cpumask *cpu_coregroup_mask(int cpu) return core_mask; } +const struct cpumask *cpu_clustergroup_mask(int cpu) +{ + return &cpu_topology[cpu].cluster_sibling; +} + void update_siblings_masks(unsigned int cpuid) { struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; @@ -617,6 +622,12 @@ void update_siblings_masks(unsigned int cpuid) if (cpuid_topo->package_id != cpu_topo->package_id) continue; + if (cpuid_topo->cluster_id == cpu_topo->cluster_id && + cpuid_topo->cluster_id != -1) { + cpumask_set_cpu(cpu, &cpuid_topo->cluster_sibling); + cpumask_set_cpu(cpuid, &cpu_topo->cluster_sibling); + } + cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); @@ -635,6 +646,9 @@ static void clear_cpu_topology(int cpu) cpumask_clear(&cpu_topo->llc_sibling); cpumask_set_cpu(cpu, &cpu_topo->llc_sibling); + cpumask_clear(&cpu_topo->cluster_sibling); + cpumask_set_cpu(cpu, &cpu_topo->cluster_sibling); + cpumask_clear(&cpu_topo->core_sibling); cpumask_set_cpu(cpu, &cpu_topo->core_sibling); cpumask_clear(&cpu_topo->thread_sibling); @@ -650,6 +664,7 @@ void __init reset_cpu_topology(void) cpu_topo->thread_id = -1; cpu_topo->core_id = -1; + cpu_topo->cluster_id = -1; cpu_topo->package_id = -1; cpu_topo->llc_id = -1; diff --git a/drivers/base/core.c b/drivers/base/core.c index e65dd803a453..249da496581a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -95,6 +95,8 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup) list_add(&link->s_hook, &sup->consumers); list_add(&link->c_hook, &con->suppliers); + pr_debug("%pfwP Linked as a fwnode consumer to %pfwP\n", + con, sup); out: mutex_unlock(&fwnode_link_lock); @@ -102,6 +104,21 @@ out: } /** + * __fwnode_link_del - Delete a link between two fwnode_handles. + * @link: the fwnode_link to be deleted + * + * The fwnode_link_lock needs to be held when this function is called. + */ +static void __fwnode_link_del(struct fwnode_link *link) +{ + pr_debug("%pfwP Dropping the fwnode link to %pfwP\n", + link->consumer, link->supplier); + list_del(&link->s_hook); + list_del(&link->c_hook); + kfree(link); +} + +/** * fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle. * @fwnode: fwnode whose supplier links need to be deleted * @@ -112,11 +129,8 @@ static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode) struct fwnode_link *link, *tmp; mutex_lock(&fwnode_link_lock); - list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) { - list_del(&link->s_hook); - list_del(&link->c_hook); - kfree(link); - } + list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) + __fwnode_link_del(link); mutex_unlock(&fwnode_link_lock); } @@ -131,11 +145,8 @@ static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode) struct fwnode_link *link, *tmp; mutex_lock(&fwnode_link_lock); - list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) { - list_del(&link->s_hook); - list_del(&link->c_hook); - kfree(link); - } + list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) + __fwnode_link_del(link); mutex_unlock(&fwnode_link_lock); } @@ -676,7 +687,8 @@ struct device_link *device_link_add(struct device *consumer, { struct device_link *link; - if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS || + if (!consumer || !supplier || consumer == supplier || + flags & ~DL_ADD_VALID_FLAGS || (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) || (flags & DL_FLAG_SYNC_STATE_ONLY && (flags & ~DL_FLAG_INFERRED) != DL_FLAG_SYNC_STATE_ONLY) || @@ -975,6 +987,7 @@ int device_links_check_suppliers(struct device *dev) { struct device_link *link; int ret = 0; + struct fwnode_handle *sup_fw; /* * Device waiting for supplier to become available is not allowed to @@ -983,10 +996,11 @@ int device_links_check_suppliers(struct device *dev) mutex_lock(&fwnode_link_lock); if (dev->fwnode && !list_empty(&dev->fwnode->suppliers) && !fw_devlink_is_permissive()) { - dev_dbg(dev, "probe deferral - wait for supplier %pfwP\n", - list_first_entry(&dev->fwnode->suppliers, - struct fwnode_link, - c_hook)->supplier); + sup_fw = list_first_entry(&dev->fwnode->suppliers, + struct fwnode_link, + c_hook)->supplier; + dev_err_probe(dev, -EPROBE_DEFER, "wait for supplier %pfwP\n", + sup_fw); mutex_unlock(&fwnode_link_lock); return -EPROBE_DEFER; } @@ -1001,8 +1015,9 @@ int device_links_check_suppliers(struct device *dev) if (link->status != DL_STATE_AVAILABLE && !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { device_links_missing_supplier(dev); - dev_dbg(dev, "probe deferral - supplier %s not ready\n", - dev_name(link->supplier)); + dev_err_probe(dev, -EPROBE_DEFER, + "supplier %s not ready\n", + dev_name(link->supplier)); ret = -EPROBE_DEFER; break; } @@ -1722,6 +1737,25 @@ static int fw_devlink_create_devlink(struct device *con, struct device *sup_dev; int ret = 0; + /* + * In some cases, a device P might also be a supplier to its child node + * C. However, this would defer the probe of C until the probe of P + * completes successfully. This is perfectly fine in the device driver + * model. device_add() doesn't guarantee probe completion of the device + * by the time it returns. + * + * However, there are a few drivers that assume C will finish probing + * as soon as it's added and before P finishes probing. So, we provide + * a flag to let fw_devlink know not to delay the probe of C until the + * probe of P completes successfully. + * + * When such a flag is set, we can't create device links where P is the + * supplier of C as that would delay the probe of C. + */ + if (sup_handle->flags & FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD && + fwnode_is_ancestor_of(sup_handle, con->fwnode)) + return -EINVAL; + sup_dev = get_dev_from_fwnode(sup_handle); if (sup_dev) { /* @@ -1772,14 +1806,21 @@ static int fw_devlink_create_devlink(struct device *con, * be broken by applying logic. Check for these types of cycles and * break them so that devices in the cycle probe properly. * - * If the supplier's parent is dependent on the consumer, then - * the consumer-supplier dependency is a false dependency. So, - * treat it as an invalid link. + * If the supplier's parent is dependent on the consumer, then the + * consumer and supplier have a cyclic dependency. Since fw_devlink + * can't tell which of the inferred dependencies are incorrect, don't + * enforce probe ordering between any of the devices in this cyclic + * dependency. Do this by relaxing all the fw_devlink device links in + * this cycle and by treating the fwnode link between the consumer and + * the supplier as an invalid dependency. */ sup_dev = fwnode_get_next_parent_dev(sup_handle); if (sup_dev && device_is_dependent(con, sup_dev)) { - dev_dbg(con, "Not linking to %pfwP - False link\n", - sup_handle); + dev_info(con, "Fixing up cyclic dependency with %pfwP (%s)\n", + sup_handle, dev_name(sup_dev)); + device_links_write_lock(); + fw_devlink_relax_cycle(con, sup_dev); + device_links_write_unlock(); ret = -EINVAL; } else { /* @@ -1858,9 +1899,7 @@ static void __fw_devlink_link_to_consumers(struct device *dev) if (!own_link || ret == -EAGAIN) continue; - list_del(&link->s_hook); - list_del(&link->c_hook); - kfree(link); + __fwnode_link_del(link); } } @@ -1912,9 +1951,7 @@ static void __fw_devlink_link_to_suppliers(struct device *dev, if (!own_link || ret == -EAGAIN) continue; - list_del(&link->s_hook); - list_del(&link->c_hook); - kfree(link); + __fwnode_link_del(link); /* If no device link was created, nothing more to do. */ if (ret) diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index cfa29dc89bbf..fabf87058d80 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -281,14 +281,14 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, if (!blk) return -ENOMEM; + rbnode->block = blk; + if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) { present = krealloc(rbnode->cache_present, BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL); - if (!present) { - kfree(blk); + if (!present) return -ENOMEM; - } memset(present + BITS_TO_LONGS(rbnode->blklen), 0, (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen)) @@ -305,7 +305,6 @@ static int regcache_rbtree_insert_to_block(struct regmap *map, } /* update the rbnode block, its size and the base register */ - rbnode->block = blk; rbnode->blklen = blklen; rbnode->base_reg = base_reg; rbnode->cache_present = present; diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 7bd0f3cfb7eb..c46f6a8e14d2 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -1116,6 +1116,9 @@ int device_create_managed_software_node(struct device *dev, to_swnode(fwnode)->managed = true; set_secondary_fwnode(dev, fwnode); + if (device_is_registered(dev)) + software_node_notify(dev); + return 0; } EXPORT_SYMBOL_GPL(device_create_managed_software_node); diff --git a/drivers/base/test/Makefile b/drivers/base/test/Makefile index 64b2f3d744d5..7f76fee6f989 100644 --- a/drivers/base/test/Makefile +++ b/drivers/base/test/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o -CFLAGS_REMOVE_property-entry-test.o += -fplugin-arg-structleak_plugin-byref -fplugin-arg-structleak_plugin-byref-all +CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN) diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 43c0940643f5..8f2b641d0b8c 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -48,6 +48,9 @@ static DEVICE_ATTR_RO(physical_package_id); define_id_show_func(die_id); static DEVICE_ATTR_RO(die_id); +define_id_show_func(cluster_id); +static DEVICE_ATTR_RO(cluster_id); + define_id_show_func(core_id); static DEVICE_ATTR_RO(core_id); @@ -63,6 +66,10 @@ define_siblings_read_func(core_siblings, core_cpumask); static BIN_ATTR_RO(core_siblings, 0); static BIN_ATTR_RO(core_siblings_list, 0); +define_siblings_read_func(cluster_cpus, cluster_cpumask); +static BIN_ATTR_RO(cluster_cpus, 0); +static BIN_ATTR_RO(cluster_cpus_list, 0); + define_siblings_read_func(die_cpus, die_cpumask); static BIN_ATTR_RO(die_cpus, 0); static BIN_ATTR_RO(die_cpus_list, 0); @@ -94,6 +101,8 @@ static struct bin_attribute *bin_attrs[] = { &bin_attr_thread_siblings_list, &bin_attr_core_siblings, &bin_attr_core_siblings_list, + &bin_attr_cluster_cpus, + &bin_attr_cluster_cpus_list, &bin_attr_die_cpus, &bin_attr_die_cpus_list, &bin_attr_package_cpus, @@ -112,6 +121,7 @@ static struct bin_attribute *bin_attrs[] = { static struct attribute *default_attrs[] = { &dev_attr_physical_package_id.attr, &dev_attr_die_id.attr, + &dev_attr_cluster_id.attr, &dev_attr_core_id.attr, #ifdef CONFIG_SCHED_BOOK &dev_attr_book_id.attr, |