linux/drivers/mcb/mcb-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * MEN Chameleon Bus.
   4 *
   5 * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
   6 * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
   7 */
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/slab.h>
  11#include <linux/types.h>
  12#include <linux/idr.h>
  13#include <linux/mcb.h>
  14
  15static DEFINE_IDA(mcb_ida);
  16
  17static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
  18                                                struct mcb_device *dev)
  19{
  20        if (ids) {
  21                while (ids->device) {
  22                        if (ids->device == dev->id)
  23                                return ids;
  24                        ids++;
  25                }
  26        }
  27
  28        return NULL;
  29}
  30
  31static int mcb_match(struct device *dev, struct device_driver *drv)
  32{
  33        struct mcb_driver *mdrv = to_mcb_driver(drv);
  34        struct mcb_device *mdev = to_mcb_device(dev);
  35        const struct mcb_device_id *found_id;
  36
  37        found_id = mcb_match_id(mdrv->id_table, mdev);
  38        if (found_id)
  39                return 1;
  40
  41        return 0;
  42}
  43
  44static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
  45{
  46        struct mcb_device *mdev = to_mcb_device(dev);
  47        int ret;
  48
  49        ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
  50        if (ret)
  51                return -ENOMEM;
  52
  53        return 0;
  54}
  55
  56static int mcb_probe(struct device *dev)
  57{
  58        struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
  59        struct mcb_device *mdev = to_mcb_device(dev);
  60        const struct mcb_device_id *found_id;
  61        struct module *carrier_mod;
  62        int ret;
  63
  64        found_id = mcb_match_id(mdrv->id_table, mdev);
  65        if (!found_id)
  66                return -ENODEV;
  67
  68        carrier_mod = mdev->dev.parent->driver->owner;
  69        if (!try_module_get(carrier_mod))
  70                return -EINVAL;
  71
  72        get_device(dev);
  73        ret = mdrv->probe(mdev, found_id);
  74        if (ret)
  75                module_put(carrier_mod);
  76
  77        return ret;
  78}
  79
  80static int mcb_remove(struct device *dev)
  81{
  82        struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
  83        struct mcb_device *mdev = to_mcb_device(dev);
  84        struct module *carrier_mod;
  85
  86        mdrv->remove(mdev);
  87
  88        carrier_mod = mdev->dev.parent->driver->owner;
  89        module_put(carrier_mod);
  90
  91        put_device(&mdev->dev);
  92
  93        return 0;
  94}
  95
  96static void mcb_shutdown(struct device *dev)
  97{
  98        struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
  99        struct mcb_device *mdev = to_mcb_device(dev);
 100
 101        if (mdrv && mdrv->shutdown)
 102                mdrv->shutdown(mdev);
 103}
 104
 105static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
 106                         char *buf)
 107{
 108        struct mcb_bus *bus = to_mcb_bus(dev);
 109
 110        return scnprintf(buf, PAGE_SIZE, "%d\n", bus->revision);
 111}
 112static DEVICE_ATTR_RO(revision);
 113
 114static ssize_t model_show(struct device *dev, struct device_attribute *attr,
 115                         char *buf)
 116{
 117        struct mcb_bus *bus = to_mcb_bus(dev);
 118
 119        return scnprintf(buf, PAGE_SIZE, "%c\n", bus->model);
 120}
 121static DEVICE_ATTR_RO(model);
 122
 123static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
 124                         char *buf)
 125{
 126        struct mcb_bus *bus = to_mcb_bus(dev);
 127
 128        return scnprintf(buf, PAGE_SIZE, "%d\n", bus->minor);
 129}
 130static DEVICE_ATTR_RO(minor);
 131
 132static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 133                         char *buf)
 134{
 135        struct mcb_bus *bus = to_mcb_bus(dev);
 136
 137        return scnprintf(buf, PAGE_SIZE, "%s\n", bus->name);
 138}
 139static DEVICE_ATTR_RO(name);
 140
 141static struct attribute *mcb_bus_attrs[] = {
 142        &dev_attr_revision.attr,
 143        &dev_attr_model.attr,
 144        &dev_attr_minor.attr,
 145        &dev_attr_name.attr,
 146        NULL,
 147};
 148
 149static const struct attribute_group mcb_carrier_group = {
 150        .attrs = mcb_bus_attrs,
 151};
 152
 153static const struct attribute_group *mcb_carrier_groups[] = {
 154        &mcb_carrier_group,
 155        NULL,
 156};
 157
 158
 159static struct bus_type mcb_bus_type = {
 160        .name = "mcb",
 161        .match = mcb_match,
 162        .uevent = mcb_uevent,
 163        .probe = mcb_probe,
 164        .remove = mcb_remove,
 165        .shutdown = mcb_shutdown,
 166};
 167
 168static struct device_type mcb_carrier_device_type = {
 169        .name = "mcb-carrier",
 170        .groups = mcb_carrier_groups,
 171};
 172
 173/**
 174 * __mcb_register_driver() - Register a @mcb_driver at the system
 175 * @drv: The @mcb_driver
 176 * @owner: The @mcb_driver's module
 177 * @mod_name: The name of the @mcb_driver's module
 178 *
 179 * Register a @mcb_driver at the system. Perform some sanity checks, if
 180 * the .probe and .remove methods are provided by the driver.
 181 */
 182int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
 183                        const char *mod_name)
 184{
 185        if (!drv->probe || !drv->remove)
 186                return -EINVAL;
 187
 188        drv->driver.owner = owner;
 189        drv->driver.bus = &mcb_bus_type;
 190        drv->driver.mod_name = mod_name;
 191
 192        return driver_register(&drv->driver);
 193}
 194EXPORT_SYMBOL_NS_GPL(__mcb_register_driver, MCB);
 195
 196/**
 197 * mcb_unregister_driver() - Unregister a @mcb_driver from the system
 198 * @drv: The @mcb_driver
 199 *
 200 * Unregister a @mcb_driver from the system.
 201 */
 202void mcb_unregister_driver(struct mcb_driver *drv)
 203{
 204        driver_unregister(&drv->driver);
 205}
 206EXPORT_SYMBOL_NS_GPL(mcb_unregister_driver, MCB);
 207
 208static void mcb_release_dev(struct device *dev)
 209{
 210        struct mcb_device *mdev = to_mcb_device(dev);
 211
 212        mcb_bus_put(mdev->bus);
 213        kfree(mdev);
 214}
 215
 216/**
 217 * mcb_device_register() - Register a mcb_device
 218 * @bus: The @mcb_bus of the device
 219 * @dev: The @mcb_device
 220 *
 221 * Register a specific @mcb_device at a @mcb_bus and the system itself.
 222 */
 223int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
 224{
 225        int ret;
 226        int device_id;
 227
 228        device_initialize(&dev->dev);
 229        mcb_bus_get(bus);
 230        dev->dev.bus = &mcb_bus_type;
 231        dev->dev.parent = bus->dev.parent;
 232        dev->dev.release = mcb_release_dev;
 233        dev->dma_dev = bus->carrier;
 234
 235        device_id = dev->id;
 236        dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
 237                bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
 238
 239        ret = device_add(&dev->dev);
 240        if (ret < 0) {
 241                pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
 242                        device_id, bus->bus_nr, ret);
 243                goto out;
 244        }
 245
 246        return 0;
 247
 248out:
 249
 250        return ret;
 251}
 252EXPORT_SYMBOL_NS_GPL(mcb_device_register, MCB);
 253
 254static void mcb_free_bus(struct device *dev)
 255{
 256        struct mcb_bus *bus = to_mcb_bus(dev);
 257
 258        put_device(bus->carrier);
 259        ida_simple_remove(&mcb_ida, bus->bus_nr);
 260        kfree(bus);
 261}
 262
 263/**
 264 * mcb_alloc_bus() - Allocate a new @mcb_bus
 265 *
 266 * Allocate a new @mcb_bus.
 267 */
 268struct mcb_bus *mcb_alloc_bus(struct device *carrier)
 269{
 270        struct mcb_bus *bus;
 271        int bus_nr;
 272        int rc;
 273
 274        bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
 275        if (!bus)
 276                return ERR_PTR(-ENOMEM);
 277
 278        bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
 279        if (bus_nr < 0) {
 280                rc = bus_nr;
 281                goto err_free;
 282        }
 283
 284        bus->bus_nr = bus_nr;
 285        bus->carrier = get_device(carrier);
 286
 287        device_initialize(&bus->dev);
 288        bus->dev.parent = carrier;
 289        bus->dev.bus = &mcb_bus_type;
 290        bus->dev.type = &mcb_carrier_device_type;
 291        bus->dev.release = &mcb_free_bus;
 292
 293        dev_set_name(&bus->dev, "mcb:%d", bus_nr);
 294        rc = device_add(&bus->dev);
 295        if (rc)
 296                goto err_free;
 297
 298        return bus;
 299err_free:
 300        put_device(carrier);
 301        kfree(bus);
 302        return ERR_PTR(rc);
 303}
 304EXPORT_SYMBOL_NS_GPL(mcb_alloc_bus, MCB);
 305
 306static int __mcb_devices_unregister(struct device *dev, void *data)
 307{
 308        device_unregister(dev);
 309        return 0;
 310}
 311
 312static void mcb_devices_unregister(struct mcb_bus *bus)
 313{
 314        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
 315}
 316/**
 317 * mcb_release_bus() - Free a @mcb_bus
 318 * @bus: The @mcb_bus to release
 319 *
 320 * Release an allocated @mcb_bus from the system.
 321 */
 322void mcb_release_bus(struct mcb_bus *bus)
 323{
 324        mcb_devices_unregister(bus);
 325}
 326EXPORT_SYMBOL_NS_GPL(mcb_release_bus, MCB);
 327
 328/**
 329 * mcb_bus_put() - Increment refcnt
 330 * @bus: The @mcb_bus
 331 *
 332 * Get a @mcb_bus' ref
 333 */
 334struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
 335{
 336        if (bus)
 337                get_device(&bus->dev);
 338
 339        return bus;
 340}
 341EXPORT_SYMBOL_NS_GPL(mcb_bus_get, MCB);
 342
 343/**
 344 * mcb_bus_put() - Decrement refcnt
 345 * @bus: The @mcb_bus
 346 *
 347 * Release a @mcb_bus' ref
 348 */
 349void mcb_bus_put(struct mcb_bus *bus)
 350{
 351        if (bus)
 352                put_device(&bus->dev);
 353}
 354EXPORT_SYMBOL_NS_GPL(mcb_bus_put, MCB);
 355
 356/**
 357 * mcb_alloc_dev() - Allocate a device
 358 * @bus: The @mcb_bus the device is part of
 359 *
 360 * Allocate a @mcb_device and add bus.
 361 */
 362struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
 363{
 364        struct mcb_device *dev;
 365
 366        dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
 367        if (!dev)
 368                return NULL;
 369
 370        dev->bus = bus;
 371
 372        return dev;
 373}
 374EXPORT_SYMBOL_NS_GPL(mcb_alloc_dev, MCB);
 375
 376/**
 377 * mcb_free_dev() - Free @mcb_device
 378 * @dev: The device to free
 379 *
 380 * Free a @mcb_device
 381 */
 382void mcb_free_dev(struct mcb_device *dev)
 383{
 384        kfree(dev);
 385}
 386EXPORT_SYMBOL_NS_GPL(mcb_free_dev, MCB);
 387
 388static int __mcb_bus_add_devices(struct device *dev, void *data)
 389{
 390        struct mcb_device *mdev = to_mcb_device(dev);
 391        int retval;
 392
 393        if (mdev->is_added)
 394                return 0;
 395
 396        retval = device_attach(dev);
 397        if (retval < 0)
 398                dev_err(dev, "Error adding device (%d)\n", retval);
 399
 400        mdev->is_added = true;
 401
 402        return 0;
 403}
 404
 405/**
 406 * mcb_bus_add_devices() - Add devices in the bus' internal device list
 407 * @bus: The @mcb_bus we add the devices
 408 *
 409 * Add devices in the bus' internal device list to the system.
 410 */
 411void mcb_bus_add_devices(const struct mcb_bus *bus)
 412{
 413        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
 414}
 415EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices, MCB);
 416
 417/**
 418 * mcb_get_resource() - get a resource for a mcb device
 419 * @dev: the mcb device
 420 * @type: the type of resource
 421 */
 422struct resource *mcb_get_resource(struct mcb_device *dev, unsigned int type)
 423{
 424        if (type == IORESOURCE_MEM)
 425                return &dev->mem;
 426        else if (type == IORESOURCE_IRQ)
 427                return &dev->irq;
 428        else
 429                return NULL;
 430}
 431EXPORT_SYMBOL_NS_GPL(mcb_get_resource, MCB);
 432
 433/**
 434 * mcb_request_mem() - Request memory
 435 * @dev: The @mcb_device the memory is for
 436 * @name: The name for the memory reference.
 437 *
 438 * Request memory for a @mcb_device. If @name is NULL the driver name will
 439 * be used.
 440 */
 441struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
 442{
 443        struct resource *mem;
 444        u32 size;
 445
 446        if (!name)
 447                name = dev->dev.driver->name;
 448
 449        size = resource_size(&dev->mem);
 450
 451        mem = request_mem_region(dev->mem.start, size, name);
 452        if (!mem)
 453                return ERR_PTR(-EBUSY);
 454
 455        return mem;
 456}
 457EXPORT_SYMBOL_NS_GPL(mcb_request_mem, MCB);
 458
 459/**
 460 * mcb_release_mem() - Release memory requested by device
 461 * @dev: The @mcb_device that requested the memory
 462 *
 463 * Release memory that was prior requested via @mcb_request_mem().
 464 */
 465void mcb_release_mem(struct resource *mem)
 466{
 467        u32 size;
 468
 469        size = resource_size(mem);
 470        release_mem_region(mem->start, size);
 471}
 472EXPORT_SYMBOL_NS_GPL(mcb_release_mem, MCB);
 473
 474static int __mcb_get_irq(struct mcb_device *dev)
 475{
 476        struct resource *irq;
 477
 478        irq = mcb_get_resource(dev, IORESOURCE_IRQ);
 479
 480        return irq->start;
 481}
 482
 483/**
 484 * mcb_get_irq() - Get device's IRQ number
 485 * @dev: The @mcb_device the IRQ is for
 486 *
 487 * Get the IRQ number of a given @mcb_device.
 488 */
 489int mcb_get_irq(struct mcb_device *dev)
 490{
 491        struct mcb_bus *bus = dev->bus;
 492
 493        if (bus->get_irq)
 494                return bus->get_irq(dev);
 495
 496        return __mcb_get_irq(dev);
 497}
 498EXPORT_SYMBOL_NS_GPL(mcb_get_irq, MCB);
 499
 500static int mcb_init(void)
 501{
 502        return bus_register(&mcb_bus_type);
 503}
 504
 505static void mcb_exit(void)
 506{
 507        ida_destroy(&mcb_ida);
 508        bus_unregister(&mcb_bus_type);
 509}
 510
 511/* mcb must be initialized after PCI but before the chameleon drivers.
 512 * That means we must use some initcall between subsys_initcall and
 513 * device_initcall.
 514 */
 515fs_initcall(mcb_init);
 516module_exit(mcb_exit);
 517
 518MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
 519MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
 520MODULE_LICENSE("GPL v2");
 521