linux/drivers/base/component.c
<<
>>
Prefs
   1/*
   2 * Componentized device handling.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This is work in progress.  We gather up the component devices into a list,
   9 * and bind them when instructed.  At the moment, we're specific to the DRM
  10 * subsystem, and only handles one master device, but this doesn't have to be
  11 * the case.
  12 */
  13#include <linux/component.h>
  14#include <linux/device.h>
  15#include <linux/kref.h>
  16#include <linux/list.h>
  17#include <linux/module.h>
  18#include <linux/mutex.h>
  19#include <linux/slab.h>
  20
  21struct 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
  30struct master {
  31        struct list_head node;
  32        struct list_head components;
  33        bool bound;
  34
  35        const struct component_master_ops *ops;
  36        struct device *dev;
  37        struct component_match *match;
  38};
  39
  40struct component {
  41        struct list_head node;
  42        struct list_head master_node;
  43        struct master *master;
  44        bool bound;
  45
  46        const struct component_ops *ops;
  47        struct device *dev;
  48};
  49
  50static DEFINE_MUTEX(component_mutex);
  51static LIST_HEAD(component_list);
  52static LIST_HEAD(masters);
  53
  54static struct master *__master_find(struct device *dev,
  55        const struct component_master_ops *ops)
  56{
  57        struct master *m;
  58
  59        list_for_each_entry(m, &masters, node)
  60                if (m->dev == dev && (!ops || m->ops == ops))
  61                        return m;
  62
  63        return NULL;
  64}
  65
  66/* Attach an unattached component to a master. */
  67static void component_attach_master(struct master *master, struct component *c)
  68{
  69        c->master = master;
  70
  71        list_add_tail(&c->master_node, &master->components);
  72}
  73
  74/* Detach a component from a master. */
  75static void component_detach_master(struct master *master, struct component *c)
  76{
  77        list_del(&c->master_node);
  78
  79        c->master = NULL;
  80}
  81
  82/*
  83 * Add a component to a master, finding the component via the compare
  84 * function and compare data.  This is safe to call for duplicate matches
  85 * and will not result in the same component being added multiple times.
  86 */
  87int component_master_add_child(struct master *master,
  88        int (*compare)(struct device *, void *), void *compare_data)
  89{
  90        struct component *c;
  91        int ret = -ENXIO;
  92
  93        list_for_each_entry(c, &component_list, node) {
  94                if (c->master && c->master != master)
  95                        continue;
  96
  97                if (compare(c->dev, compare_data)) {
  98                        if (!c->master)
  99                                component_attach_master(master, c);
 100                        ret = 0;
 101                        break;
 102                }
 103        }
 104
 105        return ret;
 106}
 107EXPORT_SYMBOL_GPL(component_master_add_child);
 108
 109static int find_components(struct master *master)
 110{
 111        struct component_match *match = master->match;
 112        size_t i;
 113        int ret = 0;
 114
 115        if (!match) {
 116                /*
 117                 * Search the list of components, looking for components that
 118                 * belong to this master, and attach them to the master.
 119                 */
 120                return master->ops->add_components(master->dev, master);
 121        }
 122
 123        /*
 124         * Scan the array of match functions and attach
 125         * any components which are found to this master.
 126         */
 127        for (i = 0; i < match->num; i++) {
 128                ret = component_master_add_child(master,
 129                                                 match->compare[i].fn,
 130                                                 match->compare[i].data);
 131                if (ret)
 132                        break;
 133        }
 134        return ret;
 135}
 136
 137/* Detach all attached components from this master */
 138static void master_remove_components(struct master *master)
 139{
 140        while (!list_empty(&master->components)) {
 141                struct component *c = list_first_entry(&master->components,
 142                                        struct component, master_node);
 143
 144                WARN_ON(c->master != master);
 145
 146                component_detach_master(master, c);
 147        }
 148}
 149
 150/*
 151 * Try to bring up a master.  If component is NULL, we're interested in
 152 * this master, otherwise it's a component which must be present to try
 153 * and bring up the master.
 154 *
 155 * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
 156 */
 157static int try_to_bring_up_master(struct master *master,
 158        struct component *component)
 159{
 160        int ret;
 161
 162        if (master->bound)
 163                return 0;
 164
 165        /*
 166         * Search the list of components, looking for components that
 167         * belong to this master, and attach them to the master.
 168         */
 169        if (find_components(master)) {
 170                /* Failed to find all components */
 171                ret = 0;
 172                goto out;
 173        }
 174
 175        if (component && component->master != master) {
 176                ret = 0;
 177                goto out;
 178        }
 179
 180        if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
 181                ret = -ENOMEM;
 182                goto out;
 183        }
 184
 185        /* Found all components */
 186        ret = master->ops->bind(master->dev);
 187        if (ret < 0) {
 188                devres_release_group(master->dev, NULL);
 189                dev_info(master->dev, "master bind failed: %d\n", ret);
 190                goto out;
 191        }
 192
 193        master->bound = true;
 194        return 1;
 195
 196out:
 197        master_remove_components(master);
 198
 199        return ret;
 200}
 201
 202static int try_to_bring_up_masters(struct component *component)
 203{
 204        struct master *m;
 205        int ret = 0;
 206
 207        list_for_each_entry(m, &masters, node) {
 208                ret = try_to_bring_up_master(m, component);
 209                if (ret != 0)
 210                        break;
 211        }
 212
 213        return ret;
 214}
 215
 216static void take_down_master(struct master *master)
 217{
 218        if (master->bound) {
 219                master->ops->unbind(master->dev);
 220                devres_release_group(master->dev, NULL);
 221                master->bound = false;
 222        }
 223
 224        master_remove_components(master);
 225}
 226
 227static size_t component_match_size(size_t num)
 228{
 229        return offsetof(struct component_match, compare[num]);
 230}
 231
 232static struct component_match *component_match_realloc(struct device *dev,
 233        struct component_match *match, size_t num)
 234{
 235        struct component_match *new;
 236
 237        if (match && match->alloc == num)
 238                return match;
 239
 240        new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
 241        if (!new)
 242                return ERR_PTR(-ENOMEM);
 243
 244        if (match) {
 245                memcpy(new, match, component_match_size(min(match->num, num)));
 246                devm_kfree(dev, match);
 247        } else {
 248                new->num = 0;
 249        }
 250
 251        new->alloc = num;
 252
 253        return new;
 254}
 255
 256/*
 257 * Add a component to be matched.
 258 *
 259 * The match array is first created or extended if necessary.
 260 */
 261void component_match_add(struct device *dev, struct component_match **matchptr,
 262        int (*compare)(struct device *, void *), void *compare_data)
 263{
 264        struct component_match *match = *matchptr;
 265
 266        if (IS_ERR(match))
 267                return;
 268
 269        if (!match || match->num == match->alloc) {
 270                size_t new_size = match ? match->alloc + 16 : 15;
 271
 272                match = component_match_realloc(dev, match, new_size);
 273
 274                *matchptr = match;
 275
 276                if (IS_ERR(match))
 277                        return;
 278        }
 279
 280        match->compare[match->num].fn = compare;
 281        match->compare[match->num].data = compare_data;
 282        match->num++;
 283}
 284EXPORT_SYMBOL(component_match_add);
 285
 286int component_master_add_with_match(struct device *dev,
 287        const struct component_master_ops *ops,
 288        struct component_match *match)
 289{
 290        struct master *master;
 291        int ret;
 292
 293        if (ops->add_components && match)
 294                return -EINVAL;
 295
 296        if (match) {
 297                /* Reallocate the match array for its true size */
 298                match = component_match_realloc(dev, match, match->num);
 299                if (IS_ERR(match))
 300                        return PTR_ERR(match);
 301        }
 302
 303        master = kzalloc(sizeof(*master), GFP_KERNEL);
 304        if (!master)
 305                return -ENOMEM;
 306
 307        master->dev = dev;
 308        master->ops = ops;
 309        master->match = match;
 310        INIT_LIST_HEAD(&master->components);
 311
 312        /* Add to the list of available masters. */
 313        mutex_lock(&component_mutex);
 314        list_add(&master->node, &masters);
 315
 316        ret = try_to_bring_up_master(master, NULL);
 317
 318        if (ret < 0) {
 319                /* Delete off the list if we weren't successful */
 320                list_del(&master->node);
 321                kfree(master);
 322        }
 323        mutex_unlock(&component_mutex);
 324
 325        return ret < 0 ? ret : 0;
 326}
 327EXPORT_SYMBOL_GPL(component_master_add_with_match);
 328
 329int component_master_add(struct device *dev,
 330        const struct component_master_ops *ops)
 331{
 332        return component_master_add_with_match(dev, ops, NULL);
 333}
 334EXPORT_SYMBOL_GPL(component_master_add);
 335
 336void component_master_del(struct device *dev,
 337        const struct component_master_ops *ops)
 338{
 339        struct master *master;
 340
 341        mutex_lock(&component_mutex);
 342        master = __master_find(dev, ops);
 343        if (master) {
 344                take_down_master(master);
 345
 346                list_del(&master->node);
 347                kfree(master);
 348        }
 349        mutex_unlock(&component_mutex);
 350}
 351EXPORT_SYMBOL_GPL(component_master_del);
 352
 353static void component_unbind(struct component *component,
 354        struct master *master, void *data)
 355{
 356        WARN_ON(!component->bound);
 357
 358        component->ops->unbind(component->dev, master->dev, data);
 359        component->bound = false;
 360
 361        /* Release all resources claimed in the binding of this component */
 362        devres_release_group(component->dev, component);
 363}
 364
 365void component_unbind_all(struct device *master_dev, void *data)
 366{
 367        struct master *master;
 368        struct component *c;
 369
 370        WARN_ON(!mutex_is_locked(&component_mutex));
 371
 372        master = __master_find(master_dev, NULL);
 373        if (!master)
 374                return;
 375
 376        list_for_each_entry_reverse(c, &master->components, master_node)
 377                component_unbind(c, master, data);
 378}
 379EXPORT_SYMBOL_GPL(component_unbind_all);
 380
 381static int component_bind(struct component *component, struct master *master,
 382        void *data)
 383{
 384        int ret;
 385
 386        /*
 387         * Each component initialises inside its own devres group.
 388         * This allows us to roll-back a failed component without
 389         * affecting anything else.
 390         */
 391        if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
 392                return -ENOMEM;
 393
 394        /*
 395         * Also open a group for the device itself: this allows us
 396         * to release the resources claimed against the sub-device
 397         * at the appropriate moment.
 398         */
 399        if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
 400                devres_release_group(master->dev, NULL);
 401                return -ENOMEM;
 402        }
 403
 404        dev_dbg(master->dev, "binding %s (ops %ps)\n",
 405                dev_name(component->dev), component->ops);
 406
 407        ret = component->ops->bind(component->dev, master->dev, data);
 408        if (!ret) {
 409                component->bound = true;
 410
 411                /*
 412                 * Close the component device's group so that resources
 413                 * allocated in the binding are encapsulated for removal
 414                 * at unbind.  Remove the group on the DRM device as we
 415                 * can clean those resources up independently.
 416                 */
 417                devres_close_group(component->dev, NULL);
 418                devres_remove_group(master->dev, NULL);
 419
 420                dev_info(master->dev, "bound %s (ops %ps)\n",
 421                         dev_name(component->dev), component->ops);
 422        } else {
 423                devres_release_group(component->dev, NULL);
 424                devres_release_group(master->dev, NULL);
 425
 426                dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
 427                        dev_name(component->dev), component->ops, ret);
 428        }
 429
 430        return ret;
 431}
 432
 433int component_bind_all(struct device *master_dev, void *data)
 434{
 435        struct master *master;
 436        struct component *c;
 437        int ret = 0;
 438
 439        WARN_ON(!mutex_is_locked(&component_mutex));
 440
 441        master = __master_find(master_dev, NULL);
 442        if (!master)
 443                return -EINVAL;
 444
 445        list_for_each_entry(c, &master->components, master_node) {
 446                ret = component_bind(c, master, data);
 447                if (ret)
 448                        break;
 449        }
 450
 451        if (ret != 0) {
 452                list_for_each_entry_continue_reverse(c, &master->components,
 453                                                     master_node)
 454                        component_unbind(c, master, data);
 455        }
 456
 457        return ret;
 458}
 459EXPORT_SYMBOL_GPL(component_bind_all);
 460
 461int component_add(struct device *dev, const struct component_ops *ops)
 462{
 463        struct component *component;
 464        int ret;
 465
 466        component = kzalloc(sizeof(*component), GFP_KERNEL);
 467        if (!component)
 468                return -ENOMEM;
 469
 470        component->ops = ops;
 471        component->dev = dev;
 472
 473        dev_dbg(dev, "adding component (ops %ps)\n", ops);
 474
 475        mutex_lock(&component_mutex);
 476        list_add_tail(&component->node, &component_list);
 477
 478        ret = try_to_bring_up_masters(component);
 479        if (ret < 0) {
 480                list_del(&component->node);
 481
 482                kfree(component);
 483        }
 484        mutex_unlock(&component_mutex);
 485
 486        return ret < 0 ? ret : 0;
 487}
 488EXPORT_SYMBOL_GPL(component_add);
 489
 490void component_del(struct device *dev, const struct component_ops *ops)
 491{
 492        struct component *c, *component = NULL;
 493
 494        mutex_lock(&component_mutex);
 495        list_for_each_entry(c, &component_list, node)
 496                if (c->dev == dev && c->ops == ops) {
 497                        list_del(&c->node);
 498                        component = c;
 499                        break;
 500                }
 501
 502        if (component && component->master)
 503                take_down_master(component->master);
 504
 505        mutex_unlock(&component_mutex);
 506
 507        WARN_ON(!component);
 508        kfree(component);
 509}
 510EXPORT_SYMBOL_GPL(component_del);
 511
 512MODULE_LICENSE("GPL v2");
 513