]> Git Repo - linux.git/blob - drivers/firmware/arm_ffa/bus.c
ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn
[linux.git] / drivers / firmware / arm_ffa / bus.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 ARM Ltd.
4  */
5
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8 #include <linux/arm_ffa.h>
9 #include <linux/device.h>
10 #include <linux/fs.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/types.h>
15
16 #include "common.h"
17
18 #define SCMI_UEVENT_MODALIAS_FMT        "arm_ffa:%04x:%pUb"
19
20 static DEFINE_IDA(ffa_bus_id);
21
22 static int ffa_device_match(struct device *dev, const struct device_driver *drv)
23 {
24         const struct ffa_device_id *id_table;
25         struct ffa_device *ffa_dev;
26
27         id_table = to_ffa_driver(drv)->id_table;
28         ffa_dev = to_ffa_dev(dev);
29
30         while (!uuid_is_null(&id_table->uuid)) {
31                 /*
32                  * FF-A v1.0 doesn't provide discovery of UUIDs, just the
33                  * partition IDs, so match it unconditionally here and handle
34                  * it via the installed bus notifier during driver binding.
35                  */
36                 if (uuid_is_null(&ffa_dev->uuid))
37                         return 1;
38
39                 if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
40                         return 1;
41                 id_table++;
42         }
43
44         return 0;
45 }
46
47 static int ffa_device_probe(struct device *dev)
48 {
49         struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
50         struct ffa_device *ffa_dev = to_ffa_dev(dev);
51
52         /* UUID can be still NULL with FF-A v1.0, so just skip probing them */
53         if (uuid_is_null(&ffa_dev->uuid))
54                 return -ENODEV;
55
56         return ffa_drv->probe(ffa_dev);
57 }
58
59 static void ffa_device_remove(struct device *dev)
60 {
61         struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
62
63         if (ffa_drv->remove)
64                 ffa_drv->remove(to_ffa_dev(dev));
65 }
66
67 static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
68 {
69         const struct ffa_device *ffa_dev = to_ffa_dev(dev);
70
71         return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
72                               ffa_dev->vm_id, &ffa_dev->uuid);
73 }
74
75 static ssize_t modalias_show(struct device *dev,
76                              struct device_attribute *attr, char *buf)
77 {
78         struct ffa_device *ffa_dev = to_ffa_dev(dev);
79
80         return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
81                           &ffa_dev->uuid);
82 }
83 static DEVICE_ATTR_RO(modalias);
84
85 static ssize_t partition_id_show(struct device *dev,
86                                  struct device_attribute *attr, char *buf)
87 {
88         struct ffa_device *ffa_dev = to_ffa_dev(dev);
89
90         return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
91 }
92 static DEVICE_ATTR_RO(partition_id);
93
94 static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
95                          char *buf)
96 {
97         struct ffa_device *ffa_dev = to_ffa_dev(dev);
98
99         return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
100 }
101 static DEVICE_ATTR_RO(uuid);
102
103 static struct attribute *ffa_device_attributes_attrs[] = {
104         &dev_attr_partition_id.attr,
105         &dev_attr_uuid.attr,
106         &dev_attr_modalias.attr,
107         NULL,
108 };
109 ATTRIBUTE_GROUPS(ffa_device_attributes);
110
111 const struct bus_type ffa_bus_type = {
112         .name           = "arm_ffa",
113         .match          = ffa_device_match,
114         .probe          = ffa_device_probe,
115         .remove         = ffa_device_remove,
116         .uevent         = ffa_device_uevent,
117         .dev_groups     = ffa_device_attributes_groups,
118 };
119 EXPORT_SYMBOL_GPL(ffa_bus_type);
120
121 int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
122                         const char *mod_name)
123 {
124         int ret;
125
126         if (!driver->probe)
127                 return -EINVAL;
128
129         driver->driver.bus = &ffa_bus_type;
130         driver->driver.name = driver->name;
131         driver->driver.owner = owner;
132         driver->driver.mod_name = mod_name;
133
134         ret = driver_register(&driver->driver);
135         if (!ret)
136                 pr_debug("registered new ffa driver %s\n", driver->name);
137
138         return ret;
139 }
140 EXPORT_SYMBOL_GPL(ffa_driver_register);
141
142 void ffa_driver_unregister(struct ffa_driver *driver)
143 {
144         driver_unregister(&driver->driver);
145 }
146 EXPORT_SYMBOL_GPL(ffa_driver_unregister);
147
148 static void ffa_release_device(struct device *dev)
149 {
150         struct ffa_device *ffa_dev = to_ffa_dev(dev);
151
152         ida_free(&ffa_bus_id, ffa_dev->id);
153         kfree(ffa_dev);
154 }
155
156 static int __ffa_devices_unregister(struct device *dev, void *data)
157 {
158         device_unregister(dev);
159
160         return 0;
161 }
162
163 static void ffa_devices_unregister(void)
164 {
165         bus_for_each_dev(&ffa_bus_type, NULL, NULL,
166                          __ffa_devices_unregister);
167 }
168
169 bool ffa_device_is_valid(struct ffa_device *ffa_dev)
170 {
171         bool valid = false;
172         struct device *dev = NULL;
173         struct ffa_device *tmp_dev;
174
175         do {
176                 dev = bus_find_next_device(&ffa_bus_type, dev);
177                 tmp_dev = to_ffa_dev(dev);
178                 if (tmp_dev == ffa_dev) {
179                         valid = true;
180                         break;
181                 }
182                 put_device(dev);
183         } while (dev);
184
185         put_device(dev);
186
187         return valid;
188 }
189
190 struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
191                                        const struct ffa_ops *ops)
192 {
193         int id, ret;
194         struct device *dev;
195         struct ffa_device *ffa_dev;
196
197         id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL);
198         if (id < 0)
199                 return NULL;
200
201         ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
202         if (!ffa_dev) {
203                 ida_free(&ffa_bus_id, id);
204                 return NULL;
205         }
206
207         dev = &ffa_dev->dev;
208         dev->bus = &ffa_bus_type;
209         dev->release = ffa_release_device;
210         dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
211
212         ffa_dev->id = id;
213         ffa_dev->vm_id = vm_id;
214         ffa_dev->ops = ops;
215         uuid_copy(&ffa_dev->uuid, uuid);
216
217         ret = device_register(&ffa_dev->dev);
218         if (ret) {
219                 dev_err(dev, "unable to register device %s err=%d\n",
220                         dev_name(dev), ret);
221                 put_device(dev);
222                 return NULL;
223         }
224
225         return ffa_dev;
226 }
227 EXPORT_SYMBOL_GPL(ffa_device_register);
228
229 void ffa_device_unregister(struct ffa_device *ffa_dev)
230 {
231         if (!ffa_dev)
232                 return;
233
234         device_unregister(&ffa_dev->dev);
235 }
236 EXPORT_SYMBOL_GPL(ffa_device_unregister);
237
238 static int __init arm_ffa_bus_init(void)
239 {
240         return bus_register(&ffa_bus_type);
241 }
242 subsys_initcall(arm_ffa_bus_init);
243
244 static void __exit arm_ffa_bus_exit(void)
245 {
246         ffa_devices_unregister();
247         bus_unregister(&ffa_bus_type);
248         ida_destroy(&ffa_bus_id);
249 }
250 module_exit(arm_ffa_bus_exit);
251
252 MODULE_ALIAS("ffa-core");
253 MODULE_AUTHOR("Sudeep Holla <[email protected]>");
254 MODULE_DESCRIPTION("ARM FF-A bus");
255 MODULE_LICENSE("GPL");
This page took 0.046797 seconds and 4 git commands to generate.