mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 23:51:33 +00:00
dm: core: Fix allocation of empty of-platdata
With of-platdata we always have a dtv struct that holds the platform data
provided by the driver_info record. However, this struct can be empty if
there are no actual devicetree properties provided.
The upshot of empty platform data is that it will end up as a zero-size
member in the BSS section, which is fine. But if the driver specifies
plat_auto then it expects the correct amount of space to be allocated.
At present this does not happen, since device_bind() assumes that the
platform-data size will always be >0. As a result we end up not
allocating the space and just use the BSS region, overwriting whatever
other contents are present.
Fix this by removing the condition that platform data be non-empty, always
allocating space if requested.
This fixes a strange bug that has been lurking since of-platdata was
implemented. It has likely never been noticed since devices normally have
at least some devicetree properties, BSS is seldom used on SPL, the dtv
structs are normally at the end of bss and the overwriting only happens
if a driver changes its platform data.
It was discovered using sandbox_spl, which exercises more features than
a normal board might, and the critical global_data variable 'gd' happened
to be at the end of BSS.
Fixes: 9fa2819009
("dm: core: Expand platdata for of-platdata devices")
Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
668866aa24
commit
20740e4fbc
1 changed files with 13 additions and 4 deletions
|
@ -92,15 +92,19 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||||
if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
|
if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
|
||||||
dev->seq_ = uclass_find_next_free_seq(uc);
|
dev->seq_ = uclass_find_next_free_seq(uc);
|
||||||
|
|
||||||
|
/* Check if we need to allocate plat */
|
||||||
if (drv->plat_auto) {
|
if (drv->plat_auto) {
|
||||||
bool alloc = !plat;
|
bool alloc = !plat;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For of-platdata, we try use the existing data, but if
|
||||||
|
* plat_auto is larger, we must allocate a new space
|
||||||
|
*/
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||||
if (of_plat_size) {
|
if (of_plat_size)
|
||||||
dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
|
dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
|
||||||
if (of_plat_size < drv->plat_auto)
|
if (of_plat_size < drv->plat_auto)
|
||||||
alloc = true;
|
alloc = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (alloc) {
|
if (alloc) {
|
||||||
dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
|
dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
|
||||||
|
@ -109,6 +113,11 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail_alloc1;
|
goto fail_alloc1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For of-platdata, copy the old plat into the new
|
||||||
|
* space
|
||||||
|
*/
|
||||||
if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
|
if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
|
||||||
memcpy(ptr, plat, of_plat_size);
|
memcpy(ptr, plat, of_plat_size);
|
||||||
dev_set_plat(dev, ptr);
|
dev_set_plat(dev, ptr);
|
||||||
|
|
Loading…
Reference in a new issue