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        /* Find a valid child */
 164        node = fdt_path_offset(blob, "/some-bus/c-test@1");
 165        ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
 166        ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
 167        ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
 168        ut_assert(dev->flags & DM_FLAG_ACTIVATED);
 169
 170        return 0;
 171}
 172DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 173
 174/* Test that we can iterate through children */
 175static int dm_test_bus_children_iterators(struct unit_test_state *uts)
 176{
 177        struct udevice *bus, *dev, *child;
 178
 179        /* Walk through the children one by one */
 180        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 181        ut_assertok(device_find_first_child(bus, &dev));
 182        ut_asserteq_str("c-test@5", dev->name);
 183        ut_assertok(device_find_next_child(&dev));
 184        ut_asserteq_str("c-test@0", dev->name);
 185        ut_assertok(device_find_next_child(&dev));
 186        ut_asserteq_str("c-test@1", dev->name);
 187        ut_assertok(device_find_next_child(&dev));
 188        ut_asserteq_ptr(dev, NULL);
 189
 190        /* Move to the next child without using device_find_first_child() */
 191        ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
 192        ut_asserteq_str("c-test@5", dev->name);
 193        ut_assertok(device_find_next_child(&dev));
 194        ut_asserteq_str("c-test@0", dev->name);
 195
 196        /* Try a device with no children */
 197        ut_assertok(device_find_first_child(dev, &child));
 198        ut_asserteq_ptr(child, NULL);
 199
 200        return 0;
 201}
 202DM_TEST(dm_test_bus_children_iterators,
 203        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 204
 205/* Test that the bus can store data about each child */
 206static int test_bus_parent_data(struct unit_test_state *uts)
 207{
 208        struct dm_test_parent_data *parent_data;
 209        struct udevice *bus, *dev;
 210        struct uclass *uc;
 211        int value;
 212
 213        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 214
 215        /* Check that parent data is allocated */
 216        ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
 217        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 218        ut_assertok(device_get_child_by_seq(bus, 0, &dev));
 219        parent_data = dev_get_parent_priv(dev);
 220        ut_assert(NULL != parent_data);
 221
 222        /* Check that it starts at 0 and goes away when device is removed */
 223        parent_data->sum += 5;
 224        ut_asserteq(5, parent_data->sum);
 225        device_remove(dev);
 226        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 227
 228        /* Check that we can do this twice */
 229        ut_assertok(device_get_child_by_seq(bus, 0, &dev));
 230        parent_data = dev_get_parent_priv(dev);
 231        ut_assert(NULL != parent_data);
 232        parent_data->sum += 5;
 233        ut_asserteq(5, parent_data->sum);
 234
 235        /* Add parent data to all children */
 236        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 237        value = 5;
 238        uclass_foreach_dev(dev, uc) {
 239                /* Ignore these if they are not on this bus */
 240                if (dev->parent != bus) {
 241                        ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 242                        continue;
 243                }
 244                ut_assertok(device_probe(dev));
 245                parent_data = dev_get_parent_priv(dev);
 246
 247                parent_data->sum = value;
 248                value += 5;
 249        }
 250
 251        /* Check it is still there */
 252        value = 5;
 253        uclass_foreach_dev(dev, uc) {
 254                /* Ignore these if they are not on this bus */
 255                if (dev->parent != bus)
 256                        continue;
 257                parent_data = dev_get_parent_priv(dev);
 258
 259                ut_asserteq(value, parent_data->sum);
 260                value += 5;
 261        }
 262
 263        return 0;
 264}
 265/* Test that the bus can store data about each child */
 266static int dm_test_bus_parent_data(struct unit_test_state *uts)
 267{
 268        return test_bus_parent_data(uts);
 269}
 270DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 271
 272/* As above but the size is controlled by the uclass */
 273static int dm_test_bus_parent_data_uclass(struct unit_test_state *uts)
 274{
 275        struct driver *drv;
 276        struct udevice *bus;
 277        int size;
 278        int ret;
 279
 280        /* Set the driver size to 0 so that the uclass size is used */
 281        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 282        drv = (struct driver *)bus->driver;
 283        size = drv->per_child_auto_alloc_size;
 284        bus->uclass->uc_drv->per_child_auto_alloc_size = size;
 285        drv->per_child_auto_alloc_size = 0;
 286        ret = test_bus_parent_data(uts);
 287        if (ret)
 288                return ret;
 289        bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
 290        drv->per_child_auto_alloc_size = size;
 291
 292        return 0;
 293}
 294DM_TEST(dm_test_bus_parent_data_uclass,
 295        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 296
 297/* Test that the bus ops are called when a child is probed/removed */
 298static int dm_test_bus_parent_ops(struct unit_test_state *uts)
 299{
 300        struct dm_test_parent_data *parent_data;
 301        struct dm_test_state *dms = uts->priv;
 302        struct udevice *bus, *dev;
 303        struct uclass *uc;
 304
 305        test_state = dms;
 306        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 307        ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
 308
 309        uclass_foreach_dev(dev, uc) {
 310                /* Ignore these if they are not on this bus */
 311                if (dev->parent != bus)
 312                        continue;
 313                ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 314
 315                ut_assertok(device_probe(dev));
 316                parent_data = dev_get_parent_priv(dev);
 317                ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
 318        }
 319
 320        uclass_foreach_dev(dev, uc) {
 321                /* Ignore these if they are not on this bus */
 322                if (dev->parent != bus)
 323                        continue;
 324                parent_data = dev_get_parent_priv(dev);
 325                ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
 326                ut_assertok(device_remove(dev));
 327                ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
 328                ut_asserteq_ptr(dms->removed, dev);
 329        }
 330        test_state = NULL;
 331
 332        return 0;
 333}
 334DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 335
 336static int test_bus_parent_platdata(struct unit_test_state *uts)
 337{
 338        struct dm_test_parent_platdata *plat;
 339        struct udevice *bus, *dev;
 340        int child_count;
 341
 342        /* Check that the bus has no children */
 343        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 344        device_find_first_child(bus, &dev);
 345        ut_asserteq_ptr(NULL, dev);
 346
 347        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 348
 349        for (device_find_first_child(bus, &dev), child_count = 0;
 350             dev;
 351             device_find_next_child(&dev)) {
 352                /* Check that platform data is allocated */
 353                plat = dev_get_parent_platdata(dev);
 354                ut_assert(plat != NULL);
 355
 356                /*
 357                 * Check that it is not affected by the device being
 358                 * probed/removed
 359                 */
 360                plat->count++;
 361                ut_asserteq(1, plat->count);
 362                device_probe(dev);
 363                device_remove(dev);
 364
 365                ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
 366                ut_asserteq(1, plat->count);
 367                ut_assertok(device_probe(dev));
 368                child_count++;
 369        }
 370        ut_asserteq(3, child_count);
 371
 372        /* Removing the bus should also have no effect (it is still bound) */
 373        device_remove(bus);
 374        for (device_find_first_child(bus, &dev), child_count = 0;
 375             dev;
 376             device_find_next_child(&dev)) {
 377                /* Check that platform data is allocated */
 378                plat = dev_get_parent_platdata(dev);
 379                ut_assert(plat != NULL);
 380                ut_asserteq(1, plat->count);
 381                child_count++;
 382        }
 383        ut_asserteq(3, child_count);
 384
 385        /* Unbind all the children */
 386        do {
 387                device_find_first_child(bus, &dev);
 388                if (dev)
 389                        device_unbind(dev);
 390        } while (dev);
 391
 392        /* Now the child platdata should be removed and re-added */
 393        device_probe(bus);
 394        for (device_find_first_child(bus, &dev), child_count = 0;
 395             dev;
 396             device_find_next_child(&dev)) {
 397                /* Check that platform data is allocated */
 398                plat = dev_get_parent_platdata(dev);
 399                ut_assert(plat != NULL);
 400                ut_asserteq(0, plat->count);
 401                child_count++;
 402        }
 403        ut_asserteq(3, child_count);
 404
 405        return 0;
 406}
 407
 408/* Test that the bus can store platform data about each child */
 409static int dm_test_bus_parent_platdata(struct unit_test_state *uts)
 410{
 411        return test_bus_parent_platdata(uts);
 412}
 413DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 414
 415/* As above but the size is controlled by the uclass */
 416static int dm_test_bus_parent_platdata_uclass(struct unit_test_state *uts)
 417{
 418        struct udevice *bus;
 419        struct driver *drv;
 420        int size;
 421        int ret;
 422
 423        /* Set the driver size to 0 so that the uclass size is used */
 424        ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
 425        drv = (struct driver *)bus->driver;
 426        size = drv->per_child_platdata_auto_alloc_size;
 427        bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
 428        drv->per_child_platdata_auto_alloc_size = 0;
 429        ret = test_bus_parent_platdata(uts);
 430        if (ret)
 431                return ret;
 432        bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
 433        drv->per_child_platdata_auto_alloc_size = size;
 434
 435        return 0;
 436}
 437DM_TEST(dm_test_bus_parent_platdata_uclass,
 438        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 439
 440/* Test that the child post_bind method is called */
 441static int dm_test_bus_child_post_bind(struct unit_test_state *uts)
 442{
 443        struct dm_test_parent_platdata *plat;
 444        struct udevice *bus, *dev;
 445        int child_count;
 446
 447        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 448        for (device_find_first_child(bus, &dev), child_count = 0;
 449             dev;
 450             device_find_next_child(&dev)) {
 451                /* Check that platform data is allocated */
 452                plat = dev_get_parent_platdata(dev);
 453                ut_assert(plat != NULL);
 454                ut_asserteq(1, plat->bind_flag);
 455                child_count++;
 456        }
 457        ut_asserteq(3, child_count);
 458
 459        return 0;
 460}
 461DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 462
 463/* Test that the child post_bind method is called */
 464static int dm_test_bus_child_post_bind_uclass(struct unit_test_state *uts)
 465{
 466        struct dm_test_parent_platdata *plat;
 467        struct udevice *bus, *dev;
 468        int child_count;
 469
 470        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 471        for (device_find_first_child(bus, &dev), child_count = 0;
 472             dev;
 473             device_find_next_child(&dev)) {
 474                /* Check that platform data is allocated */
 475                plat = dev_get_parent_platdata(dev);
 476                ut_assert(plat != NULL);
 477                ut_asserteq(2, plat->uclass_bind_flag);
 478                child_count++;
 479        }
 480        ut_asserteq(3, child_count);
 481
 482        return 0;
 483}
 484DM_TEST(dm_test_bus_child_post_bind_uclass,
 485        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 486
 487/*
 488 * Test that the bus' uclass' child_pre_probe() is called before the
 489 * device's probe() method
 490 */
 491static int dm_test_bus_child_pre_probe_uclass(struct unit_test_state *uts)
 492{
 493        struct udevice *bus, *dev;
 494        int child_count;
 495
 496        /*
 497         * See testfdt_drv_probe() which effectively checks that the uclass
 498         * flag is set before that method is called
 499         */
 500        ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 501        for (device_find_first_child(bus, &dev), child_count = 0;
 502             dev;
 503             device_find_next_child(&dev)) {
 504                struct dm_test_priv *priv = dev_get_priv(dev);
 505
 506                /* Check that things happened in the right order */
 507                ut_asserteq_ptr(NULL, priv);
 508                ut_assertok(device_probe(dev));
 509
 510                priv = dev_get_priv(dev);
 511                ut_assert(priv != NULL);
 512                ut_asserteq(1, priv->uclass_flag);
 513                ut_asserteq(1, priv->uclass_total);
 514                child_count++;
 515        }
 516        ut_asserteq(3, child_count);
 517
 518        return 0;
 519}
 520DM_TEST(dm_test_bus_child_pre_probe_uclass,
 521        DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 522