util/sconfig: Drop use of ref_count for chip_instance
chip_instance structure currently uses a ref_count to determine how many devices hold reference to that instance. If the count drops to zero, then it is assumed that the chip instance is a duplicate in override tree and has a similar instance that is already overriden in base device tree. ref_count is currently decremented whenever a device in override tree matches the one in base device tree and the registers from the override tree instance are copied over to the base tree instance. On the other hand, if a device in override tree does not match any device in base tree under a given parent, then the device is added to base tree and all the devices in its subtree that hold pointers to its parent chip instance are updated to point to the parent's chip instance in base tree. This is done as part of update_chip_pointers. However, there are a couple of issues that this suffers from: a) If a device is present only in override tree and it does not have its own chip (i.e. pointing to parent's chip instance), then it results in sconfig emiiting parent's chip instance (which can be the SoC chip instance) in static.c even though it is unused. This is because update_chip_pointers() does not call delete_chip_instance() before reassigning the chip instance pointer. b) If a device is added under root device only in the override tree and it does not have its own chip instance (i.e. uses SoC chip instance), then it results in sconfig emitting a copy of the SoC chip instance and setting that as chip_ops for this new device in the override tree. In order to fix the above issues, this change drops the ref_count field from chip_instance structure and instead adds a forwarding pointer `base_chip_instance`. This is setup as per the following rules: 1. If the instance belongs to base devicetree, base_chip_instance is set to NULL. 2. If the instance belongs to override tree, then it is set to its corresponding chip instance in base tree (if present), else set to NULL. State of base_chip_instance is then used when emitting chips and devices using the following rules: 1. If a chip_instance has non-NULL base_chip_instance, then that chip instance is not emitted to static.c 2. When emitting chip_ops for a device, base_chip_instance is used to determine the correct chip instance name to emit. BUG=b:155549176 TEST=Verified that the static.c file generated for base/override tree combination is correct when new devices without chips are added only to override tree. Change-Id: Idbb5b34f49bf874da3f30ebb6a6a0e2d8d091fe5 Signed-off-by: Furquan Shaikh <furquan@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41007 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
9f681d2d7c
commit
bbade24241
|
@ -128,7 +128,6 @@ static struct chip mainboard_chip = {
|
|||
static struct chip_instance mainboard_instance = {
|
||||
.id = 0,
|
||||
.chip = &mainboard_chip,
|
||||
.ref_count = 2,
|
||||
};
|
||||
|
||||
/* This is the parent of all devices added by parsing the devicetree file. */
|
||||
|
@ -337,54 +336,6 @@ struct chip_instance *new_chip_instance(char *path)
|
|||
return instance;
|
||||
}
|
||||
|
||||
static void delete_chip_instance(struct chip_instance *ins)
|
||||
{
|
||||
|
||||
if (ins->ref_count == 0) {
|
||||
printf("ERROR: ref count for chip instance is zero!!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (--ins->ref_count)
|
||||
return;
|
||||
|
||||
struct chip *c = ins->chip;
|
||||
|
||||
/* Get pointer to first instance of the chip. */
|
||||
struct chip_instance *i = c->instance;
|
||||
|
||||
/*
|
||||
* If chip instance to be deleted is the first instance, then update
|
||||
* instance pointer of the chip as well.
|
||||
*/
|
||||
if (i == ins) {
|
||||
c->instance = ins->next;
|
||||
free(ins);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the instances list of the chip to find and remove the
|
||||
* given instance.
|
||||
*/
|
||||
while (1) {
|
||||
if (i == NULL) {
|
||||
printf("ERROR: chip instance not found!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (i->next != ins) {
|
||||
i = i->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
i->next = ins->next;
|
||||
break;
|
||||
}
|
||||
|
||||
free(ins);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new bus for the provided device.
|
||||
* - If this is the first bus being allocated under this device, then its id
|
||||
|
@ -504,7 +455,6 @@ struct device *new_device(struct bus *parent,
|
|||
new_d->hidden = (status >> 1) & 0x01;
|
||||
new_d->mandatory = (status >> 2) & 0x01;
|
||||
new_d->chip_instance = chip_instance;
|
||||
chip_instance->ref_count++;
|
||||
|
||||
set_new_child(parent, new_d);
|
||||
|
||||
|
@ -780,6 +730,13 @@ static void pass1(FILE *fil, FILE *head, struct device *ptr, struct device *next
|
|||
struct chip_instance *chip_ins = ptr->chip_instance;
|
||||
int has_children = dev_has_children(ptr);
|
||||
|
||||
/*
|
||||
* If the chip instance of device has base_chip_instance pointer set, then follow that
|
||||
* to update the chip instance for current device.
|
||||
*/
|
||||
if (chip_ins->base_chip_instance)
|
||||
chip_ins = chip_ins->base_chip_instance;
|
||||
|
||||
if (ptr == &base_root_dev)
|
||||
fprintf(fil, "DEVTREE_CONST struct device %s = {\n", ptr->name);
|
||||
else
|
||||
|
@ -993,8 +950,14 @@ static void emit_chips(FILE *fil)
|
|||
chip_id = 1;
|
||||
instance = chip->instance;
|
||||
while (instance) {
|
||||
/*
|
||||
* Emit this chip instance only if there is no forwarding pointer to the
|
||||
* base tree chip instance.
|
||||
*/
|
||||
if (instance->base_chip_instance == NULL) {
|
||||
instance->id = chip_id++;
|
||||
emit_chip_instance(fil, instance);
|
||||
}
|
||||
instance = instance->next;
|
||||
}
|
||||
}
|
||||
|
@ -1081,29 +1044,6 @@ static int res_match(struct resource *a, struct resource *b)
|
|||
(a->index == b->index));
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through the override subtree in breadth-first manner starting at node to
|
||||
* see if chip_instance pointer of the node is same as chip_instance pointer of
|
||||
* override parent that is passed into the function. If yes, then update the
|
||||
* chip_instance pointer of the node to chip_instance pointer of the base
|
||||
* parent.
|
||||
*/
|
||||
static void update_chip_pointers(struct device *node,
|
||||
struct chip_instance *base_parent_ci,
|
||||
struct chip_instance *override_parent_ci)
|
||||
{
|
||||
struct queue_entry *q_head = NULL;
|
||||
|
||||
enqueue_tail(&q_head, node);
|
||||
|
||||
while ((node = dequeue_head(&q_head))) {
|
||||
if (node->chip_instance != override_parent_ci)
|
||||
continue;
|
||||
node->chip_instance = base_parent_ci;
|
||||
add_children_to_queue(&q_head, node);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add resource to device. If resource is already present, then update its base
|
||||
* and index. If not, then add a new resource to the device.
|
||||
|
@ -1286,6 +1226,12 @@ static void update_device(struct device *base_dev, struct device *override_dev)
|
|||
reg = reg->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update base_chip_instance member in chip instance of override tree to forward it to
|
||||
* the chip instance in base tree.
|
||||
*/
|
||||
override_dev->chip_instance->base_chip_instance = base_dev->chip_instance;
|
||||
|
||||
/*
|
||||
* Now that the device properties are all copied over, look at each bus
|
||||
* of the override device and run override_devicetree in a recursive
|
||||
|
@ -1312,9 +1258,6 @@ static void update_device(struct device *base_dev, struct device *override_dev)
|
|||
override_bus = override_bus->next_bus;
|
||||
base_bus = base_bus->next_bus;
|
||||
}
|
||||
|
||||
delete_chip_instance(override_dev->chip_instance);
|
||||
override_dev->chip_instance = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1359,14 +1302,6 @@ static void override_devicetree(struct bus *base_parent,
|
|||
* as a new child of base_parent.
|
||||
*/
|
||||
set_new_child(base_parent, override_child);
|
||||
/*
|
||||
* Ensure all nodes in override tree pointing to
|
||||
* override parent chip_instance now point to base
|
||||
* parent chip_instance.
|
||||
*/
|
||||
update_chip_pointers(override_child,
|
||||
base_parent->dev->chip_instance,
|
||||
override_parent->dev->chip_instance);
|
||||
}
|
||||
|
||||
override_child = next_child;
|
||||
|
|
|
@ -56,10 +56,16 @@ struct chip_instance {
|
|||
struct chip_instance *next;
|
||||
|
||||
/*
|
||||
* Reference count - Indicates how many devices hold pointer to this
|
||||
* chip instance.
|
||||
* Pointer to corresponding chip instance in base devicetree.
|
||||
* a) If the chip instance belongs to the base devicetree, then this pointer is set to
|
||||
* NULL.
|
||||
* b) If the chip instance belongs to override tree, then this pointer is set to its
|
||||
* corresponding chip instance in base devicetree (if it exists), else to NULL.
|
||||
*
|
||||
* This is useful when generating chip instances and chip_ops for a device to determine
|
||||
* if this is the instance to emit or if there is a base chip instance to use instead.
|
||||
*/
|
||||
int ref_count;
|
||||
struct chip_instance *base_chip_instance;
|
||||
};
|
||||
|
||||
struct chip {
|
||||
|
|
Loading…
Reference in New Issue