Skip to content

Commit

Permalink
component: track components via array rather than list
Browse files Browse the repository at this point in the history
Since we now have an array which defines each component, maintain the
components to be bound in the array rather than a separate list.  We
also need duplicate tracking so we can eliminate multiple bind calls
for the same component: we preserve the list-based component order in
that the first match which adds the component determines its position.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Dec 7, 2015
1 parent 29f1c7f commit ffc30b7
Showing 1 changed file with 80 additions and 74 deletions.
154 changes: 80 additions & 74 deletions drivers/base/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@
#include <linux/mutex.h>
#include <linux/slab.h>

struct component;

struct component_match {
size_t alloc;
size_t num;
struct {
void *data;
int (*fn)(struct device *, void *);
struct component *component;
bool duplicate;
} compare[0];
};

struct master {
struct list_head node;
struct list_head components;
bool bound;

const struct component_master_ops *ops;
Expand All @@ -39,7 +42,6 @@ struct master {

struct component {
struct list_head node;
struct list_head master_node;
struct master *master;
bool bound;

Expand All @@ -63,46 +65,20 @@ static struct master *__master_find(struct device *dev,
return NULL;
}

/* Attach an unattached component to a master. */
static void component_attach_master(struct master *master, struct component *c)
{
c->master = master;

list_add_tail(&c->master_node, &master->components);
}

/* Detach a component from a master. */
static void component_detach_master(struct master *master, struct component *c)
{
list_del(&c->master_node);

c->master = NULL;
}

/*
* Add a component to a master, finding the component via the compare
* function and compare data. This is safe to call for duplicate matches
* and will not result in the same component being added multiple times.
*/
static int component_master_add_child(struct master *master,
static struct component *find_component(struct master *master,
int (*compare)(struct device *, void *), void *compare_data)
{
struct component *c;
int ret = -ENXIO;

list_for_each_entry(c, &component_list, node) {
if (c->master && c->master != master)
continue;

if (compare(c->dev, compare_data)) {
if (!c->master)
component_attach_master(master, c);
ret = 0;
break;
}
if (compare(c->dev, compare_data))
return c;
}

return ret;
return NULL;
}

static int find_components(struct master *master)
Expand All @@ -116,26 +92,39 @@ static int find_components(struct master *master)
* any components which are found to this master.
*/
for (i = 0; i < match->num; i++) {
ret = component_master_add_child(master,
match->compare[i].fn,
match->compare[i].data);
if (ret)
struct component *c;

dev_dbg(master->dev, "Looking for component %zu\n", i);

if (match->compare[i].component)
continue;

c = find_component(master, match->compare[i].fn,
match->compare[i].data);
if (!c) {
ret = -ENXIO;
break;
}

dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);

/* Attach this component to the master */
match->compare[i].duplicate = !!c->master;
match->compare[i].component = c;
c->master = master;
}
return ret;
}

/* Detach all attached components from this master */
static void master_remove_components(struct master *master)
/* Detach component from associated master */
static void remove_component(struct master *master, struct component *c)
{
while (!list_empty(&master->components)) {
struct component *c = list_first_entry(&master->components,
struct component, master_node);

WARN_ON(c->master != master);
size_t i;

component_detach_master(master, c);
}
/* Detach the component from this master. */
for (i = 0; i < master->match->num; i++)
if (master->match->compare[i].component == c)
master->match->compare[i].component = NULL;
}

/*
Expand All @@ -150,37 +139,32 @@ static int try_to_bring_up_master(struct master *master,
{
int ret;

dev_dbg(master->dev, "trying to bring up master\n");

if (find_components(master)) {
/* Failed to find all components */
ret = 0;
goto out;
dev_dbg(master->dev, "master has incomplete components\n");
return 0;
}

if (component && component->master != master) {
ret = 0;
goto out;
dev_dbg(master->dev, "master is not for this component (%s)\n",
dev_name(component->dev));
return 0;
}

if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
ret = -ENOMEM;
goto out;
}
if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
return -ENOMEM;

