Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus Host Device
0004  *
0005  * Copyright 2014-2015 Google Inc.
0006  * Copyright 2014-2015 Linaro Ltd.
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011 #include <linux/greybus.h>
0012 
0013 #include "greybus_trace.h"
0014 
0015 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_create);
0016 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_release);
0017 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_add);
0018 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_del);
0019 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_hd_in);
0020 EXPORT_TRACEPOINT_SYMBOL_GPL(gb_message_submit);
0021 
0022 static struct ida gb_hd_bus_id_map;
0023 
0024 int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
0025          bool async)
0026 {
0027     if (!hd || !hd->driver || !hd->driver->output)
0028         return -EINVAL;
0029     return hd->driver->output(hd, req, size, cmd, async);
0030 }
0031 EXPORT_SYMBOL_GPL(gb_hd_output);
0032 
0033 static ssize_t bus_id_show(struct device *dev,
0034                struct device_attribute *attr, char *buf)
0035 {
0036     struct gb_host_device *hd = to_gb_host_device(dev);
0037 
0038     return sprintf(buf, "%d\n", hd->bus_id);
0039 }
0040 static DEVICE_ATTR_RO(bus_id);
0041 
0042 static struct attribute *bus_attrs[] = {
0043     &dev_attr_bus_id.attr,
0044     NULL
0045 };
0046 ATTRIBUTE_GROUPS(bus);
0047 
0048 int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id)
0049 {
0050     struct ida *id_map = &hd->cport_id_map;
0051     int ret;
0052 
0053     ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL);
0054     if (ret < 0) {
0055         dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id);
0056         return ret;
0057     }
0058 
0059     return 0;
0060 }
0061 EXPORT_SYMBOL_GPL(gb_hd_cport_reserve);
0062 
0063 void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id)
0064 {
0065     struct ida *id_map = &hd->cport_id_map;
0066 
0067     ida_simple_remove(id_map, cport_id);
0068 }
0069 EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved);
0070 
0071 /* Locking: Caller guarantees serialisation */
0072 int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
0073              unsigned long flags)
0074 {
0075     struct ida *id_map = &hd->cport_id_map;
0076     int ida_start, ida_end;
0077 
0078     if (hd->driver->cport_allocate)
0079         return hd->driver->cport_allocate(hd, cport_id, flags);
0080 
0081     if (cport_id < 0) {
0082         ida_start = 0;
0083         ida_end = hd->num_cports;
0084     } else if (cport_id < hd->num_cports) {
0085         ida_start = cport_id;
0086         ida_end = cport_id + 1;
0087     } else {
0088         dev_err(&hd->dev, "cport %d not available\n", cport_id);
0089         return -EINVAL;
0090     }
0091 
0092     return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
0093 }
0094 
0095 /* Locking: Caller guarantees serialisation */
0096 void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id)
0097 {
0098     if (hd->driver->cport_release) {
0099         hd->driver->cport_release(hd, cport_id);
0100         return;
0101     }
0102 
0103     ida_simple_remove(&hd->cport_id_map, cport_id);
0104 }
0105 
0106 static void gb_hd_release(struct device *dev)
0107 {
0108     struct gb_host_device *hd = to_gb_host_device(dev);
0109 
0110     trace_gb_hd_release(hd);
0111 
0112     if (hd->svc)
0113         gb_svc_put(hd->svc);
0114     ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
0115     ida_destroy(&hd->cport_id_map);
0116     kfree(hd);
0117 }
0118 
0119 struct device_type greybus_hd_type = {
0120     .name       = "greybus_host_device",
0121     .release    = gb_hd_release,
0122 };
0123 
0124 struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
0125                     struct device *parent,
0126                     size_t buffer_size_max,
0127                     size_t num_cports)
0128 {
0129     struct gb_host_device *hd;
0130     int ret;
0131 
0132     /*
0133      * Validate that the driver implements all of the callbacks
0134      * so that we don't have to every time we make them.
0135      */
0136     if ((!driver->message_send) || (!driver->message_cancel)) {
0137         dev_err(parent, "mandatory hd-callbacks missing\n");
0138         return ERR_PTR(-EINVAL);
0139     }
0140 
0141     if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
0142         dev_err(parent, "greybus host-device buffers too small\n");
0143         return ERR_PTR(-EINVAL);
0144     }
0145 
0146     if (num_cports == 0 || num_cports > CPORT_ID_MAX + 1) {
0147         dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports);
0148         return ERR_PTR(-EINVAL);
0149     }
0150 
0151     /*
0152      * Make sure to never allocate messages larger than what the Greybus
0153      * protocol supports.
0154      */
0155     if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
0156         dev_warn(parent, "limiting buffer size to %u\n",
0157              GB_OPERATION_MESSAGE_SIZE_MAX);
0158         buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
0159     }
0160 
0161     hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
0162     if (!hd)
0163         return ERR_PTR(-ENOMEM);
0164 
0165     ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
0166     if (ret < 0) {
0167         kfree(hd);
0168         return ERR_PTR(ret);
0169     }
0170     hd->bus_id = ret;
0171 
0172     hd->driver = driver;
0173     INIT_LIST_HEAD(&hd->modules);
0174     INIT_LIST_HEAD(&hd->connections);
0175     ida_init(&hd->cport_id_map);
0176     hd->buffer_size_max = buffer_size_max;
0177     hd->num_cports = num_cports;
0178 
0179     hd->dev.parent = parent;
0180     hd->dev.bus = &greybus_bus_type;
0181     hd->dev.type = &greybus_hd_type;
0182     hd->dev.groups = bus_groups;
0183     hd->dev.dma_mask = hd->dev.parent->dma_mask;
0184     device_initialize(&hd->dev);
0185     dev_set_name(&hd->dev, "greybus%d", hd->bus_id);
0186 
0187     trace_gb_hd_create(hd);
0188 
0189     hd->svc = gb_svc_create(hd);
0190     if (!hd->svc) {
0191         dev_err(&hd->dev, "failed to create svc\n");
0192         put_device(&hd->dev);
0193         return ERR_PTR(-ENOMEM);
0194     }
0195 
0196     return hd;
0197 }
0198 EXPORT_SYMBOL_GPL(gb_hd_create);
0199 
0200 int gb_hd_add(struct gb_host_device *hd)
0201 {
0202     int ret;
0203 
0204     ret = device_add(&hd->dev);
0205     if (ret)
0206         return ret;
0207 
0208     ret = gb_svc_add(hd->svc);
0209     if (ret) {
0210         device_del(&hd->dev);
0211         return ret;
0212     }
0213 
0214     trace_gb_hd_add(hd);
0215 
0216     return 0;
0217 }
0218 EXPORT_SYMBOL_GPL(gb_hd_add);
0219 
0220 void gb_hd_del(struct gb_host_device *hd)
0221 {
0222     trace_gb_hd_del(hd);
0223 
0224     /*
0225      * Tear down the svc and flush any on-going hotplug processing before
0226      * removing the remaining interfaces.
0227      */
0228     gb_svc_del(hd->svc);
0229 
0230     device_del(&hd->dev);
0231 }
0232 EXPORT_SYMBOL_GPL(gb_hd_del);
0233 
0234 void gb_hd_shutdown(struct gb_host_device *hd)
0235 {
0236     gb_svc_del(hd->svc);
0237 }
0238 EXPORT_SYMBOL_GPL(gb_hd_shutdown);
0239 
0240 void gb_hd_put(struct gb_host_device *hd)
0241 {
0242     put_device(&hd->dev);
0243 }
0244 EXPORT_SYMBOL_GPL(gb_hd_put);
0245 
0246 int __init gb_hd_init(void)
0247 {
0248     ida_init(&gb_hd_bus_id_map);
0249 
0250     return 0;
0251 }
0252 
0253 void gb_hd_exit(void)
0254 {
0255     ida_destroy(&gb_hd_bus_id_map);
0256 }