linux/drivers/bcma/main.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * Bus subsystem
   4 *
   5 * Licensed under the GNU/GPL. See COPYING for details.
   6 */
   7
   8#include "bcma_private.h"
   9#include <linux/module.h>
  10#include <linux/bcma/bcma.h>
  11#include <linux/slab.h>
  12
  13MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
  14MODULE_LICENSE("GPL");
  15
  16/* contains the number the next bus should get. */
  17static unsigned int bcma_bus_next_num = 0;
  18
  19/* bcma_buses_mutex locks the bcma_bus_next_num */
  20static DEFINE_MUTEX(bcma_buses_mutex);
  21
  22static int bcma_bus_match(struct device *dev, struct device_driver *drv);
  23static int bcma_device_probe(struct device *dev);
  24static int bcma_device_remove(struct device *dev);
  25static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
  26
  27static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
  28{
  29        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  30        return sprintf(buf, "0x%03X\n", core->id.manuf);
  31}
  32static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
  33{
  34        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  35        return sprintf(buf, "0x%03X\n", core->id.id);
  36}
  37static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
  38{
  39        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  40        return sprintf(buf, "0x%02X\n", core->id.rev);
  41}
  42static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
  43{
  44        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  45        return sprintf(buf, "0x%X\n", core->id.class);
  46}
  47static struct device_attribute bcma_device_attrs[] = {
  48        __ATTR_RO(manuf),
  49        __ATTR_RO(id),
  50        __ATTR_RO(rev),
  51        __ATTR_RO(class),
  52        __ATTR_NULL,
  53};
  54
  55static struct bus_type bcma_bus_type = {
  56        .name           = "bcma",
  57        .match          = bcma_bus_match,
  58        .probe          = bcma_device_probe,
  59        .remove         = bcma_device_remove,
  60        .uevent         = bcma_device_uevent,
  61        .dev_attrs      = bcma_device_attrs,
  62};
  63
  64struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
  65{
  66        struct bcma_device *core;
  67
  68        list_for_each_entry(core, &bus->cores, list) {
  69                if (core->id.id == coreid)
  70                        return core;
  71        }
  72        return NULL;
  73}
  74EXPORT_SYMBOL_GPL(bcma_find_core);
  75
  76static void bcma_release_core_dev(struct device *dev)
  77{
  78        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
  79        if (core->io_addr)
  80                iounmap(core->io_addr);
  81        if (core->io_wrap)
  82                iounmap(core->io_wrap);
  83        kfree(core);
  84}
  85
  86static int bcma_register_cores(struct bcma_bus *bus)
  87{
  88        struct bcma_device *core;
  89        int err, dev_id = 0;
  90
  91        list_for_each_entry(core, &bus->cores, list) {
  92                /* We support that cores ourself */
  93                switch (core->id.id) {
  94                case BCMA_CORE_CHIPCOMMON:
  95                case BCMA_CORE_PCI:
  96                case BCMA_CORE_PCIE:
  97                case BCMA_CORE_MIPS_74K:
  98                        continue;
  99                }
 100
 101                core->dev.release = bcma_release_core_dev;
 102                core->dev.bus = &bcma_bus_type;
 103                dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
 104
 105                switch (bus->hosttype) {
 106                case BCMA_HOSTTYPE_PCI:
 107                        core->dev.parent = &bus->host_pci->dev;
 108                        core->dma_dev = &bus->host_pci->dev;
 109                        core->irq = bus->host_pci->irq;
 110                        break;
 111                case BCMA_HOSTTYPE_SOC:
 112                        core->dev.dma_mask = &core->dev.coherent_dma_mask;
 113                        core->dma_dev = &core->dev;
 114                        break;
 115                case BCMA_HOSTTYPE_SDIO:
 116                        break;
 117                }
 118
 119                err = device_register(&core->dev);
 120                if (err) {
 121                        pr_err("Could not register dev for core 0x%03X\n",
 122                               core->id.id);
 123                        continue;
 124                }
 125                core->dev_registered = true;
 126                dev_id++;
 127        }
 128
 129        return 0;
 130}
 131
 132static void bcma_unregister_cores(struct bcma_bus *bus)
 133{
 134        struct bcma_device *core;
 135
 136        list_for_each_entry(core, &bus->cores, list) {
 137                if (core->dev_registered)
 138                        device_unregister(&core->dev);
 139        }
 140}
 141
 142int __devinit bcma_bus_register(struct bcma_bus *bus)
 143{
 144        int err;
 145        struct bcma_device *core;
 146
 147        mutex_lock(&bcma_buses_mutex);
 148        bus->num = bcma_bus_next_num++;
 149        mutex_unlock(&bcma_buses_mutex);
 150
 151        /* Scan for devices (cores) */
 152        err = bcma_bus_scan(bus);
 153        if (err) {
 154                pr_err("Failed to scan: %d\n", err);
 155                return -1;
 156        }
 157
 158        /* Init CC core */
 159        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 160        if (core) {
 161                bus->drv_cc.core = core;
 162                bcma_core_chipcommon_init(&bus->drv_cc);
 163        }
 164
 165        /* Init MIPS core */
 166        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 167        if (core) {
 168                bus->drv_mips.core = core;
 169                bcma_core_mips_init(&bus->drv_mips);
 170        }
 171
 172        /* Init PCIE core */
 173        core = bcma_find_core(bus, BCMA_CORE_PCIE);
 174        if (core) {
 175                bus->drv_pci.core = core;
 176                bcma_core_pci_init(&bus->drv_pci);
 177        }
 178
 179        /* Try to get SPROM */
 180        err = bcma_sprom_get(bus);
 181        if (err == -ENOENT) {
 182                pr_err("No SPROM available\n");
 183        } else if (err)
 184                pr_err("Failed to get SPROM: %d\n", err);
 185
 186        /* Register found cores */
 187        bcma_register_cores(bus);
 188
 189        pr_info("Bus registered\n");
 190
 191        return 0;
 192}
 193
 194void bcma_bus_unregister(struct bcma_bus *bus)
 195{
 196        bcma_unregister_cores(bus);
 197}
 198
 199int __init bcma_bus_early_register(struct bcma_bus *bus,
 200                                   struct bcma_device *core_cc,
 201                                   struct bcma_device *core_mips)
 202{
 203        int err;
 204        struct bcma_device *core;
 205        struct bcma_device_id match;
 206
 207        bcma_init_bus(bus);
 208
 209        match.manuf = BCMA_MANUF_BCM;
 210        match.id = BCMA_CORE_CHIPCOMMON;
 211        match.class = BCMA_CL_SIM;
 212        match.rev = BCMA_ANY_REV;
 213
 214        /* Scan for chip common core */
 215        err = bcma_bus_scan_early(bus, &match, core_cc);
 216        if (err) {
 217                pr_err("Failed to scan for common core: %d\n", err);
 218                return -1;
 219        }
 220
 221        match.manuf = BCMA_MANUF_MIPS;
 222        match.id = BCMA_CORE_MIPS_74K;
 223        match.class = BCMA_CL_SIM;
 224        match.rev = BCMA_ANY_REV;
 225
 226        /* Scan for mips core */
 227        err = bcma_bus_scan_early(bus, &match, core_mips);
 228        if (err) {
 229                pr_err("Failed to scan for mips core: %d\n", err);
 230                return -1;
 231        }
 232
 233        /* Init CC core */
 234        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 235        if (core) {
 236                bus->drv_cc.core = core;
 237                bcma_core_chipcommon_init(&bus->drv_cc);
 238        }
 239
 240        /* Init MIPS core */
 241        core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 242        if (core) {
 243                bus->drv_mips.core = core;
 244                bcma_core_mips_init(&bus->drv_mips);
 245        }
 246
 247        pr_info("Early bus registered\n");
 248
 249        return 0;
 250}
 251
 252#ifdef CONFIG_PM
 253int bcma_bus_suspend(struct bcma_bus *bus)
 254{
 255        struct bcma_device *core;
 256
 257        list_for_each_entry(core, &bus->cores, list) {
 258                struct device_driver *drv = core->dev.driver;
 259                if (drv) {
 260                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 261                        if (adrv->suspend)
 262                                adrv->suspend(core);
 263                }
 264        }
 265        return 0;
 266}
 267
 268int bcma_bus_resume(struct bcma_bus *bus)
 269{
 270        struct bcma_device *core;
 271
 272        /* Init CC core */
 273        core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
 274        if (core) {
 275                bus->drv_cc.setup_done = false;
 276                bcma_core_chipcommon_init(&bus->drv_cc);
 277        }
 278
 279        list_for_each_entry(core, &bus->cores, list) {
 280                struct device_driver *drv = core->dev.driver;
 281                if (drv) {
 282                        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 283                        if (adrv->resume)
 284                                adrv->resume(core);
 285                }
 286        }
 287
 288        return 0;
 289}
 290#endif
 291
 292int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 293{
 294        drv->drv.name = drv->name;
 295        drv->drv.bus = &bcma_bus_type;
 296        drv->drv.owner = owner;
 297
 298        return driver_register(&drv->drv);
 299}
 300EXPORT_SYMBOL_GPL(__bcma_driver_register);
 301
 302void bcma_driver_unregister(struct bcma_driver *drv)
 303{
 304        driver_unregister(&drv->drv);
 305}
 306EXPORT_SYMBOL_GPL(bcma_driver_unregister);
 307
 308static int bcma_bus_match(struct device *dev, struct device_driver *drv)
 309{
 310        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 311        struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
 312        const struct bcma_device_id *cid = &core->id;
 313        const struct bcma_device_id *did;
 314
 315        for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
 316            if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
 317                (did->id == cid->id || did->id == BCMA_ANY_ID) &&
 318                (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
 319                (did->class == cid->class || did->class == BCMA_ANY_CLASS))
 320                        return 1;
 321        }
 322        return 0;
 323}
 324
 325static int bcma_device_probe(struct device *dev)
 326{
 327        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 328        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 329                                               drv);
 330        int err = 0;
 331
 332        if (adrv->probe)
 333                err = adrv->probe(core);
 334
 335        return err;
 336}
 337
 338static int bcma_device_remove(struct device *dev)
 339{
 340        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 341        struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
 342                                               drv);
 343
 344        if (adrv->remove)
 345                adrv->remove(core);
 346
 347        return 0;
 348}
 349
 350static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 351{
 352        struct bcma_device *core = container_of(dev, struct bcma_device, dev);
 353
 354        return add_uevent_var(env,
 355                              "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
 356                              core->id.manuf, core->id.id,
 357                              core->id.rev, core->id.class);
 358}
 359
 360static int __init bcma_modinit(void)
 361{
 362        int err;
 363
 364        err = bus_register(&bcma_bus_type);
 365        if (err)
 366                return err;
 367
 368#ifdef CONFIG_BCMA_HOST_PCI
 369        err = bcma_host_pci_init();
 370        if (err) {
 371                pr_err("PCI host initialization failed\n");
 372                err = 0;
 373        }
 374#endif
 375
 376        return err;
 377}
 378fs_initcall(bcma_modinit);
 379
 380static void __exit bcma_modexit(void)
 381{
 382#ifdef CONFIG_BCMA_HOST_PCI
 383        bcma_host_pci_exit();
 384#endif
 385        bus_unregister(&bcma_bus_type);
 386}
 387module_exit(bcma_modexit)
 388