Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Bus driver for MIPS Common Device Memory Map (CDMM).
0003  *
0004  * Copyright (C) 2014-2015 Imagination Technologies Ltd.
0005  *
0006  * This file is subject to the terms and conditions of the GNU General Public
0007  * License.  See the file "COPYING" in the main directory of this archive
0008  * for more details.
0009  */
0010 
0011 #include <linux/atomic.h>
0012 #include <linux/err.h>
0013 #include <linux/cpu.h>
0014 #include <linux/cpumask.h>
0015 #include <linux/io.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/slab.h>
0020 #include <linux/smp.h>
0021 #include <asm/cdmm.h>
0022 #include <asm/hazards.h>
0023 #include <asm/mipsregs.h>
0024 
0025 /* Access control and status register fields */
0026 #define CDMM_ACSR_DEVTYPE_SHIFT 24
0027 #define CDMM_ACSR_DEVTYPE   (255ul << CDMM_ACSR_DEVTYPE_SHIFT)
0028 #define CDMM_ACSR_DEVSIZE_SHIFT 16
0029 #define CDMM_ACSR_DEVSIZE   (31ul << CDMM_ACSR_DEVSIZE_SHIFT)
0030 #define CDMM_ACSR_DEVREV_SHIFT  12
0031 #define CDMM_ACSR_DEVREV    (15ul << CDMM_ACSR_DEVREV_SHIFT)
0032 #define CDMM_ACSR_UW        (1ul << 3)
0033 #define CDMM_ACSR_UR        (1ul << 2)
0034 #define CDMM_ACSR_SW        (1ul << 1)
0035 #define CDMM_ACSR_SR        (1ul << 0)
0036 
0037 /* Each block of device registers is 64 bytes */
0038 #define CDMM_DRB_SIZE       64
0039 
0040 #define to_mips_cdmm_driver(d)  container_of(d, struct mips_cdmm_driver, drv)
0041 
0042 /* Default physical base address */
0043 static phys_addr_t mips_cdmm_default_base;
0044 
0045 /* Bus operations */
0046 
0047 static const struct mips_cdmm_device_id *
0048 mips_cdmm_lookup(const struct mips_cdmm_device_id *table,
0049          struct mips_cdmm_device *dev)
0050 {
0051     int ret = 0;
0052 
0053     for (; table->type; ++table) {
0054         ret = (dev->type == table->type);
0055         if (ret)
0056             break;
0057     }
0058 
0059     return ret ? table : NULL;
0060 }
0061 
0062 static int mips_cdmm_match(struct device *dev, struct device_driver *drv)
0063 {
0064     struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
0065     struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(drv);
0066 
0067     return mips_cdmm_lookup(cdrv->id_table, cdev) != NULL;
0068 }
0069 
0070 static int mips_cdmm_uevent(struct device *dev, struct kobj_uevent_env *env)
0071 {
0072     struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
0073     int retval = 0;
0074 
0075     retval = add_uevent_var(env, "CDMM_CPU=%u", cdev->cpu);
0076     if (retval)
0077         return retval;
0078 
0079     retval = add_uevent_var(env, "CDMM_TYPE=0x%02x", cdev->type);
0080     if (retval)
0081         return retval;
0082 
0083     retval = add_uevent_var(env, "CDMM_REV=%u", cdev->rev);
0084     if (retval)
0085         return retval;
0086 
0087     retval = add_uevent_var(env, "MODALIAS=mipscdmm:t%02X", cdev->type);
0088     return retval;
0089 }
0090 
0091 /* Device attributes */
0092 
0093 #define CDMM_ATTR(name, fmt, arg...)                    \
0094 static ssize_t name##_show(struct device *_dev,             \
0095                struct device_attribute *attr, char *buf)    \
0096 {                                   \
0097     struct mips_cdmm_device *dev = to_mips_cdmm_device(_dev);   \
0098     return sprintf(buf, fmt, arg);                  \
0099 }                                   \
0100 static DEVICE_ATTR_RO(name);
0101 
0102 CDMM_ATTR(cpu, "%u\n", dev->cpu);
0103 CDMM_ATTR(type, "0x%02x\n", dev->type);
0104 CDMM_ATTR(revision, "%u\n", dev->rev);
0105 CDMM_ATTR(modalias, "mipscdmm:t%02X\n", dev->type);
0106 CDMM_ATTR(resource, "\t%016llx\t%016llx\t%016lx\n",
0107       (unsigned long long)dev->res.start,
0108       (unsigned long long)dev->res.end,
0109       dev->res.flags);
0110 
0111 static struct attribute *mips_cdmm_dev_attrs[] = {
0112     &dev_attr_cpu.attr,
0113     &dev_attr_type.attr,
0114     &dev_attr_revision.attr,
0115     &dev_attr_modalias.attr,
0116     &dev_attr_resource.attr,
0117     NULL,
0118 };
0119 ATTRIBUTE_GROUPS(mips_cdmm_dev);
0120 
0121 struct bus_type mips_cdmm_bustype = {
0122     .name       = "cdmm",
0123     .dev_groups = mips_cdmm_dev_groups,
0124     .match      = mips_cdmm_match,
0125     .uevent     = mips_cdmm_uevent,
0126 };
0127 EXPORT_SYMBOL_GPL(mips_cdmm_bustype);
0128 
0129 /*
0130  * Standard driver callback helpers.
0131  *
0132  * All the CDMM driver callbacks need to be executed on the appropriate CPU from
0133  * workqueues. For the standard driver callbacks we need a work function
0134  * (mips_cdmm_{void,int}_work()) to do the actual call from the right CPU, and a
0135  * wrapper function (generated with BUILD_PERCPU_HELPER) to arrange for the work
0136  * function to be called on that CPU.
0137  */
0138 
0139 /**
0140  * struct mips_cdmm_work_dev - Data for per-device call work.
0141  * @fn:     CDMM driver callback function to call for the device.
0142  * @dev:    CDMM device to pass to @fn.
0143  */
0144 struct mips_cdmm_work_dev {
0145     void            *fn;
0146     struct mips_cdmm_device *dev;
0147 };
0148 
0149 /**
0150  * mips_cdmm_void_work() - Call a void returning CDMM driver callback.
0151  * @data:   struct mips_cdmm_work_dev pointer.
0152  *
0153  * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
0154  * function which doesn't return a value.
0155  */
0156 static long mips_cdmm_void_work(void *data)
0157 {
0158     struct mips_cdmm_work_dev *work = data;
0159     void (*fn)(struct mips_cdmm_device *) = work->fn;
0160 
0161     fn(work->dev);
0162     return 0;
0163 }
0164 
0165 /**
0166  * mips_cdmm_int_work() - Call an int returning CDMM driver callback.
0167  * @data:   struct mips_cdmm_work_dev pointer.
0168  *
0169  * A work_on_cpu() callback function to call an arbitrary CDMM driver callback
0170  * function which returns an int.
0171  */
0172 static long mips_cdmm_int_work(void *data)
0173 {
0174     struct mips_cdmm_work_dev *work = data;
0175     int (*fn)(struct mips_cdmm_device *) = work->fn;
0176 
0177     return fn(work->dev);
0178 }
0179 
0180 #define _BUILD_RET_void
0181 #define _BUILD_RET_int  return
0182 
0183 /**
0184  * BUILD_PERCPU_HELPER() - Helper to call a CDMM driver callback on right CPU.
0185  * @_ret:   Return type (void or int).
0186  * @_name:  Name of CDMM driver callback function.
0187  *
0188  * Generates a specific device callback function to call a CDMM driver callback
0189  * function on the appropriate CPU for the device, and if applicable return the
0190  * result.
0191  */
0192 #define BUILD_PERCPU_HELPER(_ret, _name)                \
0193 static _ret mips_cdmm_##_name(struct device *dev)           \
0194 {                                   \
0195     struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);   \
0196     struct mips_cdmm_driver *cdrv = to_mips_cdmm_driver(dev->driver); \
0197     struct mips_cdmm_work_dev work = {              \
0198         .fn = cdrv->_name,                  \
0199         .dev    = cdev,                     \
0200     };                              \
0201                                     \
0202     _BUILD_RET_##_ret work_on_cpu(cdev->cpu,            \
0203                       mips_cdmm_##_ret##_work, &work);  \
0204 }
0205 
0206 /* Driver callback functions */
0207 BUILD_PERCPU_HELPER(int, probe)     /* int mips_cdmm_probe(struct device) */
0208 BUILD_PERCPU_HELPER(int, remove)    /* int mips_cdmm_remove(struct device) */
0209 BUILD_PERCPU_HELPER(void, shutdown) /* void mips_cdmm_shutdown(struct device) */
0210 
0211 
0212 /* Driver registration */
0213 
0214 /**
0215  * mips_cdmm_driver_register() - Register a CDMM driver.
0216  * @drv:    CDMM driver information.
0217  *
0218  * Register a CDMM driver with the CDMM subsystem. The driver will be informed
0219  * of matching devices which are discovered.
0220  *
0221  * Returns: 0 on success.
0222  */
0223 int mips_cdmm_driver_register(struct mips_cdmm_driver *drv)
0224 {
0225     drv->drv.bus = &mips_cdmm_bustype;
0226 
0227     if (drv->probe)
0228         drv->drv.probe = mips_cdmm_probe;
0229     if (drv->remove)
0230         drv->drv.remove = mips_cdmm_remove;
0231     if (drv->shutdown)
0232         drv->drv.shutdown = mips_cdmm_shutdown;
0233 
0234     return driver_register(&drv->drv);
0235 }
0236 EXPORT_SYMBOL_GPL(mips_cdmm_driver_register);
0237 
0238 /**
0239  * mips_cdmm_driver_unregister() - Unregister a CDMM driver.
0240  * @drv:    CDMM driver information.
0241  *
0242  * Unregister a CDMM driver from the CDMM subsystem.
0243  */
0244 void mips_cdmm_driver_unregister(struct mips_cdmm_driver *drv)
0245 {
0246     driver_unregister(&drv->drv);
0247 }
0248 EXPORT_SYMBOL_GPL(mips_cdmm_driver_unregister);
0249 
0250 
0251 /* CDMM initialisation and bus discovery */
0252 
0253 /**
0254  * struct mips_cdmm_bus - Info about CDMM bus.
0255  * @phys:       Physical address at which it is mapped.
0256  * @regs:       Virtual address where registers can be accessed.
0257  * @drbs:       Total number of DRBs.
0258  * @drbs_reserved:  Number of DRBs reserved.
0259  * @discovered:     Whether the devices on the bus have been discovered yet.
0260  * @offline:        Whether the CDMM bus is going offline (or very early
0261  *          coming back online), in which case it should be
0262  *          reconfigured each time.
0263  */
0264 struct mips_cdmm_bus {
0265     phys_addr_t  phys;
0266     void __iomem    *regs;
0267     unsigned int     drbs;
0268     unsigned int     drbs_reserved;
0269     bool         discovered;
0270     bool         offline;
0271 };
0272 
0273 static struct mips_cdmm_bus mips_cdmm_boot_bus;
0274 static DEFINE_PER_CPU(struct mips_cdmm_bus *, mips_cdmm_buses);
0275 static atomic_t mips_cdmm_next_id = ATOMIC_INIT(-1);
0276 
0277 /**
0278  * mips_cdmm_get_bus() - Get the per-CPU CDMM bus information.
0279  *
0280  * Get information about the per-CPU CDMM bus, if the bus is present.
0281  *
0282  * The caller must prevent migration to another CPU, either by disabling
0283  * pre-emption or by running from a pinned kernel thread.
0284  *
0285  * Returns: Pointer to CDMM bus information for the current CPU.
0286  *      May return ERR_PTR(-errno) in case of error, so check with
0287  *      IS_ERR().
0288  */
0289 static struct mips_cdmm_bus *mips_cdmm_get_bus(void)
0290 {
0291     struct mips_cdmm_bus *bus, **bus_p;
0292     unsigned long flags;
0293     unsigned int cpu;
0294 
0295     if (!cpu_has_cdmm)
0296         return ERR_PTR(-ENODEV);
0297 
0298     cpu = smp_processor_id();
0299     /* Avoid early use of per-cpu primitives before initialised */
0300     if (cpu == 0)
0301         return &mips_cdmm_boot_bus;
0302 
0303     /* Get bus pointer */
0304     bus_p = per_cpu_ptr(&mips_cdmm_buses, cpu);
0305     local_irq_save(flags);
0306     bus = *bus_p;
0307     /* Attempt allocation if NULL */
0308     if (unlikely(!bus)) {
0309         bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
0310         if (unlikely(!bus))
0311             bus = ERR_PTR(-ENOMEM);
0312         else
0313             *bus_p = bus;
0314     }
0315     local_irq_restore(flags);
0316     return bus;
0317 }
0318 
0319 /**
0320  * mips_cdmm_cur_base() - Find current physical base address of CDMM region.
0321  *
0322  * Returns: Physical base address of CDMM region according to cdmmbase CP0
0323  *      register, or 0 if the CDMM region is disabled.
0324  */
0325 static phys_addr_t mips_cdmm_cur_base(void)
0326 {
0327     unsigned long cdmmbase = read_c0_cdmmbase();
0328 
0329     if (!(cdmmbase & MIPS_CDMMBASE_EN))
0330         return 0;
0331 
0332     return (cdmmbase >> MIPS_CDMMBASE_ADDR_SHIFT)
0333         << MIPS_CDMMBASE_ADDR_START;
0334 }
0335 
0336 /**
0337  * mips_cdmm_phys_base() - Choose a physical base address for CDMM region.
0338  *
0339  * Picking a suitable physical address at which to map the CDMM region is
0340  * platform specific, so this weak function can be overridden by platform
0341  * code to pick a suitable value if none is configured by the bootloader.
0342  * By default this method tries to find a CDMM-specific node in the system
0343  * dtb. Note that this won't work for early serial console.
0344  */
0345 phys_addr_t __weak mips_cdmm_phys_base(void)
0346 {
0347     struct device_node *np;
0348     struct resource res;
0349     int err;
0350 
0351     np = of_find_compatible_node(NULL, NULL, "mti,mips-cdmm");
0352     if (np) {
0353         err = of_address_to_resource(np, 0, &res);
0354         of_node_put(np);
0355         if (!err)
0356             return res.start;
0357     }
0358 
0359     return 0;
0360 }
0361 
0362 /**
0363  * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable.
0364  * @bus:    Pointer to bus information for current CPU.
0365  *      IS_ERR(bus) is checked, so no need for caller to check.
0366  *
0367  * The caller must prevent migration to another CPU, either by disabling
0368  * pre-emption or by running from a pinned kernel thread.
0369  *
0370  * Returns  0 on success, -errno on failure.
0371  */
0372 static int mips_cdmm_setup(struct mips_cdmm_bus *bus)
0373 {
0374     unsigned long cdmmbase, flags;
0375     int ret = 0;
0376 
0377     if (IS_ERR(bus))
0378         return PTR_ERR(bus);
0379 
0380     local_irq_save(flags);
0381     /* Don't set up bus a second time unless marked offline */
0382     if (bus->offline) {
0383         /* If CDMM region is still set up, nothing to do */
0384         if (bus->phys == mips_cdmm_cur_base())
0385             goto out;
0386         /*
0387          * The CDMM region isn't set up as expected, so it needs
0388          * reconfiguring, but then we can stop checking it.
0389          */
0390         bus->offline = false;
0391     } else if (bus->phys > 1) {
0392         goto out;
0393     }
0394 
0395     /* If the CDMM region is already configured, inherit that setup */
0396     if (!bus->phys)
0397         bus->phys = mips_cdmm_cur_base();
0398     /* Otherwise, ask platform code for suggestions */
0399     if (!bus->phys)
0400         bus->phys = mips_cdmm_phys_base();
0401     /* Otherwise, copy what other CPUs have done */
0402     if (!bus->phys)
0403         bus->phys = mips_cdmm_default_base;
0404     /* Otherwise, complain once */
0405     if (!bus->phys) {
0406         bus->phys = 1;
0407         /*
0408          * If you hit this, either your bootloader needs to set up the
0409          * CDMM on the boot CPU, or else you need to implement
0410          * mips_cdmm_phys_base() for your platform (see asm/cdmm.h).
0411          */
0412         pr_err("cdmm%u: Failed to choose a physical base\n",
0413                smp_processor_id());
0414     }
0415     /* Already complained? */
0416     if (bus->phys == 1) {
0417         ret = -ENOMEM;
0418         goto out;
0419     }
0420     /* Record our success for other CPUs to copy */
0421     mips_cdmm_default_base = bus->phys;
0422 
0423     pr_debug("cdmm%u: Enabling CDMM region at %pa\n",
0424          smp_processor_id(), &bus->phys);
0425 
0426     /* Enable CDMM */
0427     cdmmbase = read_c0_cdmmbase();
0428     cdmmbase &= (1ul << MIPS_CDMMBASE_ADDR_SHIFT) - 1;
0429     cdmmbase |= (bus->phys >> MIPS_CDMMBASE_ADDR_START)
0430             << MIPS_CDMMBASE_ADDR_SHIFT;
0431     cdmmbase |= MIPS_CDMMBASE_EN;
0432     write_c0_cdmmbase(cdmmbase);
0433     tlbw_use_hazard();
0434 
0435     bus->regs = (void __iomem *)CKSEG1ADDR(bus->phys);
0436     bus->drbs = 1 + ((cdmmbase & MIPS_CDMMBASE_SIZE) >>
0437              MIPS_CDMMBASE_SIZE_SHIFT);
0438     bus->drbs_reserved = !!(cdmmbase & MIPS_CDMMBASE_CI);
0439 
0440 out:
0441     local_irq_restore(flags);
0442     return ret;
0443 }
0444 
0445 /**
0446  * mips_cdmm_early_probe() - Minimally probe for a specific device on CDMM.
0447  * @dev_type:   CDMM type code to look for.
0448  *
0449  * Minimally configure the in-CPU Common Device Memory Map (CDMM) and look for a
0450  * specific device. This can be used to find a device very early in boot for
0451  * example to configure an early FDC console device.
0452  *
0453  * The caller must prevent migration to another CPU, either by disabling
0454  * pre-emption or by running from a pinned kernel thread.
0455  *
0456  * Returns: MMIO pointer to device memory. The caller can read the ACSR
0457  *      register to find more information about the device (such as the
0458  *      version number or the number of blocks).
0459  *      May return IOMEM_ERR_PTR(-errno) in case of error, so check with
0460  *      IS_ERR().
0461  */
0462 void __iomem *mips_cdmm_early_probe(unsigned int dev_type)
0463 {
0464     struct mips_cdmm_bus *bus;
0465     void __iomem *cdmm;
0466     u32 acsr;
0467     unsigned int drb, type, size;
0468     int err;
0469 
0470     if (WARN_ON(!dev_type))
0471         return IOMEM_ERR_PTR(-ENODEV);
0472 
0473     bus = mips_cdmm_get_bus();
0474     err = mips_cdmm_setup(bus);
0475     if (err)
0476         return IOMEM_ERR_PTR(err);
0477 
0478     /* Skip the first block if it's reserved for more registers */
0479     drb = bus->drbs_reserved;
0480     cdmm = bus->regs;
0481 
0482     /* Look for a specific device type */
0483     for (; drb < bus->drbs; drb += size + 1) {
0484         acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
0485         type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
0486         if (type == dev_type)
0487             return cdmm + drb * CDMM_DRB_SIZE;
0488         size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
0489     }
0490 
0491     return IOMEM_ERR_PTR(-ENODEV);
0492 }
0493 EXPORT_SYMBOL_GPL(mips_cdmm_early_probe);
0494 
0495 /**
0496  * mips_cdmm_release() - Release a removed CDMM device.
0497  * @dev:    Device object
0498  *
0499  * Clean up the struct mips_cdmm_device for an unused CDMM device. This is
0500  * called automatically by the driver core when a device is removed.
0501  */
0502 static void mips_cdmm_release(struct device *dev)
0503 {
0504     struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
0505 
0506     kfree(cdev);
0507 }
0508 
0509 /**
0510  * mips_cdmm_bus_discover() - Discover the devices on the CDMM bus.
0511  * @bus:    CDMM bus information, must already be set up.
0512  */
0513 static void mips_cdmm_bus_discover(struct mips_cdmm_bus *bus)
0514 {
0515     void __iomem *cdmm;
0516     u32 acsr;
0517     unsigned int drb, type, size, rev;
0518     struct mips_cdmm_device *dev;
0519     unsigned int cpu = smp_processor_id();
0520     int ret = 0;
0521     int id = 0;
0522 
0523     /* Skip the first block if it's reserved for more registers */
0524     drb = bus->drbs_reserved;
0525     cdmm = bus->regs;
0526 
0527     /* Discover devices */
0528     bus->discovered = true;
0529     pr_info("cdmm%u discovery (%u blocks)\n", cpu, bus->drbs);
0530     for (; drb < bus->drbs; drb += size + 1) {
0531         acsr = __raw_readl(cdmm + drb * CDMM_DRB_SIZE);
0532         type = (acsr & CDMM_ACSR_DEVTYPE) >> CDMM_ACSR_DEVTYPE_SHIFT;
0533         size = (acsr & CDMM_ACSR_DEVSIZE) >> CDMM_ACSR_DEVSIZE_SHIFT;
0534         rev  = (acsr & CDMM_ACSR_DEVREV)  >> CDMM_ACSR_DEVREV_SHIFT;
0535 
0536         if (!type)
0537             continue;
0538 
0539         pr_info("cdmm%u-%u: @%u (%#x..%#x), type 0x%02x, rev %u\n",
0540             cpu, id, drb, drb * CDMM_DRB_SIZE,
0541             (drb + size + 1) * CDMM_DRB_SIZE - 1,
0542             type, rev);
0543 
0544         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0545         if (!dev)
0546             break;
0547 
0548         dev->cpu = cpu;
0549         dev->res.start = bus->phys + drb * CDMM_DRB_SIZE;
0550         dev->res.end = bus->phys +
0551                 (drb + size + 1) * CDMM_DRB_SIZE - 1;
0552         dev->res.flags = IORESOURCE_MEM;
0553         dev->type = type;
0554         dev->rev = rev;
0555         dev->dev.parent = get_cpu_device(cpu);
0556         dev->dev.bus = &mips_cdmm_bustype;
0557         dev->dev.id = atomic_inc_return(&mips_cdmm_next_id);
0558         dev->dev.release = mips_cdmm_release;
0559 
0560         dev_set_name(&dev->dev, "cdmm%u-%u", cpu, id);
0561         ++id;
0562         ret = device_register(&dev->dev);
0563         if (ret)
0564             put_device(&dev->dev);
0565     }
0566 }
0567 
0568 
0569 /*
0570  * CPU hotplug and initialisation
0571  *
0572  * All the CDMM driver callbacks need to be executed on the appropriate CPU from
0573  * workqueues. For the CPU callbacks, they need to be called for all devices on
0574  * that CPU, so the work function calls bus_for_each_dev, using a helper
0575  * (generated with BUILD_PERDEV_HELPER) to call the driver callback if the
0576  * device's CPU matches.
0577  */
0578 
0579 /**
0580  * BUILD_PERDEV_HELPER() - Helper to call a CDMM driver callback if CPU matches.
0581  * @_name:  Name of CDMM driver callback function.
0582  *
0583  * Generates a bus_for_each_dev callback function to call a specific CDMM driver
0584  * callback function for the device if the device's CPU matches that pointed to
0585  * by the data argument.
0586  *
0587  * This is used for informing drivers for all devices on a given CPU of some
0588  * event (such as the CPU going online/offline).
0589  *
0590  * It is expected to already be called from the appropriate CPU.
0591  */
0592 #define BUILD_PERDEV_HELPER(_name)                  \
0593 static int mips_cdmm_##_name##_helper(struct device *dev, void *data)   \
0594 {                                   \
0595     struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);   \
0596     struct mips_cdmm_driver *cdrv;                  \
0597     unsigned int cpu = *(unsigned int *)data;           \
0598                                     \
0599     if (cdev->cpu != cpu || !dev->driver)               \
0600         return 0;                       \
0601                                     \
0602     cdrv = to_mips_cdmm_driver(dev->driver);            \
0603     if (!cdrv->_name)                       \
0604         return 0;                       \
0605     return cdrv->_name(cdev);                   \
0606 }
0607 
0608 /* bus_for_each_dev callback helper functions */
0609 BUILD_PERDEV_HELPER(cpu_down)       /* int mips_cdmm_cpu_down_helper(...) */
0610 BUILD_PERDEV_HELPER(cpu_up)         /* int mips_cdmm_cpu_up_helper(...) */
0611 
0612 /**
0613  * mips_cdmm_cpu_down_prep() - Callback for CPUHP DOWN_PREP:
0614  *                 Tear down the CDMM bus.
0615  * @cpu:    unsigned int CPU number.
0616  *
0617  * This function is executed on the hotplugged CPU and calls the CDMM
0618  * driver cpu_down callback for all devices on that CPU.
0619  */
0620 static int mips_cdmm_cpu_down_prep(unsigned int cpu)
0621 {
0622     struct mips_cdmm_bus *bus;
0623     long ret;
0624 
0625     /* Inform all the devices on the bus */
0626     ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
0627                    mips_cdmm_cpu_down_helper);
0628 
0629     /*
0630      * While bus is offline, each use of it should reconfigure it just in
0631      * case it is first use when coming back online again.
0632      */
0633     bus = mips_cdmm_get_bus();
0634     if (!IS_ERR(bus))
0635         bus->offline = true;
0636 
0637     return ret;
0638 }
0639 
0640 /**
0641  * mips_cdmm_cpu_online() - Callback for CPUHP ONLINE: Bring up the CDMM bus.
0642  * @cpu:    unsigned int CPU number.
0643  *
0644  * This work_on_cpu callback function is executed on a given CPU to discover
0645  * CDMM devices on that CPU, or to call the CDMM driver cpu_up callback for all
0646  * devices already discovered on that CPU.
0647  *
0648  * It is used as work_on_cpu callback function during
0649  * initialisation. When CPUs are brought online the function is
0650  * invoked directly on the hotplugged CPU.
0651  */
0652 static int mips_cdmm_cpu_online(unsigned int cpu)
0653 {
0654     struct mips_cdmm_bus *bus;
0655     long ret;
0656 
0657     bus = mips_cdmm_get_bus();
0658     ret = mips_cdmm_setup(bus);
0659     if (ret)
0660         return ret;
0661 
0662     /* Bus now set up, so we can drop the offline flag if still set */
0663     bus->offline = false;
0664 
0665     if (!bus->discovered)
0666         mips_cdmm_bus_discover(bus);
0667     else
0668         /* Inform all the devices on the bus */
0669         ret = bus_for_each_dev(&mips_cdmm_bustype, NULL, &cpu,
0670                        mips_cdmm_cpu_up_helper);
0671 
0672     return ret;
0673 }
0674 
0675 /**
0676  * mips_cdmm_init() - Initialise CDMM bus.
0677  *
0678  * Initialise CDMM bus, discover CDMM devices for online CPUs, and arrange for
0679  * hotplug notifications so the CDMM drivers can be kept up to date.
0680  */
0681 static int __init mips_cdmm_init(void)
0682 {
0683     int ret;
0684 
0685     /* Register the bus */
0686     ret = bus_register(&mips_cdmm_bustype);
0687     if (ret)
0688         return ret;
0689 
0690     /* We want to be notified about new CPUs */
0691     ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "bus/cdmm:online",
0692                 mips_cdmm_cpu_online, mips_cdmm_cpu_down_prep);
0693     if (ret < 0)
0694         pr_warn("cdmm: Failed to register CPU notifier\n");
0695 
0696     return ret;
0697 }
0698 subsys_initcall(mips_cdmm_init);