Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

component: add support for component match array

Add support for generating a set of component matches at master probe
time, and submitting them to the component layer. This allows the
component layer to perform the matches internally without needing to
call into the master driver, and allows for further restructuring of
the component helper.

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

+124 -3
+117 -3
drivers/base/component.c
··· 18 18 #include <linux/mutex.h> 19 19 #include <linux/slab.h> 20 20 21 + struct component_match { 22 + size_t alloc; 23 + size_t num; 24 + struct { 25 + void *data; 26 + int (*fn)(struct device *, void *); 27 + } compare[0]; 28 + }; 29 + 21 30 struct master { 22 31 struct list_head node; 23 32 struct list_head components; ··· 34 25 35 26 const struct component_master_ops *ops; 36 27 struct device *dev; 28 + struct component_match *match; 37 29 }; 38 30 39 31 struct component { ··· 106 96 } 107 97 EXPORT_SYMBOL_GPL(component_master_add_child); 108 98 99 + static int find_components(struct master *master) 100 + { 101 + struct component_match *match = master->match; 102 + size_t i; 103 + int ret = 0; 104 + 105 + if (!match) { 106 + /* 107 + * Search the list of components, looking for components that 108 + * belong to this master, and attach them to the master. 109 + */ 110 + return master->ops->add_components(master->dev, master); 111 + } 112 + 113 + /* 114 + * Scan the array of match functions and attach 115 + * any components which are found to this master. 116 + */ 117 + for (i = 0; i < match->num; i++) { 118 + ret = component_master_add_child(master, 119 + match->compare[i].fn, 120 + match->compare[i].data); 121 + if (ret) 122 + break; 123 + } 124 + return ret; 125 + } 126 + 109 127 /* Detach all attached components from this master */ 110 128 static void master_remove_components(struct master *master) 111 129 { ··· 166 128 * Search the list of components, looking for components that 167 129 * belong to this master, and attach them to the master. 168 130 */ 169 - if (master->ops->add_components(master->dev, master)) { 131 + if (find_components(master)) { 170 132 /* Failed to find all components */ 171 133 ret = 0; 172 134 goto out; ··· 224 186 master_remove_components(master); 225 187 } 226 188 227 - int component_master_add(struct device *dev, 228 - const struct component_master_ops *ops) 189 + static size_t component_match_size(size_t num) 190 + { 191 + return offsetof(struct component_match, compare[num]); 192 + } 193 + 194 + static struct component_match *component_match_realloc(struct device *dev, 195 + struct component_match *match, size_t num) 196 + { 197 + struct component_match *new; 198 + 199 + if (match && match->alloc == num) 200 + return match; 201 + 202 + new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL); 203 + if (!new) 204 + return ERR_PTR(-ENOMEM); 205 + 206 + if (match) { 207 + memcpy(new, match, component_match_size(min(match->num, num))); 208 + devm_kfree(dev, match); 209 + } else { 210 + new->num = 0; 211 + } 212 + 213 + new->alloc = num; 214 + 215 + return new; 216 + } 217 + 218 + /* 219 + * Add a component to be matched. 220 + * 221 + * The match array is first created or extended if necessary. 222 + */ 223 + void component_match_add(struct device *dev, struct component_match **matchptr, 224 + int (*compare)(struct device *, void *), void *compare_data) 225 + { 226 + struct component_match *match = *matchptr; 227 + 228 + if (IS_ERR(match)) 229 + return; 230 + 231 + if (!match || match->num == match->alloc) { 232 + size_t new_size = match ? match->alloc + 16 : 15; 233 + 234 + match = component_match_realloc(dev, match, new_size); 235 + 236 + *matchptr = match; 237 + 238 + if (IS_ERR(match)) 239 + return; 240 + } 241 + 242 + match->compare[match->num].fn = compare; 243 + match->compare[match->num].data = compare_data; 244 + match->num++; 245 + } 246 + EXPORT_SYMBOL(component_match_add); 247 + 248 + int component_master_add_with_match(struct device *dev, 249 + const struct component_master_ops *ops, 250 + struct component_match *match) 229 251 { 230 252 struct master *master; 231 253 int ret; 254 + 255 + if (ops->add_components && match) 256 + return -EINVAL; 257 + 258 + /* Reallocate the match array for its true size */ 259 + match = component_match_realloc(dev, match, match->num); 260 + if (IS_ERR(match)) 261 + return PTR_ERR(match); 232 262 233 263 master = kzalloc(sizeof(*master), GFP_KERNEL); 234 264 if (!master) ··· 304 198 305 199 master->dev = dev; 306 200 master->ops = ops; 201 + master->match = match; 307 202 INIT_LIST_HEAD(&master->components); 308 203 309 204 /* Add to the list of available masters. */ ··· 321 214 mutex_unlock(&component_mutex); 322 215 323 216 return ret < 0 ? ret : 0; 217 + } 218 + EXPORT_SYMBOL_GPL(component_master_add_with_match); 219 + 220 + int component_master_add(struct device *dev, 221 + const struct component_master_ops *ops) 222 + { 223 + return component_master_add_with_match(dev, ops, NULL); 324 224 } 325 225 EXPORT_SYMBOL_GPL(component_master_add); 326 226
+7
include/linux/component.h
··· 29 29 int component_master_add_child(struct master *master, 30 30 int (*compare)(struct device *, void *), void *compare_data); 31 31 32 + struct component_match; 33 + 34 + int component_master_add_with_match(struct device *, 35 + const struct component_master_ops *, struct component_match *); 36 + void component_match_add(struct device *, struct component_match **, 37 + int (*compare)(struct device *, void *), void *compare_data); 38 + 32 39 #endif