summaryrefslogtreecommitdiff
path: root/drivers/block/blk-uclass.c
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2017-04-23 20:02:07 -0600
committerSimon Glass <sjg@chromium.org>2017-06-01 07:03:05 -0600
commite48eeb9ea3aed67e4bda94c65a7f13e8672a3501 (patch)
tree13a6fb91509ee655c8536577e8ec5101c67ac5dd /drivers/block/blk-uclass.c
parente8abbb531f506dc0cac973b86fb5fa01f0bf88c4 (diff)
dm: blk: Improve block device claiming
The intention with block devices is that the device number (devnum field in its descriptor) matches the alias of its parent device. For example, with: aliases { mmc0 = "/sdhci@700b0600"; mmc1 = "/sdhci@700b0400"; } we expect that the block devices for mmc0 and mmc1 would have device numbers of 0 and 1 respectively. Unfortunately this does not currently always happen. If there is another MMC device earlier in the driver model data structures its block device will be created first. It will therefore get device number 0 and mmc0 will therefore miss out. In this case the MMC device will have sequence number 0 but its block device will not. To avoid this, allow a device to request a device number and bump any existing device number that is using it. This all happens during the binding phase so it is safe to change these numbers around. This allows device numbers to match the aliases in all circumstances. Add a test to verify the behaviour. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/block/blk-uclass.c')
-rw-r--r--drivers/block/blk-uclass.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 881c39f774..6145675271 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -486,6 +486,31 @@ static int blk_next_free_devnum(enum if_type if_type)
return ret + 1;
}
+static int blk_claim_devnum(enum if_type if_type, int devnum)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_BLK, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+ if (desc->if_type == if_type && desc->devnum == devnum) {
+ int next = blk_next_free_devnum(if_type);
+
+ if (next < 0)
+ return next;
+ desc->devnum = next;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
int blk_create_device(struct udevice *parent, const char *drv_name,
const char *name, int if_type, int devnum, int blksz,
lbaint_t size, struct udevice **devp)
@@ -495,11 +520,14 @@ int blk_create_device(struct udevice *parent, const char *drv_name,
int ret;
if (devnum == -1) {
- ret = blk_next_free_devnum(if_type);
- if (ret < 0)
+ devnum = blk_next_free_devnum(if_type);
+ } else {
+ ret = blk_claim_devnum(if_type, devnum);
+ if (ret < 0 && ret != -ENOENT)
return ret;
- devnum = ret;
}
+ if (devnum < 0)
+ return devnum;
ret = device_bind_driver(parent, drv_name, name, &dev);
if (ret)
return ret;