m68k: Fix asm register constraints for atomic ops
[sfrench/cifs-2.6.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 static int ffa_device_match(struct device *dev, struct device_driver *drv)
19 {
20         const struct ffa_device_id *id_table;
21         struct ffa_device *ffa_dev;
22
23         id_table = to_ffa_driver(drv)->id_table;
24         ffa_dev = to_ffa_dev(dev);
25
26         while (!uuid_is_null(&id_table->uuid)) {
27                 /*
28                  * FF-A v1.0 doesn't provide discovery of UUIDs, just the
29                  * partition IDs, so fetch the partitions IDs for this
30                  * id_table UUID and assign the UUID to the device if the
31                  * partition ID matches
32                  */
33                 if (uuid_is_null(&ffa_dev->uuid))
34                         ffa_device_match_uuid(ffa_dev, &id_table->uuid);
35
36                 if (uuid_equal(&ffa_dev->uuid, &id_table->uuid))
37                         return 1;
38                 id_table++;
39         }
40
41         return 0;
42 }
43
44 static int ffa_device_probe(struct device *dev)
45 {
46         struct ffa_driver *ffa_drv = to_ffa_driver(dev->driver);
47         struct ffa_device *ffa_dev = to_ffa_dev(dev);
48
49         if (!ffa_device_match(dev, dev->driver))
50                 return -ENODEV;
51
52         return ffa_drv->probe(ffa_dev);
53 }
54
55 static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env)
56 {
57         struct ffa_device *ffa_dev = to_ffa_dev(dev);
58
59         return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
60                               ffa_dev->vm_id, &ffa_dev->uuid);
61 }
62
63 static ssize_t partition_id_show(struct device *dev,
64                                  struct device_attribute *attr, char *buf)
65 {
66         struct ffa_device *ffa_dev = to_ffa_dev(dev);
67
68         return sprintf(buf, "0x%04x\n", ffa_dev->vm_id);
69 }
70 static DEVICE_ATTR_RO(partition_id);
71
72 static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
73                          char *buf)
74 {
75         struct ffa_device *ffa_dev = to_ffa_dev(dev);
76
77         return sprintf(buf, "%pUb\n", &ffa_dev->uuid);
78 }
79 static DEVICE_ATTR_RO(uuid);
80
81 static struct attribute *ffa_device_attributes_attrs[] = {
82         &dev_attr_partition_id.attr,
83         &dev_attr_uuid.attr,
84         NULL,
85 };
86 ATTRIBUTE_GROUPS(ffa_device_attributes);
87
88 struct bus_type ffa_bus_type = {
89         .name           = "arm_ffa",
90         .match          = ffa_device_match,
91         .probe          = ffa_device_probe,
92         .uevent         = ffa_device_uevent,
93         .dev_groups     = ffa_device_attributes_groups,
94 };
95 EXPORT_SYMBOL_GPL(ffa_bus_type);
96
97 int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
98                         const char *mod_name)
99 {
100         int ret;
101
102         driver->driver.bus = &ffa_bus_type;
103         driver->driver.name = driver->name;
104         driver->driver.owner = owner;
105         driver->driver.mod_name = mod_name;
106
107         ret = driver_register(&driver->driver);
108         if (!ret)
109                 pr_debug("registered new ffa driver %s\n", driver->name);
110
111         return ret;
112 }
113 EXPORT_SYMBOL_GPL(ffa_driver_register);
114
115 void ffa_driver_unregister(struct ffa_driver *driver)
116 {
117         driver_unregister(&driver->driver);
118 }
119 EXPORT_SYMBOL_GPL(ffa_driver_unregister);
120
121 static void ffa_release_device(struct device *dev)
122 {
123         struct ffa_device *ffa_dev = to_ffa_dev(dev);
124
125         kfree(ffa_dev);
126 }
127
128 static int __ffa_devices_unregister(struct device *dev, void *data)
129 {
130         ffa_release_device(dev);
131
132         return 0;
133 }
134
135 static void ffa_devices_unregister(void)
136 {
137         bus_for_each_dev(&ffa_bus_type, NULL, NULL,
138                          __ffa_devices_unregister);
139 }
140
141 bool ffa_device_is_valid(struct ffa_device *ffa_dev)
142 {
143         bool valid = false;
144         struct device *dev = NULL;
145         struct ffa_device *tmp_dev;
146
147         do {
148                 dev = bus_find_next_device(&ffa_bus_type, dev);
149                 tmp_dev = to_ffa_dev(dev);
150                 if (tmp_dev == ffa_dev) {
151                         valid = true;
152                         break;
153                 }
154                 put_device(dev);
155         } while (dev);
156
157         put_device(dev);
158
159         return valid;
160 }
161
162 struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id)
163 {
164         int ret;
165         struct device *dev;
166         struct ffa_device *ffa_dev;
167
168         ffa_dev = kzalloc(sizeof(*ffa_dev), GFP_KERNEL);
169         if (!ffa_dev)
170                 return NULL;
171
172         dev = &ffa_dev->dev;
173         dev->bus = &ffa_bus_type;
174         dev->release = ffa_release_device;
175         dev_set_name(&ffa_dev->dev, "arm-ffa-%04x", vm_id);
176
177         ffa_dev->vm_id = vm_id;
178         uuid_copy(&ffa_dev->uuid, uuid);
179
180         ret = device_register(&ffa_dev->dev);
181         if (ret) {
182                 dev_err(dev, "unable to register device %s err=%d\n",
183                         dev_name(dev), ret);
184                 put_device(dev);
185                 return NULL;
186         }
187
188         return ffa_dev;
189 }
190 EXPORT_SYMBOL_GPL(ffa_device_register);
191
192 void ffa_device_unregister(struct ffa_device *ffa_dev)
193 {
194         if (!ffa_dev)
195                 return;
196
197         device_unregister(&ffa_dev->dev);
198 }
199 EXPORT_SYMBOL_GPL(ffa_device_unregister);
200
201 int arm_ffa_bus_init(void)
202 {
203         return bus_register(&ffa_bus_type);
204 }
205
206 void arm_ffa_bus_exit(void)
207 {
208         ffa_devices_unregister();
209         bus_unregister(&ffa_bus_type);
210 }