/* Found all components */
ret = master->ops->bind(master->dev);
if (ret < 0) {
devres_release_group(master->dev, NULL);
dev_info(master->dev, "master bind failed: %d\n", ret);
goto out;
return ret;
}

master->bound = true;
return 1;

out:
master_remove_components(master);

return ret;
}

static int try_to_bring_up_masters(struct component *component)
Expand All @@ -206,8 +190,6 @@ static void take_down_master(struct master *master)
devres_release_group(master->dev, NULL);
master->bound = false;
}

master_remove_components(master);
}

static size_t component_match_size(size_t num)
Expand Down Expand Up @@ -265,6 +247,7 @@ void component_match_add(struct device *dev, struct component_match **matchptr,

match->compare[match->num].fn = compare;
match->compare[match->num].data = compare_data;
match->compare[match->num].component = NULL;
match->num++;
}
EXPORT_SYMBOL(component_match_add);
Expand All @@ -288,7 +271,6 @@ int component_master_add_with_match(struct device *dev,
master->dev = dev;
master->ops = ops;
master->match = match;
INIT_LIST_HEAD(&master->components);

/* Add to the list of available masters. */
mutex_lock(&component_mutex);
Expand All @@ -311,13 +293,24 @@ void component_master_del(struct device *dev,
const struct component_master_ops *ops)
{
struct master *master;
int i;

mutex_lock(&component_mutex);
master = __master_find(dev, ops);
if (master) {
struct component_match *match = master->match;

take_down_master(master);

list_del(&master->node);

if (match) {
for (i = 0; i < match->num; i++) {
struct component *c = match->compare[i].component;
if (c)
c->master = NULL;
}
}
kfree(master);
}
mutex_unlock(&component_mutex);
Expand All @@ -340,15 +333,20 @@ void component_unbind_all(struct device *master_dev, void *data)
{
struct master *master;
struct component *c;
size_t i;

WARN_ON(!mutex_is_locked(&component_mutex));

master = __master_find(master_dev, NULL);
if (!master)
return;

list_for_each_entry_reverse(c, &master->components, master_node)
component_unbind(c, master, data);
/* Unbind components in reverse order */
for (i = master->match->num; i--; )
if (!master->match->compare[i].duplicate) {
c = master->match->compare[i].component;
component_unbind(c, master, data);
}
}
EXPORT_SYMBOL_GPL(component_unbind_all);

Expand Down Expand Up @@ -408,6 +406,7 @@ int component_bind_all(struct device *master_dev, void *data)
{
struct master *master;
struct component *c;
size_t i;
int ret = 0;

WARN_ON(!mutex_is_locked(&component_mutex));
Expand All @@ -416,16 +415,21 @@ int component_bind_all(struct device *master_dev, void *data)
if (!master)
return -EINVAL;

list_for_each_entry(c, &master->components, master_node) {
ret = component_bind(c, master, data);
if (ret)
break;
}
/* Bind components in match order */
for (i = 0; i < master->match->num; i++)
if (!master->match->compare[i].duplicate) {
c = master->match->compare[i].component;
ret = component_bind(c, master, data);
if (ret)
break;
}

if (ret != 0) {
list_for_each_entry_continue_reverse(c, &master->components,
master_node)
component_unbind(c, master, data);
for (; i--; )
if (!master->match->compare[i].duplicate) {
c = master->match->compare[i].component;
component_unbind(c, master, data);
}
}

return ret;
Expand Down Expand Up @@ -473,8 +477,10 @@ void component_del(struct device *dev, const struct component_ops *ops)
break;
}

if (component && component->master)
if (component && component->master) {
take_down_master(component->master);
remove_component(component->master, component);
}

mutex_unlock(&component_mutex);

Expand Down

0 comments on commit ffc30b7

Please sign in to comment.