uboot/test/dm/bus.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Google, Inc
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <dm/device-internal.h>
  10#include <dm/test.h>
  11#include <dm/uclass-internal.h>
  12#include <dm/util.h>
  13#include <test/ut.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17struct dm_test_parent_platdata {
  18        int count;
  19        int bind_flag;
  20        int uclass_bind_flag;
  21};
  22
  23enum {
  24        FLAG_CHILD_PROBED       = 10,
  25        FLAG_CHILD_REMOVED      = -7,
  26};
  27
  28static struct dm_test_state *test_state;
  29
  30static int testbus_drv_probe(struct udevice *dev)
  31{
  32        return dm_scan_fdt_dev(dev);
  33}
  34
  35static int testbus_child_post_bind(struct udevice *dev)
  36{
  37        struct dm_test_parent_platdata *plat;
  38
  39        plat = dev_get_parent_platdata(dev);
  40        plat->bind_flag = 1;
  41        plat->uclass_bind_flag = 2;
  42
  43        return 0;
  44}
  45
  46static int testbus_child_pre_probe(struct udevice *dev)
  47{
  48        struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
  49
  50        parent_data->flag += FLAG_CHILD_PROBED;
  51
  52        return 0;
  53}
  54
  55static int testbus_child_pre_probe_uclass(struct udevice *dev)
  56{
  57        struct dm_test_priv *priv = dev_get_priv(dev);
  58
  59        priv->uclass_flag++;
  60
  61        return 0;
  62}
  63
  64static int testbus_child_post_remove(struct udevice *dev)
  65{
  66        struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
  67        struct dm_test_state *dms = test_state;
  68
  69        parent_data->flag += FLAG_CHILD_REMOVED;
  70        if (dms)
  71                dms->removed = dev;
  72
  73        return 0;
  74}
  75
  76static const struct udevice_id testbus_ids[] = {
  77        {
  78                .compatible = "denx,u-boot-test-bus",
  79                .data = DM_TEST_TYPE_FIRST },
  80        { }
  81};
  82
  83U_BOOT_DRIVER(testbus_drv) = {
  84        .name   = "testbus_drv",
  85        .of_match       = testbus_ids,
  86        .id     = UCLASS_TEST_BUS,
  87        .probe  = testbus_drv_probe,
  88        .child_post_bind = testbus_child_post_bind,
  89        .priv_auto_alloc_size = sizeof(struct dm_test_priv),
  90        .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
  91        .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
  92        .per_child_platdata_auto_alloc_size =
  93                        sizeof(struct dm_test_parent_platdata),
  94        .child_pre_probe = testbus_child_pre_probe,
  95        .child_post_remove = testbus_child_post_remove,
  96};
  97
  98UCLASS_DRIVER(testbus) = {
  99        .name           = "testbus",
 100        .id             = UCLASS_TEST_BUS,
 101        .flags          = DM_UC_FLAG_SEQ_ALIAS,
 102        .child_pre_probe = testbus_child_pre_probe_uclass,
 103};
 104
 105/* Test that we can probe for children */
 106static int dm_test_bus_children(struct unit_test_state *uts)
 107{
 108        int num_devices = 6;
 109        struct udevice *bus;
 110        struct uclass *uc;
 111
 112        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 113        ut_asserteq(num_devices, list_count_items(&uc->dev_head));
 114
 115        /* Probe the bus, which should yield 3 more devices */
 116        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 117        num_devices += 3;
 118
 119        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 120        ut_asserteq(num_devices, list_count_items(&uc->dev_head));
 121
 122        ut_assert(!dm_check_devices(uts, num_devices));
 123
 124        return 0;
 125}
 126DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 127
 128/* Test our functions for accessing children */
 129static int dm_test_bus_children_funcs(struct unit_test_state *uts)
 130{
 131        const void *blob = gd->fdt_blob;
 132        struct udevice *bus, *dev;
 133        int node;
 134
 135        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 136
 137        /* device_get_child() */
 138        ut_assertok(device_get_child(bus, 0, &dev));
 139        ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
 140        ut_assertok(device_get_child_by_seq(bus, 5, &dev));
 141        ut_assert(dev->flags & DM_FLAG_ACTIVATED);
 142        ut_asserteq_str("c-test@5", dev->name);
 143
 144        /* Device with sequence number 0 should be accessible */
 145        ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
 146        ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
 147        ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
 148        ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
 149        ut_assertok(device_get_child_by_seq(bus, 0, &dev));
 150        ut_assert(dev->flags & DM_FLAG_ACTIVATED);
 151
 152        /* There is no device with sequence number 2 */
 153        ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
 154        ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
 155        ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
 156
 157        /* Looking for something that is not a child */
 158        node = fdt_path_offset(blob, "/junk");
 159        ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
 160        node = fdt_path_offset(blob, "/d-test");
 161        ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
 162
 163        return 0;
 164}
 165DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 166
 167static int dm_test_bus_children_of_offset(struct unit_test_state *uts)
 168{
 169        const void *blob = gd->fdt_blob;
 170        struct udevice *bus, *dev;
 171        int node;
 172
 173        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 174        ut_assertnonnull(bus);
 175
 176        /* Find a valid child */
 177        node = fdt_path_offset(blob, "/some-bus/c-test@1");
 178        ut_assert(node > 0);
 179        ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
 180        ut_assertnonnull(dev);
 181        ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
 182        ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
 183        ut_assertnonnull(dev);
 184        ut_assert(dev->flags & DM_FLAG_ACTIVATED);
 185
 186        return 0;
 187}
 188DM_TEST(dm_test_bus_children_of_offset,
 189        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
 190
 191/* Test that we can iterate through children */
 192static int dm_test_bus_children_iterators(struct unit_test_state *uts)
 193{
 194        struct udevice *bus, *dev, *child;
 195
 196        /* Walk through the children one by one */
 197        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 198        ut_assertok(device_find_first_child(bus, &dev));
 199        ut_asserteq_str("c-test@5", dev->name);
 200        ut_assertok(device_find_next_child(&dev));
 201        ut_asserteq_str("c-test@0", dev->name);
 202        ut_assertok(device_find_next_child(&dev));
 203        ut_asserteq_str("c-test@1", dev->name);
 204        ut_assertok(device_find_next_child(&dev));
 205        ut_asserteq_ptr(dev, NULL);
 206
 207        /* Move to the next child without using device_find_first_child() */
 208        ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
 209        ut_asserteq_str("c-test@5", dev->name);
 210        ut_assertok(device_find_next_child(&dev));
 211        ut_asserteq_str("c-test@0", dev->name);
 212
 213        /* Try a device with no children */
 214        ut_assertok(device_find_first_child(dev, &child));
 215        ut_asserteq_ptr(child, NULL);
 216
 217        return 0;
 218}
 219DM_TEST(dm_test_bus_children_iterators,
 220        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 221
 222/* Test that the bus can store data about each child */
 223static int test_bus_parent_data(struct unit_test_state *uts)
 224{
 225        struct dm_test_parent_data *parent_data;
 226        struct udevice *bus, *dev;
 227        struct uclass *uc;
 228        int value;
 229
 230        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 231
 232        /* Check that parent data is allocated */
 233        ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
 234        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 235        ut_assertok(device_get_child_by_seq(bus, 0, &dev));
 236        parent_data = dev_get_parent_priv(dev);
 237        ut_assert(NULL != parent_data);
 238
 239        /* Check that it starts at 0 and goes away when device is removed */
 240        parent_data->sum += 5;
 241        ut_asserteq(5, parent_data->sum);
 242        device_remove(dev, DM_REMOVE_NORMAL);
 243        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 244
 245        /* Check that we can do this twice */
 246        ut_assertok(device_get_child_by_seq(bus, 0, &dev));
 247        parent_data = dev_get_parent_priv(dev);
 248        ut_assert(NULL != parent_data);
 249        parent_data->sum += 5;
 250        ut_asserteq(5, parent_data->sum);
 251
 252        /* Add parent data to all children */
 253        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 254        value = 5;
 255        uclass_foreach_dev(dev, uc) {
 256                /* Ignore these if they are not on this bus */
 257                if (dev->parent != bus) {
 258                        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 259                        continue;
 260                }
 261                ut_assertok(device_probe(dev));
 262                parent_data = dev_get_parent_priv(dev);
 263
 264                parent_data->sum = value;
 265                value += 5;
 266        }
 267
 268        /* Check it is still there */
 269        value = 5;
 270        uclass_foreach_dev(dev, uc) {
 271                /* Ignore these if they are not on this bus */
 272                if (dev->parent != bus)
 273                        continue;
 274                parent_data = dev_get_parent_priv(dev);
 275
 276                ut_asserteq(value, parent_data->sum);
 277                value += 5;
 278        }
 279
 280        return 0;
 281}
 282/* Test that the bus can store data about each child */
 283static int dm_test_bus_parent_data(struct unit_test_state *uts)
 284{
 285        return test_bus_parent_data(uts);
 286}
 287DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 288
 289/* As above but the size is controlled by the uclass */
 290static int dm_test_bus_parent_data_uclass(struct unit_test_state *uts)
 291{
 292        struct driver *drv;
 293        struct udevice *bus;
 294        int size;
 295        int ret;
 296
 297        /* Set the driver size to 0 so that the uclass size is used */
 298        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 299        drv = (struct driver *)bus->driver;
 300        size = drv->per_child_auto_alloc_size;
 301        bus->uclass->uc_drv->per_child_auto_alloc_size = size;
 302        drv->per_child_auto_alloc_size = 0;
 303        ret = test_bus_parent_data(uts);
 304        if (ret)
 305                return ret;
 306        bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
 307        drv->per_child_auto_alloc_size = size;
 308
 309        return 0;
 310}
 311DM_TEST(dm_test_bus_parent_data_uclass,
 312        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 313
 314/* Test that the bus ops are called when a child is probed/removed */
 315static int dm_test_bus_parent_ops(struct unit_test_state *uts)
 316{
 317        struct dm_test_parent_data *parent_data;
 318        struct dm_test_state *dms = uts->priv;
 319        struct udevice *bus, *dev;
 320        struct uclass *uc;
 321
 322        test_state = dms;
 323        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 324        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 325
 326        uclass_foreach_dev(dev, uc) {
 327                /* Ignore these if they are not on this bus */
 328                if (dev->parent != bus)
 329                        continue;
 330                ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 331
 332                ut_assertok(device_probe(dev));
 333                parent_data = dev_get_parent_priv(dev);
 334                ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
 335        }
 336
 337        uclass_foreach_dev(dev, uc) {
 338                /* Ignore these if they are not on this bus */
 339                if (dev->parent != bus)
 340                        continue;
 341                parent_data = dev_get_parent_priv(dev);
 342                ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
 343                ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
 344                ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 345                ut_asserteq_ptr(dms->removed, dev);
 346        }
 347        test_state = NULL;
 348
 349        return 0;
 350}
 351DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 352
 353static int test_bus_parent_platdata(struct unit_test_state *uts)
 354{
 355        struct dm_test_parent_platdata *plat;
 356        struct udevice *bus, *dev;
 357        int child_count;
 358
 359        /* Check that the bus has no children */
 360        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 361        device_find_first_child(bus, &dev);
 362        ut_asserteq_ptr(NULL, dev);
 363
 364        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 365
 366        for (device_find_first_child(bus, &dev), child_count = 0;
 367             dev;
 368             device_find_next_child(&dev)) {
 369                /* Check that platform data is allocated */
 370                plat = dev_get_parent_platdata(dev);
 371                ut_assert(plat != NULL);
 372
 373                /*
 374                 * Check that it is not affected by the device being
 375                 * probed/removed
 376                 */
 377                plat->count++;
 378                ut_asserteq(1, plat->count);
 379                device_probe(dev);
 380                device_remove(dev, DM_REMOVE_NORMAL);
 381
 382                ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
 383                ut_asserteq(1, plat->count);
 384                ut_assertok(device_probe(dev));
 385                child_count++;
 386        }
 387        ut_asserteq(3, child_count);
 388
 389        /* Removing the bus should also have no effect (it is still bound) */
 390        device_remove(bus, DM_REMOVE_NORMAL);
 391        for (device_find_first_child(bus, &dev), child_count = 0;
 392             dev;
 393             device_find_next_child(&dev)) {
 394                /* Check that platform data is allocated */
 395                plat = dev_get_parent_platdata(dev);
 396                ut_assert(plat != NULL);
 397                ut_asserteq(1, plat->count);
 398                child_count++;
 399        }
 400        ut_asserteq(3, child_count);
 401
 402        /* Unbind all the children */
 403        do {
 404                device_find_first_child(bus, &dev);
 405                if (dev)
 406                        device_unbind(dev);
 407        } while (dev);
 408
 409        /* Now the child platdata should be removed and re-added */
 410        device_probe(bus);
 411        for (device_find_first_child(bus, &dev), child_count = 0;
 412             dev;
 413             device_find_next_child(&dev)) {
 414                /* Check that platform data is allocated */
 415                plat = dev_get_parent_platdata(dev);
 416                ut_assert(plat != NULL);
 417                ut_asserteq(0, plat->count);
 418                child_count++;
 419        }
 420        ut_asserteq(3, child_count);
 421
 422        return 0;
 423}
 424
 425/* Test that the bus can store platform data about each child */
 426static int dm_test_bus_parent_platdata(struct unit_test_state *uts)
 427{
 428        return test_bus_parent_platdata(uts);
 429}
 430DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 431
 432/* As above but the size is controlled by the uclass */
 433static int dm_test_bus_parent_platdata_uclass(struct unit_test_state *uts)
 434{
 435        struct udevice *bus;
 436        struct driver *drv;
 437        int size;
 438        int ret;
 439
 440        /* Set the driver size to 0 so that the uclass size is used */
 441        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 442        drv = (struct driver *)bus->driver;
 443        size = drv->per_child_platdata_auto_alloc_size;
 444        bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
 445        drv->per_child_platdata_auto_alloc_size = 0;
 446        ret = test_bus_parent_platdata(uts);
 447        if (ret)
 448                return ret;
 449        bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
 450        drv->per_child_platdata_auto_alloc_size = size;
 451
 452        return 0;
 453}
 454DM_TEST(dm_test_bus_parent_platdata_uclass,
 455        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 456
 457/* Test that the child post_bind method is called */
 458static int dm_test_bus_child_post_bind(struct unit_test_state *uts)
 459{
 460        struct dm_test_parent_platdata *plat;
 461        struct udevice *bus, *dev;
 462        int child_count;
 463
 464        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 465        for (device_find_first_child(bus, &dev), child_count = 0;
 466             dev;
 467             device_find_next_child(&dev)) {
 468                /* Check that platform data is allocated */
 469                plat = dev_get_parent_platdata(dev);
 470                ut_assert(plat != NULL);
 471                ut_asserteq(1, plat->bind_flag);
 472                child_count++;
 473        }
 474        ut_asserteq(3, child_count);
 475
 476        return 0;
 477}
 478DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 479
 480/* Test that the child post_bind method is called */
 481static int dm_test_bus_child_post_bind_uclass(struct unit_test_state *uts)
 482{
 483        struct dm_test_parent_platdata *plat;
 484        struct udevice *bus, *dev;
 485        int child_count;
 486
 487        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 488        for (device_find_first_child(bus, &dev), child_count = 0;
 489             dev;
 490             device_find_next_child(&dev)) {
 491                /* Check that platform data is allocated */
 492                plat = dev_get_parent_platdata(dev);
 493                ut_assert(plat != NULL);
 494                ut_asserteq(2, plat->uclass_bind_flag);
 495                child_count++;
 496        }
 497        ut_asserteq(3, child_count);
 498
 499        return 0;
 500}
 501DM_TEST(dm_test_bus_child_post_bind_uclass,
 502        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 503
 504/*
 505 * Test that the bus' uclass' child_pre_probe() is called before the
 506 * device's probe() method
 507 */
 508static int dm_test_bus_child_pre_probe_uclass(struct unit_test_state *uts)
 509{
 510        struct udevice *bus, *dev;
 511        int child_count;
 512
 513        /*
 514         * See testfdt_drv_probe() which effectively checks that the uclass
 515         * flag is set before that method is called
 516         */
 517        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 518        for (device_find_first_child(bus, &dev), child_count = 0;
 519             dev;
 520             device_find_next_child(&dev)) {
 521                struct dm_test_priv *priv = dev_get_priv(dev);
 522
 523                /* Check that things happened in the right order */
 524                ut_asserteq_ptr(NULL, priv);
 525                ut_assertok(device_probe(dev));
 526
 527                priv = dev_get_priv(dev);
 528                ut_assert(priv != NULL);
 529                ut_asserteq(1, priv->uclass_flag);
 530                ut_asserteq(1, priv->uclass_total);
 531                child_count++;
 532        }
 533        ut_asserteq(3, child_count);
 534
 535        return 0;
 536}
 537DM_TEST(dm_test_bus_child_pre_probe_uclass,
 538        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 539