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