linux/drivers/firmware/arm_scmi/bus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * System Control and Management Interface (SCMI) Message Protocol bus layer
   4 *
   5 * Copyright (C) 2018-2021 ARM Ltd.
   6 */
   7
   8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9
  10#include <linux/types.h>
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/slab.h>
  14#include <linux/device.h>
  15
  16#include "common.h"
  17
  18static DEFINE_IDA(scmi_bus_id);
  19static DEFINE_IDR(scmi_protocols);
  20static DEFINE_SPINLOCK(protocol_lock);
  21
  22static const struct scmi_device_id *
  23scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
  24{
  25        const struct scmi_device_id *id = scmi_drv->id_table;
  26
  27        if (!id)
  28                return NULL;
  29
  30        for (; id->protocol_id; id++)
  31                if (id->protocol_id == scmi_dev->protocol_id) {
  32                        if (!id->name)
  33                                return id;
  34                        else if (!strcmp(id->name, scmi_dev->name))
  35                                return id;
  36                }
  37
  38        return NULL;
  39}
  40
  41static int scmi_dev_match(struct device *dev, struct device_driver *drv)
  42{
  43        struct scmi_driver *scmi_drv = to_scmi_driver(drv);
  44        struct scmi_device *scmi_dev = to_scmi_dev(dev);
  45        const struct scmi_device_id *id;
  46
  47        id = scmi_dev_match_id(scmi_dev, scmi_drv);
  48        if (id)
  49                return 1;
  50
  51        return 0;
  52}
  53
  54static int scmi_match_by_id_table(struct device *dev, void *data)
  55{
  56        struct scmi_device *sdev = to_scmi_dev(dev);
  57        struct scmi_device_id *id_table = data;
  58
  59        return sdev->protocol_id == id_table->protocol_id &&
  60                !strcmp(sdev->name, id_table->name);
  61}
  62
  63struct scmi_device *scmi_child_dev_find(struct device *parent,
  64                                        int prot_id, const char *name)
  65{
  66        struct scmi_device_id id_table;
  67        struct device *dev;
  68
  69        id_table.protocol_id = prot_id;
  70        id_table.name = name;
  71
  72        dev = device_find_child(parent, &id_table, scmi_match_by_id_table);
  73        if (!dev)
  74                return NULL;
  75
  76        return to_scmi_dev(dev);
  77}
  78
  79const struct scmi_protocol *scmi_protocol_get(int protocol_id)
  80{
  81        const struct scmi_protocol *proto;
  82
  83        proto = idr_find(&scmi_protocols, protocol_id);
  84        if (!proto || !try_module_get(proto->owner)) {
  85                pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id);
  86                return NULL;
  87        }
  88
  89        pr_debug("Found SCMI Protocol 0x%x\n", protocol_id);
  90
  91        return proto;
  92}
  93
  94void scmi_protocol_put(int protocol_id)
  95{
  96        const struct scmi_protocol *proto;
  97
  98        proto = idr_find(&scmi_protocols, protocol_id);
  99        if (proto)
 100                module_put(proto->owner);
 101}
 102
 103static int scmi_dev_probe(struct device *dev)
 104{
 105        struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
 106        struct scmi_device *scmi_dev = to_scmi_dev(dev);
 107
 108        if (!scmi_dev->handle)
 109                return -EPROBE_DEFER;
 110
 111        return scmi_drv->probe(scmi_dev);
 112}
 113
 114static void scmi_dev_remove(struct device *dev)
 115{
 116        struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
 117        struct scmi_device *scmi_dev = to_scmi_dev(dev);
 118
 119        if (scmi_drv->remove)
 120                scmi_drv->remove(scmi_dev);
 121}
 122
 123static struct bus_type scmi_bus_type = {
 124        .name = "scmi_protocol",
 125        .match = scmi_dev_match,
 126        .probe = scmi_dev_probe,
 127        .remove = scmi_dev_remove,
 128};
 129
 130int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
 131                         const char *mod_name)
 132{
 133        int retval;
 134
 135        if (!driver->probe)
 136                return -EINVAL;
 137
 138        retval = scmi_protocol_device_request(driver->id_table);
 139        if (retval)
 140                return retval;
 141
 142        driver->driver.bus = &scmi_bus_type;
 143        driver->driver.name = driver->name;
 144        driver->driver.owner = owner;
 145        driver->driver.mod_name = mod_name;
 146
 147        retval = driver_register(&driver->driver);
 148        if (!retval)
 149                pr_debug("registered new scmi driver %s\n", driver->name);
 150
 151        return retval;
 152}
 153EXPORT_SYMBOL_GPL(scmi_driver_register);
 154
 155void scmi_driver_unregister(struct scmi_driver *driver)
 156{
 157        driver_unregister(&driver->driver);
 158        scmi_protocol_device_unrequest(driver->id_table);
 159}
 160EXPORT_SYMBOL_GPL(scmi_driver_unregister);
 161
 162static void scmi_device_release(struct device *dev)
 163{
 164        kfree(to_scmi_dev(dev));
 165}
 166
 167struct scmi_device *
 168scmi_device_create(struct device_node *np, struct device *parent, int protocol,
 169                   const char *name)
 170{
 171        int id, retval;
 172        struct scmi_device *scmi_dev;
 173
 174        scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL);
 175        if (!scmi_dev)
 176                return NULL;
 177
 178        scmi_dev->name = kstrdup_const(name ?: "unknown", GFP_KERNEL);
 179        if (!scmi_dev->name) {
 180                kfree(scmi_dev);
 181                return NULL;
 182        }
 183
 184        id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
 185        if (id < 0) {
 186                kfree_const(scmi_dev->name);
 187                kfree(scmi_dev);
 188                return NULL;
 189        }
 190
 191        scmi_dev->id = id;
 192        scmi_dev->protocol_id = protocol;
 193        scmi_dev->dev.parent = parent;
 194        scmi_dev->dev.of_node = np;
 195        scmi_dev->dev.bus = &scmi_bus_type;
 196        scmi_dev->dev.release = scmi_device_release;
 197        dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id);
 198
 199        retval = device_register(&scmi_dev->dev);
 200        if (retval)
 201                goto put_dev;
 202
 203        return scmi_dev;
 204put_dev:
 205        kfree_const(scmi_dev->name);
 206        put_device(&scmi_dev->dev);
 207        ida_simple_remove(&scmi_bus_id, id);
 208        return NULL;
 209}
 210
 211void scmi_device_destroy(struct scmi_device *scmi_dev)
 212{
 213        kfree_const(scmi_dev->name);
 214        scmi_handle_put(scmi_dev->handle);
 215        ida_simple_remove(&scmi_bus_id, scmi_dev->id);
 216        device_unregister(&scmi_dev->dev);
 217}
 218
 219void scmi_set_handle(struct scmi_device *scmi_dev)
 220{
 221        scmi_dev->handle = scmi_handle_get(&scmi_dev->dev);
 222}
 223
 224int scmi_protocol_register(const struct scmi_protocol *proto)
 225{
 226        int ret;
 227
 228        if (!proto) {
 229                pr_err("invalid protocol\n");
 230                return -EINVAL;
 231        }
 232
 233        if (!proto->instance_init) {
 234                pr_err("missing init for protocol 0x%x\n", proto->id);
 235                return -EINVAL;
 236        }
 237
 238        spin_lock(&protocol_lock);
 239        ret = idr_alloc(&scmi_protocols, (void *)proto,
 240                        proto->id, proto->id + 1, GFP_ATOMIC);
 241        spin_unlock(&protocol_lock);
 242        if (ret != proto->id) {
 243                pr_err("unable to allocate SCMI idr slot for 0x%x - err %d\n",
 244                       proto->id, ret);
 245                return ret;
 246        }
 247
 248        pr_debug("Registered SCMI Protocol 0x%x\n", proto->id);
 249
 250        return 0;
 251}
 252EXPORT_SYMBOL_GPL(scmi_protocol_register);
 253
 254void scmi_protocol_unregister(const struct scmi_protocol *proto)
 255{
 256        spin_lock(&protocol_lock);
 257        idr_remove(&scmi_protocols, proto->id);
 258        spin_unlock(&protocol_lock);
 259
 260        pr_debug("Unregistered SCMI Protocol 0x%x\n", proto->id);
 261
 262        return;
 263}
 264EXPORT_SYMBOL_GPL(scmi_protocol_unregister);
 265
 266static int __scmi_devices_unregister(struct device *dev, void *data)
 267{
 268        struct scmi_device *scmi_dev = to_scmi_dev(dev);
 269
 270        scmi_device_destroy(scmi_dev);
 271        return 0;
 272}
 273
 274static void scmi_devices_unregister(void)
 275{
 276        bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
 277}
 278
 279int __init scmi_bus_init(void)
 280{
 281        int retval;
 282
 283        retval = bus_register(&scmi_bus_type);
 284        if (retval)
 285                pr_err("scmi protocol bus register failed (%d)\n", retval);
 286
 287        return retval;
 288}
 289
 290void __exit scmi_bus_exit(void)
 291{
 292        scmi_devices_unregister();
 293        bus_unregister(&scmi_bus_type);
 294        ida_destroy(&scmi_bus_id);
 295}
 296