uboot/drivers/block/blk-uclass.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Google, Inc
   3 * Written by Simon Glass <sjg@chromium.org>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <blk.h>
  10#include <dm.h>
  11#include <dm/device-internal.h>
  12#include <dm/lists.h>
  13
  14static const char *if_typename_str[IF_TYPE_COUNT] = {
  15        [IF_TYPE_IDE]           = "ide",
  16        [IF_TYPE_SCSI]          = "scsi",
  17        [IF_TYPE_ATAPI]         = "atapi",
  18        [IF_TYPE_USB]           = "usb",
  19        [IF_TYPE_DOC]           = "doc",
  20        [IF_TYPE_MMC]           = "mmc",
  21        [IF_TYPE_SD]            = "sd",
  22        [IF_TYPE_SATA]          = "sata",
  23        [IF_TYPE_HOST]          = "host",
  24        [IF_TYPE_SYSTEMACE]     = "ace",
  25};
  26
  27static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
  28        [IF_TYPE_IDE]           = UCLASS_INVALID,
  29        [IF_TYPE_SCSI]          = UCLASS_SCSI,
  30        [IF_TYPE_ATAPI]         = UCLASS_INVALID,
  31        [IF_TYPE_USB]           = UCLASS_MASS_STORAGE,
  32        [IF_TYPE_DOC]           = UCLASS_INVALID,
  33        [IF_TYPE_MMC]           = UCLASS_MMC,
  34        [IF_TYPE_SD]            = UCLASS_INVALID,
  35        [IF_TYPE_SATA]          = UCLASS_AHCI,
  36        [IF_TYPE_HOST]          = UCLASS_ROOT,
  37        [IF_TYPE_SYSTEMACE]     = UCLASS_INVALID,
  38};
  39
  40static enum if_type if_typename_to_iftype(const char *if_typename)
  41{
  42        int i;
  43
  44        for (i = 0; i < IF_TYPE_COUNT; i++) {
  45                if (if_typename_str[i] &&
  46                    !strcmp(if_typename, if_typename_str[i]))
  47                        return i;
  48        }
  49
  50        return IF_TYPE_UNKNOWN;
  51}
  52
  53static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
  54{
  55        return if_type_uclass_id[if_type];
  56}
  57
  58struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
  59{
  60        struct blk_desc *desc;
  61        struct udevice *dev;
  62        int ret;
  63
  64        ret = blk_get_device(if_type, devnum, &dev);
  65        if (ret)
  66                return NULL;
  67        desc = dev_get_uclass_platdata(dev);
  68
  69        return desc;
  70}
  71
  72/*
  73 * This function is complicated with driver model. We look up the interface
  74 * name in a local table. This gives us an interface type which we can match
  75 * against the uclass of the block device's parent.
  76 */
  77struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
  78{
  79        enum uclass_id uclass_id;
  80        enum if_type if_type;
  81        struct udevice *dev;
  82        struct uclass *uc;
  83        int ret;
  84
  85        if_type = if_typename_to_iftype(if_typename);
  86        if (if_type == IF_TYPE_UNKNOWN) {
  87                debug("%s: Unknown interface type '%s'\n", __func__,
  88                      if_typename);
  89                return NULL;
  90        }
  91        uclass_id = if_type_to_uclass_id(if_type);
  92        if (uclass_id == UCLASS_INVALID) {
  93                debug("%s: Unknown uclass for interface type'\n",
  94                      if_typename_str[if_type]);
  95                return NULL;
  96        }
  97
  98        ret = uclass_get(UCLASS_BLK, &uc);
  99        if (ret)
 100                return NULL;
 101        uclass_foreach_dev(dev, uc) {
 102                struct blk_desc *desc = dev_get_uclass_platdata(dev);
 103
 104                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 105                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 106                if (desc->devnum != devnum)
 107                        continue;
 108
 109                /* Find out the parent device uclass */
 110                if (device_get_uclass_id(dev->parent) != uclass_id) {
 111                        debug("%s: parent uclass %d, this dev %d\n", __func__,
 112                              device_get_uclass_id(dev->parent), uclass_id);
 113                        continue;
 114                }
 115
 116                if (device_probe(dev))
 117                        return NULL;
 118
 119                debug("%s: Device desc %p\n", __func__, desc);
 120                return desc;
 121        }
 122        debug("%s: No device found\n", __func__);
 123
 124        return NULL;
 125}
 126
 127/**
 128 * get_desc() - Get the block device descriptor for the given device number
 129 *
 130 * @if_type:    Interface type
 131 * @devnum:     Device number (0 = first)
 132 * @descp:      Returns block device descriptor on success
 133 * @return 0 on success, -ENODEV if there is no such device and no device
 134 * with a higher device number, -ENOENT if there is no such device but there
 135 * is one with a higher number, or other -ve on other error.
 136 */
 137static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
 138{
 139        bool found_more = false;
 140        struct udevice *dev;
 141        struct uclass *uc;
 142        int ret;
 143
 144        *descp = NULL;
 145        ret = uclass_get(UCLASS_BLK, &uc);
 146        if (ret)
 147                return ret;
 148        uclass_foreach_dev(dev, uc) {
 149                struct blk_desc *desc = dev_get_uclass_platdata(dev);
 150
 151                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 152                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 153                if (desc->if_type == if_type) {
 154                        if (desc->devnum == devnum) {
 155                                ret = device_probe(dev);
 156                                if (ret)
 157                                        return ret;
 158
 159                                *descp = desc;
 160                                return 0;
 161                        } else if (desc->devnum > devnum) {
 162                                found_more = true;
 163                        }
 164                }
 165        }
 166
 167        return found_more ? -ENOENT : -ENODEV;
 168}
 169
 170int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
 171{
 172        struct udevice *dev;
 173        int ret;
 174
 175        ret = blk_get_device(if_type, devnum, &dev);
 176        if (ret)
 177                return ret;
 178
 179        return blk_select_hwpart(dev, hwpart);
 180}
 181
 182int blk_list_part(enum if_type if_type)
 183{
 184        struct blk_desc *desc;
 185        int devnum, ok;
 186        int ret;
 187
 188        for (ok = 0, devnum = 0;; ++devnum) {
 189                ret = get_desc(if_type, devnum, &desc);
 190                if (ret == -ENODEV)
 191                        break;
 192                else if (ret)
 193                        continue;
 194                if (desc->part_type != PART_TYPE_UNKNOWN) {
 195                        ++ok;
 196                        if (devnum)
 197                                putc('\n');
 198                        part_print(desc);
 199                }
 200        }
 201        if (!ok)
 202                return -ENODEV;
 203
 204        return 0;
 205}
 206
 207int blk_print_part_devnum(enum if_type if_type, int devnum)
 208{
 209        struct blk_desc *desc;
 210        int ret;
 211
 212        ret = get_desc(if_type, devnum, &desc);
 213        if (ret)
 214                return ret;
 215        if (desc->type == DEV_TYPE_UNKNOWN)
 216                return -ENOENT;
 217        part_print(desc);
 218
 219        return 0;
 220}
 221
 222void blk_list_devices(enum if_type if_type)
 223{
 224        struct blk_desc *desc;
 225        int ret;
 226        int i;
 227
 228        for (i = 0;; ++i) {
 229                ret = get_desc(if_type, i, &desc);
 230                if (ret == -ENODEV)
 231                        break;
 232                else if (ret)
 233                        continue;
 234                if (desc->type == DEV_TYPE_UNKNOWN)
 235                        continue;  /* list only known devices */
 236                printf("Device %d: ", i);
 237                dev_print(desc);
 238        }
 239}
 240
 241int blk_print_device_num(enum if_type if_type, int devnum)
 242{
 243        struct blk_desc *desc;
 244        int ret;
 245
 246        ret = get_desc(if_type, devnum, &desc);
 247        if (ret)
 248                return ret;
 249        printf("\nIDE device %d: ", devnum);
 250        dev_print(desc);
 251
 252        return 0;
 253}
 254
 255int blk_show_device(enum if_type if_type, int devnum)
 256{
 257        struct blk_desc *desc;
 258        int ret;
 259
 260        printf("\nDevice %d: ", devnum);
 261        ret = get_desc(if_type, devnum, &desc);
 262        if (ret == -ENODEV || ret == -ENOENT) {
 263                printf("unknown device\n");
 264                return -ENODEV;
 265        }
 266        if (ret)
 267                return ret;
 268        dev_print(desc);
 269
 270        if (desc->type == DEV_TYPE_UNKNOWN)
 271                return -ENOENT;
 272
 273        return 0;
 274}
 275
 276ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
 277                      lbaint_t blkcnt, void *buffer)
 278{
 279        struct blk_desc *desc;
 280        ulong n;
 281        int ret;
 282
 283        ret = get_desc(if_type, devnum, &desc);
 284        if (ret)
 285                return ret;
 286        n = blk_dread(desc, start, blkcnt, buffer);
 287        if (IS_ERR_VALUE(n))
 288                return n;
 289
 290        /* flush cache after read */
 291        flush_cache((ulong)buffer, blkcnt * desc->blksz);
 292
 293        return n;
 294}
 295
 296ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
 297                       lbaint_t blkcnt, const void *buffer)
 298{
 299        struct blk_desc *desc;
 300        int ret;
 301
 302        ret = get_desc(if_type, devnum, &desc);
 303        if (ret)
 304                return ret;
 305        return blk_dwrite(desc, start, blkcnt, buffer);
 306}
 307
 308int blk_select_hwpart(struct udevice *dev, int hwpart)
 309{
 310        const struct blk_ops *ops = blk_get_ops(dev);
 311
 312        if (!ops)
 313                return -ENOSYS;
 314        if (!ops->select_hwpart)
 315                return 0;
 316
 317        return ops->select_hwpart(dev, hwpart);
 318}
 319
 320int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
 321{
 322        return blk_select_hwpart(desc->bdev, hwpart);
 323}
 324
 325int blk_first_device(int if_type, struct udevice **devp)
 326{
 327        struct blk_desc *desc;
 328        int ret;
 329
 330        ret = uclass_first_device(UCLASS_BLK, devp);
 331        if (ret)
 332                return ret;
 333        if (!*devp)
 334                return -ENODEV;
 335        do {
 336                desc = dev_get_uclass_platdata(*devp);
 337                if (desc->if_type == if_type)
 338                        return 0;
 339                ret = uclass_next_device(devp);
 340                if (ret)
 341                        return ret;
 342        } while (*devp);
 343
 344        return -ENODEV;
 345}
 346
 347int blk_next_device(struct udevice **devp)
 348{
 349        struct blk_desc *desc;
 350        int ret, if_type;
 351
 352        desc = dev_get_uclass_platdata(*devp);
 353        if_type = desc->if_type;
 354        do {
 355                ret = uclass_next_device(devp);
 356                if (ret)
 357                        return ret;
 358                if (!*devp)
 359                        return -ENODEV;
 360                desc = dev_get_uclass_platdata(*devp);
 361                if (desc->if_type == if_type)
 362                        return 0;
 363        } while (1);
 364}
 365
 366int blk_get_device(int if_type, int devnum, struct udevice **devp)
 367{
 368        struct uclass *uc;
 369        struct udevice *dev;
 370        int ret;
 371
 372        ret = uclass_get(UCLASS_BLK, &uc);
 373        if (ret)
 374                return ret;
 375        uclass_foreach_dev(dev, uc) {
 376                struct blk_desc *desc = dev_get_uclass_platdata(dev);
 377
 378                debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
 379                      if_type, devnum, dev->name, desc->if_type, desc->devnum);
 380                if (desc->if_type == if_type && desc->devnum == devnum) {
 381                        *devp = dev;
 382                        return device_probe(dev);
 383                }
 384        }
 385
 386        return -ENODEV;
 387}
 388
 389unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
 390                        lbaint_t blkcnt, void *buffer)
 391{
 392        struct udevice *dev = block_dev->bdev;
 393        const struct blk_ops *ops = blk_get_ops(dev);
 394        ulong blks_read;
 395
 396        if (!ops->read)
 397                return -ENOSYS;
 398
 399        if (blkcache_read(block_dev->if_type, block_dev->devnum,
 400                          start, blkcnt, block_dev->blksz, buffer))
 401                return blkcnt;
 402        blks_read = ops->read(dev, start, blkcnt, buffer);
 403        if (blks_read == blkcnt)
 404                blkcache_fill(block_dev->if_type, block_dev->devnum,
 405                              start, blkcnt, block_dev->blksz, buffer);
 406
 407        return blks_read;
 408}
 409
 410unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
 411                         lbaint_t blkcnt, const void *buffer)
 412{
 413        struct udevice *dev = block_dev->bdev;
 414        const struct blk_ops *ops = blk_get_ops(dev);
 415
 416        if (!ops->write)
 417                return -ENOSYS;
 418
 419        blkcache_invalidate(block_dev->if_type, block_dev->devnum);
 420        return ops->write(dev, start, blkcnt, buffer);
 421}
 422
 423unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
 424                         lbaint_t blkcnt)
 425{
 426        struct udevice *dev = block_dev->bdev;
 427        const struct blk_ops *ops = blk_get_ops(dev);
 428
 429        if (!ops->erase)
 430                return -ENOSYS;
 431
 432        blkcache_invalidate(block_dev->if_type, block_dev->devnum);
 433        return ops->erase(dev, start, blkcnt);
 434}
 435
 436int blk_prepare_device(struct udevice *dev)
 437{
 438        struct blk_desc *desc = dev_get_uclass_platdata(dev);
 439
 440        part_init(desc);
 441
 442        return 0;
 443}
 444
 445int blk_find_max_devnum(enum if_type if_type)
 446{
 447        struct udevice *dev;
 448        int max_devnum = -ENODEV;
 449        struct uclass *uc;
 450        int ret;
 451
 452        ret = uclass_get(UCLASS_BLK, &uc);
 453        if (ret)
 454                return ret;
 455        uclass_foreach_dev(dev, uc) {
 456                struct blk_desc *desc = dev_get_uclass_platdata(dev);
 457
 458                if (desc->if_type == if_type && desc->devnum > max_devnum)
 459                        max_devnum = desc->devnum;
 460        }
 461
 462        return max_devnum;
 463}
 464
 465int blk_create_device(struct udevice *parent, const char *drv_name,
 466                      const char *name, int if_type, int devnum, int blksz,
 467                      lbaint_t size, struct udevice **devp)
 468{
 469        struct blk_desc *desc;
 470        struct udevice *dev;
 471        int ret;
 472
 473        if (devnum == -1) {
 474                ret = blk_find_max_devnum(if_type);
 475                if (ret == -ENODEV)
 476                        devnum = 0;
 477                else if (ret < 0)
 478                        return ret;
 479                else
 480                        devnum = ret + 1;
 481        }
 482        ret = device_bind_driver(parent, drv_name, name, &dev);
 483        if (ret)
 484                return ret;
 485        desc = dev_get_uclass_platdata(dev);
 486        desc->if_type = if_type;
 487        desc->blksz = blksz;
 488        desc->lba = size / blksz;
 489        desc->part_type = PART_TYPE_UNKNOWN;
 490        desc->bdev = dev;
 491        desc->devnum = devnum;
 492        *devp = dev;
 493
 494        return 0;
 495}
 496
 497int blk_create_devicef(struct udevice *parent, const char *drv_name,
 498                       const char *name, int if_type, int devnum, int blksz,
 499                       lbaint_t size, struct udevice **devp)
 500{
 501        char dev_name[30], *str;
 502        int ret;
 503
 504        snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
 505        str = strdup(dev_name);
 506        if (!str)
 507                return -ENOMEM;
 508
 509        ret = blk_create_device(parent, drv_name, str, if_type, devnum,
 510                                blksz, size, devp);
 511        if (ret) {
 512                free(str);
 513                return ret;
 514        }
 515        device_set_name_alloced(*devp);
 516
 517        return ret;
 518}
 519
 520int blk_unbind_all(int if_type)
 521{
 522        struct uclass *uc;
 523        struct udevice *dev, *next;
 524        int ret;
 525
 526        ret = uclass_get(UCLASS_BLK, &uc);
 527        if (ret)
 528                return ret;
 529        uclass_foreach_dev_safe(dev, next, uc) {
 530                struct blk_desc *desc = dev_get_uclass_platdata(dev);
 531
 532                if (desc->if_type == if_type) {
 533                        ret = device_remove(dev);
 534                        if (ret)
 535                                return ret;
 536                        ret = device_unbind(dev);
 537                        if (ret)
 538                                return ret;
 539                }
 540        }
 541
 542        return 0;
 543}
 544
 545UCLASS_DRIVER(blk) = {
 546        .id             = UCLASS_BLK,
 547        .name           = "blk",
 548        .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
 549};
 550