root/drivers/bus/mips_cdmm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mips_cdmm_lookup
  2. mips_cdmm_match
  3. mips_cdmm_uevent
  4. mips_cdmm_void_work
  5. mips_cdmm_int_work
  6. BUILD_PERCPU_HELPER
  7. mips_cdmm_driver_unregister
  8. mips_cdmm_get_bus
  9. mips_cdmm_cur_base
  10. mips_cdmm_phys_base
  11. mips_cdmm_setup
  12. mips_cdmm_early_probe
  13. mips_cdmm_release
  14. mips_cdmm_bus_discover
  15. BUILD_PERDEV_HELPER
  16. mips_cdmm_cpu_online
  17. mips_cdmm_init

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

/* [<][>][^][v][top][bottom][index][help] */