linux/drivers/bus/mips_cdmm.c
<<
>>
Prefs
   1/*
   2 * Bus driver for MIPS Common Device Memory Map (CDMM).
   3 *
   4 * Copyright (C) 2014-2015 Imagination Technologies Ltd.
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License.  See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 */
  10
  11#include <linux/atomic.h>
  12#include <linux/err.h>
  13#include <linux/cpu.h>
  14#include <linux/cpumask.h>
  15#include <linux/io.h>
  16#include <linux/of_address.h>
  17#include <linux/of.h>
  18#include <linux/platform_device.h>
  19#include <linux/slab.h>
  20#include <linux/smp.h>
  21#include <asm/cdmm.h>
  22#include <asm/hazards.h>
  23#include <asm/mipsregs.h>
  24
  25/* Access control and status register fields */
  26#define CDMM_ACSR_DEVTYPE_SHIFT 24
  27#define CDMM_ACSR_DEVTYPE       (255ul << CDMM_ACSR_DEVTYPE_SHIFT)
  28#define CDMM_ACSR_DEVSIZE_SHIFT 16
  29#define CDMM_ACSR_DEVSIZE       (31ul << CDMM_ACSR_DEVSIZE_SHIFT)
  30#define CDMM_ACSR_DEVREV_SHIFT  12
  31#define CDMM_ACSR_DEVREV        (15ul << CDMM_ACSR_DEVREV_SHIFT)
  32#define CDMM_ACSR_UW            (1ul << 3)
  33#define CDMM_ACSR_UR            (1ul << 2)
  34#define CDMM_ACSR_SW            (1ul << 1)
  35#define CDMM_ACSR_SR            (1ul << 0)
  36
  37/* Each block of device registers is 64 bytes */
  38#define CDMM_DRB_SIZE           64
  39
  40#define to_mips_cdmm_driver(d)  container_of(d, struct mips_cdmm_driver, drv)
  41
  42/* Default physical base address */
  43static phys_addr_t mips_cdmm_default_base;
  44
  45/* Bus operations */
  46
  47static const struct mips_cdmm_device_id *
  48mips_cdmm_lookup(const struct mips_cdmm_device_id *table,
  49                 struct mips_cdmm_device *dev)
  50{
  51        int ret = 0;
  52
  53        for (; table->type; ++table) {
  54                ret = (dev->type == table->type);
  55                if (ret)
  56                        break;
  57        }
  58
  59        return ret ? table : NULL;
  60}
  61
  62static int mips_cdmm_match(struct device *dev, struct device_driver *drv)
  63{
  64        struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
  65        struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(drv);
  66
  67        return mips_cdmm_lookup(cdrv->id_table, cdev) != NULL;
  68}
  69
  70static int mips_cdmm_uevent(struct device *dev, struct kobj_uevent_env *env)
  71{
  72        struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
  73        int retval = 0;
  74
  75        retval = add_uevent_var(env, "CDMM_CPU=%u", cdev->cpu);
  76        if (retval)
  77                return retval;
  78
  79        retval = add_uevent_var(env, "CDMM_TYPE=0x%02x", cdev->type);
  80        if (retval)
  81                return retval;
  82
  83        retval = add_uevent_var(env, "CDMM_REV=%u", cdev->rev);
  84        if (retval)
  85                return retval;
  86
  87        retval = add_uevent_var(env, "MODALIAS=mipscdmm:t%02X", cdev->type);
  88        return retval;
  89}
  90
  91/* Device attributes */
  92
  93#define CDMM_ATTR(name, fmt, arg...)                                    \
  94static ssize_t name##_show(struct device *_dev,                         \
  95                           struct device_attribute *attr, char *buf)    \
  96{                                                                       \
  97        struct mips_cdmm_device *dev = to_mips_cdmm_device(_dev);       \
  98        return sprintf(buf, fmt, arg);                                  \
  99}                                                                       \
 100static DEVICE_ATTR_RO(name);
 101
 102CDMM_ATTR(cpu, "%u\n", dev->cpu);
 103CDMM_ATTR(type, "0x%02x\n", dev->type);
 104CDMM_ATTR(revision, "%u\n", dev->rev);
 105CDMM_ATTR(modalias, "mipscdmm:t%02X\n", dev->type);
 106CDMM_ATTR(resource, "\t%016llx\t%016llx\t%016lx\n",
 107          (unsigned long long)dev->res.start,
 108          (unsigned long long)dev->res.end,
 109          dev->res.flags);
 110
 111static struct attribute *mips_cdmm_dev_attrs[] = {
 112        &dev_attr_cpu.attr,
 113        &dev_attr_type.attr,
 114        &dev_attr_revision.attr,
 115        &dev_attr_modalias.attr,
 116        &dev_attr_resource.attr,
 117        NULL,
 118};
 119ATTRIBUTE_GROUPS(mips_cdmm_dev);
 120
 121struct bus_type mips_cdmm_bustype = {
 122        .name           = "cdmm",
 123        .dev_groups     = mips_cdmm_dev_groups,
 124        .match          = mips_cdmm_match,
 125        .uevent         = mips_cdmm_uevent,
 126};
 127EXPORT_SYMBOL_GPL(mips_cdmm_bustype);
 128
 129/*
 130 * Standard driver callback helpers.
 131 *
 132 * All the CDMM driver callbacks need to be executed on the appropriate CPU from
 133 * workqueues. For the standard driver callbacks we need a work function
 134 * (mips_cdmm_{void,int}_work()) to do the actual call from the right CPU, and a
 135 * wrapper function (generated with BUILD_PERCPU_HELPER) to arrange for the work
 136 * function to be called on that CPU.
 137 */
 138
 139/**
 140 * struct mips_cdmm_work_dev - Data for per-device call work.
 141 * @fn:         CDMM driver callback function to call for the device.
 142 * @dev:        CDMM device to pass to @fn.
 143 */
 144struct mips_cdmm_work_dev {
 145        void                    *fn;
 146        struct mips_cdmm_device *dev;
 147};
 148
 149/**
 150 * mips_cdmm_void_work() - Call a void returning CDMM driver callback.
 151 * @data:       struct mips_cdmm_work_dev pointer.
 152 *
 153 * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
 154 * function which doesn't return a value.
 155 */
 156static long mips_cdmm_void_work(void *data)
 157{
 158        struct mips_cdmm_work_dev *work = data;
 159        void (*fn)(struct mips_cdmm_device *) = work->fn;
 160
 161        fn(work->dev);
 162        return 0;
 163}
 164
 165/**
 166 * mips_cdmm_int_work() - Call an int returning CDMM driver callback.
 167 * @data:       struct mips_cdmm_work_dev pointer.
 168 *
 169 * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
 170 * function which returns an int.
 171 */
 172static long mips_cdmm_int_work(void *data)
 173{
 174        struct mips_cdmm_work_dev *work = data;
 175        int (*fn)(struct mips_cdmm_device *) = work->fn;
 176
 177        return fn(work->dev);
 178}
 179
 180#define _BUILD_RET_void
 181#define _BUILD_RET_int  return
 182
 183/**
 184 * BUILD_PERCPU_HELPER() - Helper to call a CDMM driver callback on right CPU.
 185 * @_ret:       Return type (void or int).
 186 * @_name:      Name of CDMM driver callback function.
 187 *
 188 * Generates a specific device callback function to call a CDMM driver callback
 189 * function on the appropriate CPU for the device, and if applicable return the
 190 * result.
 191 */
 192#define BUILD_PERCPU_HELPER(_ret, _name)                                \
 193static _ret mips_cdmm_##_name(struct device *dev)                       \
 194{                                                                       \
 195        struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);       \
 196        struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(dev->driver); \
 197        struct mips_cdmm_work_dev work = {                              \
 198                .fn     = cdrv->_name,                                  \
 199                .dev    = cdev,                                         \
 200        };                                                              \
 201                                                                        \
 202        _BUILD_RET_##_ret work_on_cpu(cdev->cpu,                        \
 203                                      mips_cdmm_##_ret##_work, &work);  \
 204}
 205
 206/* Driver callback functions */
 207BUILD_PERCPU_HELPER(int, probe)     /* int mips_cdmm_probe(struct device) */
 208BUILD_PERCPU_HELPER(int, remove)    /* int mips_cdmm_remove(struct device) */
 209BUILD_PERCPU_HELPER(void, shutdown) /* void mips_cdmm_shutdown(struct device) */
 210
 211
 212/* Driver registration */
 213
 214/**
 215 * mips_cdmm_driver_register() - Register a CDMM driver.
 216 * @drv:        CDMM driver information.
 217 *
 218 * Register a CDMM driver with the CDMM subsystem. The driver will be informed
 219 * of matching devices which are discovered.
 220 *
 221 * Returns:     0 on success.
 222 */
 223int mips_cdmm_driver_register(struct mips_cdmm_driver *drv)
 224{
 225        drv->drv.bus = &mips_cdmm_bustype;
 226
 227        if (drv->probe)
 228                drv->drv.probe = mips_cdmm_probe;
 229        if (drv->remove)
 230                drv->drv.remove = mips_cdmm_remove;
 231        if (drv->shutdown)
 232                drv->drv.shutdown = mips_cdmm_shutdown;
 233
 234        return driver_register(&drv->drv);
 235}
 236EXPORT_SYMBOL_GPL(mips_cdmm_driver_register);
 237
 238/**
 239 * mips_cdmm_driver_unregister() - Unregister a CDMM driver.
 240 * @drv:        CDMM driver information.
 241 *
 242 * Unregister a CDMM driver from the CDMM subsystem.
 243 */
 244void mips_cdmm_driver_unregister(struct mips_cdmm_driver *drv)
 245{
 246        driver_unregister(&drv->drv);
 247}
 248EXPORT_SYMBOL_GPL(mips_cdmm_driver_unregister);
 249
 250
 251/* CDMM initialisation and bus discovery */
 252
 253/**
 254 * struct mips_cdmm_bus - Info about CDMM bus.
 255 * @phys:               Physical address at which it is mapped.
 256 * @regs:               Virtual address where registers can be accessed.
 257 * @drbs:               Total number of DRBs.
 258 * @drbs_reserved:      Number of DRBs reserved.
 259 * @discovered:         Whether the devices on the bus have been discovered yet.
 260 * @offline:            Whether the CDMM bus is going offline (or very early
 261 *                      coming back online), in which case it should be
 262 *                      reconfigured each time.
 263 */
 264struct mips_cdmm_bus {
 265        phys_addr_t      phys;
 266        void __iomem    *regs;
 267        unsigned int     drbs;
 268        unsigned int     drbs_reserved;
 269        bool             discovered;
 270        bool             offline;
 271};
 272
 273static struct mips_cdmm_bus mips_cdmm_boot_bus;
 274static DEFINE_PER_CPU(struct mips_cdmm_bus *, mips_cdmm_buses);
 275static atomic_t mips_cdmm_next_id = ATOMIC_INIT(-1);
 276
 277/**
 278 * mips_cdmm_get_bus() - Get the per-CPU CDMM bus information.
 279 *
 280 * Get information about the per-CPU CDMM bus, if the bus is present.
 281 *
 282 * The caller must prevent migration to another CPU, either by disabling
 283 * pre-emption or by running from a pinned kernel thread.
 284 *
 285 * Returns:     Pointer to CDMM bus information for the current CPU.
 286 *              May return ERR_PTR(-errno) in case of error, so check with
 287 *              IS_ERR().
 288 */
 289static struct mips_cdmm_bus *mips_cdmm_get_bus(void)
 290{
 291        struct mips_cdmm_bus *bus, **bus_p;
 292        unsigned long flags;
 293        unsigned int cpu;
 294
 295        if (!cpu_has_cdmm)
 296                return ERR_PTR(-ENODEV);
 297
 298        cpu = smp_processor_id();
 299        /* Avoid early use of per-cpu primitives before initialised */
 300        if (cpu == 0)
 301                return &mips_cdmm_boot_bus;
 302
 303        /* Get bus pointer */
 304        bus_p = per_cpu_ptr(&mips_cdmm_buses, cpu);
 305        local_irq_save(flags);
 306        bus = *bus_p;
 307        /* Attempt allocation if NULL */
 308        if (unlikely(!bus)) {
 309                bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
 310                if (unlikely(!bus))
 311                        bus = ERR_PTR(-ENOMEM);
 312                else
 313                        *bus_p = bus;
 314        }
 315        local_irq_restore(flags);
 316        return bus;
 317}
 318
 319/**
 320 * mips_cdmm_cur_base() - Find current physical base address of CDMM region.
 321 *
 322 * Returns:     Physical base address of CDMM region according to cdmmbase CP0
 323 *              register, or 0 if the CDMM region is disabled.
 324 */
 325static phys_addr_t mips_cdmm_cur_base(void)
 326{
 327        unsigned long cdmmbase = read_c0_cdmmbase();
 328
 329        if (!(cdmmbase & MIPS_CDMMBASE_EN))
 330                return 0;
 331
 332        return (cdmmbase >> MIPS_CDMMBASE_ADDR_SHIFT)
 333                << MIPS_CDMMBASE_ADDR_START;
 334}
 335
 336/**
 337 * mips_cdmm_phys_base() - Choose a physical base address for CDMM region.
 338 *
 339 * Picking a suitable physical address at which to map the CDMM region is
 340 * platform specific, so this weak function can be overridden by platform
 341 * code to pick a suitable value if none is configured by the bootloader.
 342 * By default this method tries to find a CDMM-specific node in the system
 343 * dtb. Note that this won't work for early serial console.
 344 */
 345phys_addr_t __weak mips_cdmm_phys_base(void)
 346{
 347        struct device_node *np;
 348        struct resource res;
 349        int err;
 350
 351        np = of_find_compatible_node(NULL, NULL, "mti,mips-cdmm");
 352        if (np) {
 353                err = of_address_to_resource(np, 0, &res);
 354                if (!err)
 355                        return res.start;
 356        }
 357
 358        return 0;
 359}
 360
 361/**
 362 * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable.
 363 * @bus:        Pointer to bus information for current CPU.
 364 *              IS_ERR(bus) is checked, so no need for caller to check.
 365 *
 366 * The caller must prevent migration to another CPU, either by disabling
 367 * pre-emption or by running from a pinned kernel thread.
 368 *
 369 * Returns      0 on success, -errno on failure.
 370 */
 371static int mips_cdmm_setup(struct mips_cdmm_bus *bus)
 372{
 373        unsigned long cdmmbase, flags;
 374        int ret = 0;
 375
 376        if (IS_ERR(bus))
 377                return PTR_ERR(bus);
 378
 379        local_irq_save(flags);
 380        /* Don't set up bus a second time unless marked offline */
 381        if (bus->offline) {
 382                /* If CDMM region is still set up, nothing to do */
 383                if (bus->phys == mips_cdmm_cur_base())
 384                        goto out;
 385                /*
 386                 * The CDMM region isn't set up as expected, so it needs
 387                 * reconfiguring, but then we can stop checking it.
 388                 */
 389                bus->offline = false;
 390        } else if (bus->phys > 1) {
 391                goto out;
 392        }
 393
 394        /* If the CDMM region is already configured, inherit that setup */
 395        if (!bus->phys)
 396                bus->phys = mips_cdmm_cur_base();
 397        /* Otherwise, ask platform code for suggestions */
 398        if (!bus->phys)
 399                bus->phys = mips_cdmm_phys_base();
 400        /* Otherwise, copy what other CPUs have done */
 401        if (!bus->phys)
 402                bus->phys = mips_cdmm_default_base;
 403        /* Otherwise, complain once */
 404        if (!bus->phys) {
 405                bus->phys = 1;
 406                /*
 407                 * If you hit this, either your bootloader needs to set up the
 408                 * CDMM on the boot CPU, or else you need to implement
 409                 * mips_cdmm_phys_base() for your platform (see asm/cdmm.h).
 410                 */
 411                pr_err("cdmm%u: Failed to choose a physical base\n",
 412                       smp_processor_id());
 413        }
 414        /* Already complained? */
 415        if (bus->phys == 1) {
 416                ret = -ENOMEM;
 417                goto out;
 418        }
 419        /* Record our success for other CPUs to copy */
 420        mips_cdmm_default_base = bus->phys;
 421
 422        pr_debug("cdmm%u: Enabling CDMM region at %pa\n",
 423                 smp_processor_id(), &bus->phys);
 424
 425        /* Enable CDMM */
 426        cdmmbase = read_c0_cdmmbase();
 427        cdmmbase &= (1ul << MIPS_CDMMBASE_ADDR_SHIFT) - 1;
 428        cdmmbase |= (bus->phys >> MIPS_CDMMBASE_ADDR_START)
 429                        << MIPS_CDMMBASE_ADDR_SHIFT;
 430        cdmmbase |= MIPS_CDMMBASE_EN;
 431        write_c0_cdmmbase(cdmmbase);
 432        tlbw_use_hazard();
 433
 434        bus->regs = (void __iomem *)CKSEG1ADDR(bus->phys);
 435        bus->drbs = 1 + ((cdmmbase & MIPS_CDMMBASE_SIZE) >>
 436                         MIPS_CDMMBASE_SIZE_SHIFT);
 437        bus->drbs_reserved = !!(cdmmbase & MIPS_CDMMBASE_CI);
 438
 439out:
 440        local_irq_restore(flags);
 441        return ret;
 442}
 443
 444/**
 445 * mips_cdmm_early_probe() - Minimally probe for a specific device on CDMM.
 446 * @dev_type:   CDMM type code to look for.
 447 *
 448 * Minimally configure the in-CPU Common Device Memory Map (CDMM) and look for a
 449 * specific device. This can be used to find a device very early in boot for
 450 * example to configure an early FDC console device.
 451 *
 452 * The caller must prevent migration to another CPU, either by disabling
 453 * pre-emption or by running from a pinned kernel thread.
 454 *
 455 * Returns:     MMIO pointer to device memory. The caller can read the ACSR
 456 *              register to find more information about the device (such as the
 457 *              version number or the number of blocks).
 458 *              May return IOMEM_ERR_PTR(-errno) in case of error, so check with
 459 *              IS_ERR().
 460 */
 461void __iomem *mips_cdmm_early_probe(unsigned int dev_type)
 462{
 463        struct mips_cdmm_bus *bus;
 464        void __iomem *cdmm;
 465        u32 acsr;
 466        unsigned int drb, type, size;
 467        int err;
 468
 469        if (WARN_ON(!dev_type))
 470                return IOMEM_ERR_PTR(-ENODEV);
 471
 472        bus = mips_cdmm_get_bus();
 473        err = mips_cdmm_setup(bus);
 474        if (err)
 475                return IOMEM_ERR_PTR(err);
 476
 477        /* Skip the first block if it's reserved for more registers */
 478        drb = bus->drbs_reserved;
 479        cdmm = bus->regs;
 480
 481        /* Look for a specific device type */
 482        for (; drb < bus->drbs; drb += size + 1) {
 483                acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
 484                type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
 485                if (type == dev_type)
 486                        return cdmm + drb * CDMM_DRB_SIZE;
 487                size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
 488        }
 489
 490        return IOMEM_ERR_PTR(-ENODEV);
 491}
 492EXPORT_SYMBOL_GPL(mips_cdmm_early_probe);
 493
 494/**
 495 * mips_cdmm_release() - Release a removed CDMM device.
 496 * @dev:        Device object
 497 *
 498 * Clean up the struct mips_cdmm_device for an unused CDMM device. This is
 499 * called automatically by the driver core when a device is removed.
 500 */
 501static void mips_cdmm_release(struct device *dev)
 502{
 503        struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
 504
 505        kfree(cdev);
 506}
 507
 508/**
 509 * mips_cdmm_bus_discover() - Discover the devices on the CDMM bus.
 510 * @bus:        CDMM bus information, must already be set up.
 511 */
 512static void mips_cdmm_bus_discover(struct mips_cdmm_bus *bus)
 513{
 514        void __iomem *cdmm;
 515        u32 acsr;
 516        unsigned int drb, type, size, rev;
 517        struct mips_cdmm_device *dev;
 518        unsigned int cpu = smp_processor_id();
 519        int ret = 0;
 520        int id = 0;
 521
 522        /* Skip the first block if it's reserved for more registers */
 523        drb = bus->drbs_reserved;
 524        cdmm = bus->regs;
 525
 526        /* Discover devices */
 527        bus->discovered = true;
 528        pr_info("cdmm%u discovery (%u blocks)\n", cpu, bus->drbs);
 529        for (; drb < bus->drbs; drb += size + 1) {
 530                acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
 531                type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
 532                size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
 533                rev  = (acsr & CDMM_ACSR_DEVREV)  >> CDMM_ACSR_DEVREV_SHIFT;
 534
 535                if (!type)
 536                        continue;
 537
 538                pr_info("cdmm%u-%u: @%u (%#x..%#x), type 0x%02x, rev %u\n",
 539                        cpu, id, drb, drb * CDMM_DRB_SIZE,
 540                        (drb + size + 1) * CDMM_DRB_SIZE - 1,
 541                        type, rev);
 542
 543                dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 544                if (!dev)
 545                        break;
 546
 547                dev->cpu = cpu;
 548                dev->res.start = bus->phys + drb * CDMM_DRB_SIZE;
 549                dev->res.end = bus->phys +
 550                                (drb + size + 1) * CDMM_DRB_SIZE - 1;
 551                dev->res.flags = IORESOURCE_MEM;
 552                dev->type = type;
 553                dev->rev = rev;
 554                dev->dev.parent = get_cpu_device(cpu);
 555                dev->dev.bus = &mips_cdmm_bustype;
 556                dev->dev.id = atomic_inc_return(&mips_cdmm_next_id);
 557                dev->dev.release = mips_cdmm_release;
 558
 559                dev_set_name(&dev->dev, "cdmm%u-%u", cpu, id);
 560                ++id;
 561                ret = device_register(&dev->dev);
 562                if (ret)
 563                        put_device(&dev->dev);
 564        }
 565}
 566
 567
 568/*
 569 * CPU hotplug and initialisation
 570 *
 571 * All the CDMM driver callbacks need to be executed on the appropriate CPU from
 572 * workqueues. For the CPU callbacks, they need to be called for all devices on
 573 * that CPU, so the work function calls bus_for_each_dev, using a helper
 574 * (generated with BUILD_PERDEV_HELPER) to call the driver callback if the
 575 * device's CPU matches.
 576 */
 577
 578/**
 579 * BUILD_PERDEV_HELPER() - Helper to call a CDMM driver callback if CPU matches.
 580 * @_name:      Name of CDMM driver callback function.
 581 *
 582 * Generates a bus_for_each_dev callback function to call a specific CDMM driver
 583 * callback function for the device if the device's CPU matches that pointed to
 584 * by the data argument.
 585 *
 586 * This is used for informing drivers for all devices on a given CPU of some
 587 * event (such as the CPU going online/offline).
 588 *
 589 * It is expected to already be called from the appropriate CPU.
 590 */
 591#define BUILD_PERDEV_HELPER(_name)                                      \
 592static int mips_cdmm_##_name##_helper(struct device *dev, void *data)   \
 593{                                                                       \
 594        struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);       \
 595        struct mips_cdmm_driver *cdrv;                                  \
 596        unsigned int cpu = *(unsigned int *)data;                       \
 597                                                                        \
 598        if (cdev->cpu != cpu || !dev->driver)                           \
 599                return 0;                                               \
 600                                                                        \
 601        cdrv = to_mips_cdmm_driver(dev->driver);                        \
 602        if (!cdrv->_name)                                               \
 603                return 0;                                               \
 604        return cdrv->_name(cdev);                                       \
 605}
 606
 607/* bus_for_each_dev callback helper functions */
 608BUILD_PERDEV_HELPER(cpu_down)       /* int mips_cdmm_cpu_down_helper(...) */
 609BUILD_PERDEV_HELPER(cpu_up)         /* int mips_cdmm_cpu_up_helper(...) */
 610
 611/**
 612 * mips_cdmm_cpu_down_prep() - Callback for CPUHP DOWN_PREP:
 613 *                             Tear down the CDMM bus.
 614 * @cpu:        unsigned int CPU number.
 615 *
 616 * This function is executed on the hotplugged CPU and calls the CDMM
 617 * driver cpu_down callback for all devices on that CPU.
 618 */
 619static int mips_cdmm_cpu_down_prep(unsigned int cpu)
 620{
 621        struct mips_cdmm_bus *bus;
 622        long ret;
 623
 624        /* Inform all the devices on the bus */
 625        ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
 626                               mips_cdmm_cpu_down_helper);
 627
 628        /*
 629         * While bus is offline, each use of it should reconfigure it just in
 630         * case it is first use when coming back online again.
 631         */
 632        bus = mips_cdmm_get_bus();
 633        if (!IS_ERR(bus))
 634                bus->offline = true;
 635
 636        return ret;
 637}
 638
 639/**
 640 * mips_cdmm_cpu_online() - Callback for CPUHP ONLINE: Bring up the CDMM bus.
 641 * @cpu:        unsigned int CPU number.
 642 *
 643 * This work_on_cpu callback function is executed on a given CPU to discover
 644 * CDMM devices on that CPU, or to call the CDMM driver cpu_up callback for all
 645 * devices already discovered on that CPU.
 646 *
 647 * It is used as work_on_cpu callback function during
 648 * initialisation. When CPUs are brought online the function is
 649 * invoked directly on the hotplugged CPU.
 650 */
 651static int mips_cdmm_cpu_online(unsigned int cpu)
 652{
 653        struct mips_cdmm_bus *bus;
 654        long ret;
 655
 656        bus = mips_cdmm_get_bus();
 657        ret = mips_cdmm_setup(bus);
 658        if (ret)
 659                return ret;
 660
 661        /* Bus now set up, so we can drop the offline flag if still set */
 662        bus->offline = false;
 663
 664        if (!bus->discovered)
 665                mips_cdmm_bus_discover(bus);
 666        else
 667                /* Inform all the devices on the bus */
 668                ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
 669                                       mips_cdmm_cpu_up_helper);
 670
 671        return ret;
 672}
 673
 674/**
 675 * mips_cdmm_init() - Initialise CDMM bus.
 676 *
 677 * Initialise CDMM bus, discover CDMM devices for online CPUs, and arrange for
 678 * hotplug notifications so the CDMM drivers can be kept up to date.
 679 */
 680static int __init mips_cdmm_init(void)
 681{
 682        int ret;
 683
 684        /* Register the bus */
 685        ret = bus_register(&mips_cdmm_bustype);
 686        if (ret)
 687                return ret;
 688
 689        /* We want to be notified about new CPUs */
 690        ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "bus/cdmm:online",
 691                                mips_cdmm_cpu_online, mips_cdmm_cpu_down_prep);
 692        if (ret < 0)
 693                pr_warn("cdmm: Failed to register CPU notifier\n");
 694
 695        return ret;
 696}
 697subsys_initcall(mips_cdmm_init);
 698