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