Skip to content

Commit 5e619b4

Browse files
committed
rpmsg: Split rpmsg core and virtio backend
Extract the generic rpmsg core functionality from the virtio rpmsg implementation, splitting the implementation in a rpmsg core and a virtio backend. Based on initial work by Sricharan R <[email protected]> Cc: Sricharan R <[email protected]> Signed-off-by: Bjorn Andersson <[email protected]>
1 parent 6eed598 commit 5e619b4

File tree

3 files changed

+237
-223
lines changed

3 files changed

+237
-223
lines changed

drivers/rpmsg/rpmsg_core.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,234 @@ struct device *rpmsg_find_device(struct device *parent,
262262

263263
}
264264
EXPORT_SYMBOL(rpmsg_find_device);
265+
266+
/* sysfs show configuration fields */
267+
#define rpmsg_show_attr(field, path, format_string) \
268+
static ssize_t \
269+
field##_show(struct device *dev, \
270+
struct device_attribute *attr, char *buf) \
271+
{ \
272+
struct rpmsg_device *rpdev = to_rpmsg_device(dev); \
273+
\
274+
return sprintf(buf, format_string, rpdev->path); \
275+
}
276+
277+
/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
278+
rpmsg_show_attr(name, id.name, "%s\n");
279+
rpmsg_show_attr(src, src, "0x%x\n");
280+
rpmsg_show_attr(dst, dst, "0x%x\n");
281+
rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
282+
283+
static ssize_t modalias_show(struct device *dev,
284+
struct device_attribute *attr, char *buf)
285+
{
286+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
287+
288+
return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
289+
}
290+
291+
static struct device_attribute rpmsg_dev_attrs[] = {
292+
__ATTR_RO(name),
293+
__ATTR_RO(modalias),
294+
__ATTR_RO(dst),
295+
__ATTR_RO(src),
296+
__ATTR_RO(announce),
297+
__ATTR_NULL
298+
};
299+
300+
/* rpmsg devices and drivers are matched using the service name */
301+
static inline int rpmsg_id_match(const struct rpmsg_device *rpdev,
302+
const struct rpmsg_device_id *id)
303+
{
304+
return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
305+
}
306+
307+
/* match rpmsg channel and rpmsg driver */
308+
static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
309+
{
310+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
311+
struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
312+
const struct rpmsg_device_id *ids = rpdrv->id_table;
313+
unsigned int i;
314+
315+
if (ids)
316+
for (i = 0; ids[i].name[0]; i++)
317+
if (rpmsg_id_match(rpdev, &ids[i]))
318+
return 1;
319+
320+
return of_driver_match_device(dev, drv);
321+
}
322+
323+
static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
324+
{
325+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
326+
327+
return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
328+
rpdev->id.name);
329+
}
330+
331+
/*
332+
* when an rpmsg driver is probed with a channel, we seamlessly create
333+
* it an endpoint, binding its rx callback to a unique local rpmsg
334+
* address.
335+
*
336+
* if we need to, we also announce about this channel to the remote
337+
* processor (needed in case the driver is exposing an rpmsg service).
338+
*/
339+
static int rpmsg_dev_probe(struct device *dev)
340+
{
341+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
342+
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
343+
struct rpmsg_channel_info chinfo = {};
344+
struct rpmsg_endpoint *ept;
345+
int err;
346+
347+
strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
348+
chinfo.src = rpdev->src;
349+
chinfo.dst = RPMSG_ADDR_ANY;
350+
351+
ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
352+
if (!ept) {
353+
dev_err(dev, "failed to create endpoint\n");
354+
err = -ENOMEM;
355+
goto out;
356+
}
357+
358+
rpdev->ept = ept;
359+
rpdev->src = ept->addr;
360+
361+
err = rpdrv->probe(rpdev);
362+
if (err) {
363+
dev_err(dev, "%s: failed: %d\n", __func__, err);
364+
rpmsg_destroy_ept(ept);
365+
goto out;
366+
}
367+
368+
if (rpdev->ops->announce_create)
369+
err = rpdev->ops->announce_create(rpdev);
370+
out:
371+
return err;
372+
}
373+
374+
static int rpmsg_dev_remove(struct device *dev)
375+
{
376+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
377+
struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
378+
int err = 0;
379+
380+
if (rpdev->ops->announce_destroy)
381+
err = rpdev->ops->announce_destroy(rpdev);
382+
383+
rpdrv->remove(rpdev);
384+
385+
rpmsg_destroy_ept(rpdev->ept);
386+
387+
return err;
388+
}
389+
390+
static struct bus_type rpmsg_bus = {
391+
.name = "rpmsg",
392+
.match = rpmsg_dev_match,
393+
.dev_attrs = rpmsg_dev_attrs,
394+
.uevent = rpmsg_uevent,
395+
.probe = rpmsg_dev_probe,
396+
.remove = rpmsg_dev_remove,
397+
};
398+
399+
static void rpmsg_release_device(struct device *dev)
400+
{
401+
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
402+
403+
kfree(rpdev);
404+
}
405+
406+
int rpmsg_register_device(struct rpmsg_device *rpdev)
407+
{
408+
struct device *dev = &rpdev->dev;
409+
int ret;
410+
411+
dev_set_name(&rpdev->dev, "%s:%s",
412+
dev_name(dev->parent), rpdev->id.name);
413+
414+
rpdev->dev.bus = &rpmsg_bus;
415+
rpdev->dev.release = rpmsg_release_device;
416+
417+
ret = device_register(&rpdev->dev);
418+
if (ret) {
419+
dev_err(dev, "device_register failed: %d\n", ret);
420+
put_device(&rpdev->dev);
421+
}
422+
423+
return ret;
424+
}
425+
EXPORT_SYMBOL(rpmsg_register_device);
426+
427+
/*
428+
* find an existing channel using its name + address properties,
429+
* and destroy it
430+
*/
431+
int rpmsg_unregister_device(struct device *parent,
432+
struct rpmsg_channel_info *chinfo)
433+
{
434+
struct device *dev;
435+
436+
dev = rpmsg_find_device(parent, chinfo);
437+
if (!dev)
438+
return -EINVAL;
439+
440+
device_unregister(dev);
441+
442+
put_device(dev);
443+
444+
return 0;
445+
}
446+
EXPORT_SYMBOL(rpmsg_unregister_device);
447+
448+
/**
449+
* __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
450+
* @rpdrv: pointer to a struct rpmsg_driver
451+
* @owner: owning module/driver
452+
*
453+
* Returns 0 on success, and an appropriate error value on failure.
454+
*/
455+
int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner)
456+
{
457+
rpdrv->drv.bus = &rpmsg_bus;
458+
rpdrv->drv.owner = owner;
459+
return driver_register(&rpdrv->drv);
460+
}
461+
EXPORT_SYMBOL(__register_rpmsg_driver);
462+
463+
/**
464+
* unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
465+
* @rpdrv: pointer to a struct rpmsg_driver
466+
*
467+
* Returns 0 on success, and an appropriate error value on failure.
468+
*/
469+
void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
470+
{
471+
driver_unregister(&rpdrv->drv);
472+
}
473+
EXPORT_SYMBOL(unregister_rpmsg_driver);
474+
475+
476+
static int __init rpmsg_init(void)
477+
{
478+
int ret;
479+
480+
ret = bus_register(&rpmsg_bus);
481+
if (ret)
482+
pr_err("failed to register rpmsg bus: %d\n", ret);
483+
484+
return ret;
485+
}
486+
postcore_initcall(rpmsg_init);
487+
488+
static void __exit rpmsg_fini(void)
489+
{
490+
bus_unregister(&rpmsg_bus);
491+
}
492+
module_exit(rpmsg_fini);
493+
494+
MODULE_DESCRIPTION("remote processor messaging bus");
495+
MODULE_LICENSE("GPL v2");

drivers/rpmsg/rpmsg_internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)
2626
#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
2727

28+
int rpmsg_register_device(struct rpmsg_device *rpdev);
29+
int rpmsg_unregister_device(struct device *parent,
30+
struct rpmsg_channel_info *chinfo);
31+
2832
struct device *rpmsg_find_device(struct device *parent,
2933
struct rpmsg_channel_info *chinfo);
3034

0 commit comments

Comments
 (0)