0001
0002
0003
0004
0005
0006
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
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
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
0134
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
0153
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
0226
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 }