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