Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 15052C54EAA for ; Sun, 22 Jan 2023 23:51:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230344AbjAVXvK (ORCPT ); Sun, 22 Jan 2023 18:51:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55660 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229990AbjAVXvI (ORCPT ); Sun, 22 Jan 2023 18:51:08 -0500 Received: from mout.kundenserver.de (mout.kundenserver.de [212.227.126.130]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 102941351B; Sun, 22 Jan 2023 15:51:05 -0800 (PST) Received: from [192.168.1.141] ([37.4.248.41]) by mrelayeu.kundenserver.de (mreue009 [212.227.15.167]) with ESMTPSA (Nemesis) id 1McY0L-1ogpK01CE1-00d2rb; Mon, 23 Jan 2023 00:50:49 +0100 Message-ID: <4a609f3c-1153-124a-ed94-90c05a87285f@i2se.com> Date: Mon, 23 Jan 2023 00:50:46 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 Subject: Re: [PATCH v6 6/6] staging: vc04_services: vchiq: Register devices with a custom bus_type Content-Language: en-US To: Umang Jain , linux-staging@lists.linux.dev, linux-rpi-kernel@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , Florian Fainelli , Adrien Thierry , Dan Carpenter , Dave Stevenson , Kieran Bingham , Laurent Pinchart , Paul Elder References: <20230120201104.606876-1-umang.jain@ideasonboard.com> <20230120201104.606876-7-umang.jain@ideasonboard.com> From: Stefan Wahren In-Reply-To: <20230120201104.606876-7-umang.jain@ideasonboard.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Provags-ID: V03:K1:iEzmCp1rbWF/cGR3w375qN2Wbv5TZMoIgVOhGmG43vkdxEitf1P Ay+xY7+HNl2hq2OloqUDWIA8EWrSO9xUe6jvfbvF5uSFuPqzon/DRG9SkwjYVOPXt9mqr6C r6fvKSvHv+3KOqQVYcfY5nUgUlEc30xh+5crJqxp51PCxqocnjMgjeTAuptExIrkGsTJgwC 90DPLxLy7yx//61QfSVUg== UI-OutboundReport: notjunk:1;M01:P0:+M6vUNInQ8I=;c4/OLedLCcqMm8DIRW99zQQpyVq X1eBW3/GzTqzdoawEVdU1nPgJPi0G+58e0tgYnpOaE4fdK7/aolnyk6YrLsrroLWnr/sjojX5 z7illeHUQTiWIiCuzDB7m4b2fn2bbKz++0DVxgys4DYloK0MU986EKMmVLGYP/leRTH1et1+O Be/WjElCvdGRDaJQidPJc70s0ZV2hI91OaSK0Rg50z/fyPzJpBzXt+SJg0ICUUqFamvfHd/qI HQX//QPiU5iNQfsVUkejrVPdhevFbGkcAg7f/zgWbUGt9ee1oKg+UASmtEOB2VYbcswuW+5Gw 2NHjqKQ3XiFdmtdjT4Xioc2cUmE+QqiCS1FOh12vQ2kSxRrdm8tcGoWQqWlpjJ86LyoqbLtAK r/yvI1chwx+mJnOKSyFK6IwM85I4rvqzX848kIVuddsIcSCUvqr7xQFOfJK+tOERO2ndK8X8b tlErO8ChI6bt+KorVTAqFcpbAT5n2de/7g5kjY8dCm/B4fT3qpSwJtjt7NO7en7YkthmXJhl4 eN1PtKrlE34qS18iASSw5qFnvGUdsmrIVfdeqXQ54dIj4VQtgo0LrAJtTEFlDKDaU7rGN66Ud jY3CMKYQsIzTwm8UV8PUjodUjKnlQS//faowSeZ3EgjB+15JZ0vp534T43HT7bpD03lkWOtjk qYDZ+mmhX+UAh6ME0Q71AGsTV3GzDYUVhPRh06qyHg== Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Umang, Am 20.01.23 um 21:11 schrieb Umang Jain: > The devices that the vchiq interface registers (bcm2835-audio, > bcm2835-camera) are implemented and exposed by the VC04 firmware. > The device tree describes the VC04 itself with the resources required > to communicate with it through a mailbox interface. However, the > vchiq interface registers these devices as platform devices. This > also means the specific drivers for these devices are getting > registered as platform drivers. This is not correct and a blatant > abuse of platform device/driver. > > Replace the platform device/driver model with a standard device driver > model. A custom bus_type, vchiq_bus_type, is created in the vchiq > interface which matches the devices to their specific device drivers > thereby, establishing driver binding. A struct vchiq_device wraps the > struct device for each device being registered on the bus by the vchiq > interface. On the other hand, struct vchiq_driver wraps the struct > device_driver and the module_vchiq_driver() macro is provided for the > driver registration. > > Each device registered will expose a 'name' read-only device attribute > in sysfs (/sys/bus/vchiq-bus/devices). New devices and drivers can be > added by registering on vchiq_bus_type and adding a corresponding > device name entry in the static list of devices, vchiq_devices. There > is currently no way to enumerate the VCHIQ devices that are available > from the firmware. > > Signed-off-by: Umang Jain > --- > drivers/staging/vc04_services/Makefile | 1 + > .../vc04_services/bcm2835-audio/bcm2835.c | 27 +++-- > .../bcm2835-camera/bcm2835-camera.c | 25 ++--- > .../interface/vchiq_arm/vchiq_arm.c | 52 +++++---- > .../interface/vchiq_arm/vchiq_device.c | 102 ++++++++++++++++++ > .../interface/vchiq_arm/vchiq_device.h | 39 +++++++ > 6 files changed, 192 insertions(+), 54 deletions(-) > create mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.c > create mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.h > > diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile > index 44794bdf6173..2d071e55e175 100644 > --- a/drivers/staging/vc04_services/Makefile > +++ b/drivers/staging/vc04_services/Makefile > @@ -5,6 +5,7 @@ vchiq-objs := \ > interface/vchiq_arm/vchiq_core.o \ > interface/vchiq_arm/vchiq_arm.o \ > interface/vchiq_arm/vchiq_debugfs.o \ > + interface/vchiq_arm/vchiq_device.o \ > interface/vchiq_arm/vchiq_connected.o \ > > ifdef CONFIG_VCHIQ_CDEV > diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c > index 00bc898b0189..05118dafe62d 100644 > --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c > +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c > @@ -1,12 +1,12 @@ > // SPDX-License-Identifier: GPL-2.0 > /* Copyright 2011 Broadcom Corporation. All rights reserved. */ > > -#include > - > #include > #include > #include > > +#include "../interface/vchiq_arm/vchiq_arm.h" > +#include "../interface/vchiq_arm/vchiq_device.h" > #include "bcm2835.h" > > static bool enable_hdmi; > @@ -268,9 +268,8 @@ static int snd_add_child_devices(struct device *device, u32 numchans) > return 0; > } > > -static int snd_bcm2835_alsa_probe(struct platform_device *pdev) > +static int snd_bcm2835_alsa_probe(struct device *dev) > { > - struct device *dev = &pdev->dev; > int err; > > if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) { > @@ -292,32 +291,32 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) > > #ifdef CONFIG_PM > > -static int snd_bcm2835_alsa_suspend(struct platform_device *pdev, > +static int snd_bcm2835_alsa_suspend(struct device *pdev, > pm_message_t state) > { > return 0; > } > > -static int snd_bcm2835_alsa_resume(struct platform_device *pdev) > +static int snd_bcm2835_alsa_resume(struct device *pdev) > { > return 0; > } > > #endif > > -static struct platform_driver bcm2835_alsa_driver = { > - .probe = snd_bcm2835_alsa_probe, > +static struct vchiq_driver bcm2835_alsa_driver = { > + .driver = { > + .probe = snd_bcm2835_alsa_probe, > #ifdef CONFIG_PM > - .suspend = snd_bcm2835_alsa_suspend, > - .resume = snd_bcm2835_alsa_resume, > + .suspend = snd_bcm2835_alsa_suspend, > + .resume = snd_bcm2835_alsa_resume, > #endif > - .driver = { > .name = "bcm2835_audio", > - }, > + } > }; > -module_platform_driver(bcm2835_alsa_driver); > +module_vchiq_driver(bcm2835_alsa_driver); > > MODULE_AUTHOR("Dom Cobley"); > MODULE_DESCRIPTION("Alsa driver for BCM2835 chip"); > MODULE_LICENSE("GPL"); > -MODULE_ALIAS("platform:bcm2835_audio"); > +MODULE_ALIAS("bcm2835_audio"); > diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c > index 4f81765912ea..57f053de53b9 100644 > --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c > +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c > @@ -24,8 +24,9 @@ > #include > #include > #include > -#include > > +#include "../interface/vchiq_arm/vchiq_arm.h" > +#include "../interface/vchiq_arm/vchiq_device.h" > #include "../vchiq-mmal/mmal-common.h" > #include "../vchiq-mmal/mmal-encodings.h" > #include "../vchiq-mmal/mmal-vchiq.h" > @@ -1841,7 +1842,7 @@ static struct v4l2_format default_v4l2_format = { > .fmt.pix.sizeimage = 1024 * 768, > }; > > -static int bcm2835_mmal_probe(struct platform_device *pdev) > +static int bcm2835_mmal_probe(struct device *device) > { > int ret; > struct bcm2835_mmal_dev *dev; > @@ -1896,7 +1897,7 @@ static int bcm2835_mmal_probe(struct platform_device *pdev) > &camera_instance); > ret = v4l2_device_register(NULL, &dev->v4l2_dev); > if (ret) { > - dev_err(&pdev->dev, "%s: could not register V4L2 device: %d\n", > + dev_err(device, "%s: could not register V4L2 device: %d\n", > __func__, ret); > goto free_dev; > } > @@ -1976,7 +1977,7 @@ static int bcm2835_mmal_probe(struct platform_device *pdev) > return ret; > } > > -static int bcm2835_mmal_remove(struct platform_device *pdev) > +static int bcm2835_mmal_remove(struct device *device) > { > int camera; > struct vchiq_mmal_instance *instance = gdev[0]->instance; > @@ -1990,17 +1991,17 @@ static int bcm2835_mmal_remove(struct platform_device *pdev) > return 0; > } > > -static struct platform_driver bcm2835_camera_driver = { > - .probe = bcm2835_mmal_probe, > - .remove = bcm2835_mmal_remove, > - .driver = { > - .name = "bcm2835-camera", > - }, > +static struct vchiq_driver bcm2835_camera_driver = { > + .driver = { > + .name = "bcm2835-camera", > + .probe = bcm2835_mmal_probe, > + .remove = bcm2835_mmal_remove, > + } > }; > > -module_platform_driver(bcm2835_camera_driver) > +module_vchiq_driver(bcm2835_camera_driver) > > MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture"); > MODULE_AUTHOR("Vincent Sanders"); > MODULE_LICENSE("GPL"); > -MODULE_ALIAS("platform:bcm2835-camera"); > +MODULE_ALIAS("bcm2835-camera"); > diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c > index 22de23f3af02..4a57ff760106 100644 > --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c > +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c > @@ -12,6 +12,8 @@ > #include > #include > #include > +#include > +#include > #include > #include > #include > @@ -34,6 +36,7 @@ > #include "vchiq_ioctl.h" > #include "vchiq_arm.h" > #include "vchiq_debugfs.h" > +#include "vchiq_device.h" > #include "vchiq_connected.h" > #include "vchiq_pagelist.h" > > @@ -65,9 +68,6 @@ int vchiq_susp_log_level = VCHIQ_LOG_ERROR; > DEFINE_SPINLOCK(msg_queue_spinlock); > struct vchiq_state g_state; > > -static struct platform_device *bcm2835_camera; > -static struct platform_device *bcm2835_audio; > - > struct vchiq_drvdata { > const unsigned int cache_line_size; > struct rpi_firmware *fw; > @@ -132,6 +132,11 @@ struct vchiq_pagelist_info { > unsigned int scatterlist_mapped; > }; > > +static const char *const vchiq_devices[] = { > + "bcm2835_audio", > + "bcm2835-camera", > +}; > + > static void __iomem *g_regs; > /* This value is the size of the L2 cache lines as understood by the > * VPU firmware, which determines the required alignment of the > @@ -1763,33 +1768,13 @@ static const struct of_device_id vchiq_of_match[] = { > }; > MODULE_DEVICE_TABLE(of, vchiq_of_match); > > -static struct platform_device * > -vchiq_register_child(struct platform_device *pdev, const char *name) > -{ > - struct platform_device_info pdevinfo; > - struct platform_device *child; > - > - memset(&pdevinfo, 0, sizeof(pdevinfo)); > - > - pdevinfo.parent = &pdev->dev; > - pdevinfo.name = name; > - pdevinfo.id = PLATFORM_DEVID_NONE; > - pdevinfo.dma_mask = DMA_BIT_MASK(32); > - > - child = platform_device_register_full(&pdevinfo); > - if (IS_ERR(child)) { > - dev_warn(&pdev->dev, "%s not registered\n", name); > - child = NULL; > - } > - > - return child; > -} > > static int vchiq_probe(struct platform_device *pdev) > { > struct device_node *fw_node; > const struct of_device_id *of_id; > struct vchiq_drvdata *drvdata; > + unsigned int i; > int err; > > of_id = of_match_node(vchiq_of_match, pdev->dev.of_node); > @@ -1832,8 +1817,12 @@ static int vchiq_probe(struct platform_device *pdev) > goto error_exit; > } > > - bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera"); > - bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio"); > + for (i = 0; i < ARRAY_SIZE(vchiq_devices); i++) { > + err = vchiq_device_register(&pdev->dev, vchiq_devices[i]); > + if (!err) > + dev_err(&pdev->dev, "Failed to register %s vchiq device\n", > + vchiq_devices[i]); I think it's helpful to log "err" here. > + } > > return 0; > > @@ -1845,8 +1834,8 @@ static int vchiq_probe(struct platform_device *pdev) > > static int vchiq_remove(struct platform_device *pdev) > { > - platform_device_unregister(bcm2835_audio); > - platform_device_unregister(bcm2835_camera); > + bus_for_each_dev(&vchiq_bus_type, NULL, NULL, vchiq_device_unregister); > + > vchiq_debugfs_deinit(); > vchiq_deregister_chrdev(); > > @@ -1866,6 +1855,12 @@ static int __init vchiq_driver_init(void) > { > int ret; > > + ret = bus_register(&vchiq_bus_type); > + if (ret) { > + pr_err("Failed to register %s\n", vchiq_bus_type.name); > + return ret; > + } > + > ret = platform_driver_register(&vchiq_driver); > if (ret) > pr_err("Failed to register vchiq driver\n"); Shouldn't we unregister the bus in this error case? > @@ -1876,6 +1871,7 @@ module_init(vchiq_driver_init); > > static void __exit vchiq_driver_exit(void) > { > + bus_unregister(&vchiq_bus_type); > platform_driver_unregister(&vchiq_driver); > } > module_exit(vchiq_driver_exit); > diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.c > new file mode 100644 > index 000000000000..ec542d6bc68a > --- /dev/null > +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.c > @@ -0,0 +1,102 @@ > +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause > +/* > + * vchiq_device.c - VCHIQ generic device and bus-type > + * > + * Copyright (c) 2023 Ideas On Board Oy > + */ > + > +#include > +#include > +#include > + > +#include "vchiq_device.h" > + > +static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv); > + > +static ssize_t vchiq_dev_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct vchiq_device *device = container_of(dev, struct vchiq_device, dev); > + > + return sprintf(buf, "%s", device->name); > +} > + > +static DEVICE_ATTR_RO(vchiq_dev); > + > +static struct attribute *vchiq_dev_attrs[] = { > + &dev_attr_vchiq_dev.attr, > + NULL > +}; > + > +ATTRIBUTE_GROUPS(vchiq_dev); > + > +static const struct device_type vchiq_device_type = { > + .groups = vchiq_dev_groups > +}; > + > +struct bus_type vchiq_bus_type = { > + .name = "vchiq-bus", > + .match = vchiq_bus_type_match, > +}; > +EXPORT_SYMBOL_GPL(vchiq_bus_type); > + > +static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv) > +{ > + if (dev->bus == &vchiq_bus_type && > + strcmp(dev_name(dev), drv->name) == 0) > + return 1; Please add a empty line here. > + return 0; > +} > + > +static void vchiq_device_release(struct device *dev) > +{ > + struct vchiq_device *device; > + > + device = container_of(dev, struct vchiq_device, dev); > + kfree(device); > +} > + > +int vchiq_device_register(struct device *parent, const char *name) > +{ > + struct vchiq_device *device = NULL; > + int ret; > + > + device = kzalloc(sizeof(*device), GFP_KERNEL); > + if (!device) > + return -ENOMEM; > + > + device->name = name; > + device->dev.init_name = name; > + device->dev.parent = parent; > + device->dev.bus = &vchiq_bus_type; > + device->dev.type = &vchiq_device_type; > + device->dev.release = vchiq_device_release; > + > + ret = device_register(&device->dev); > + if (ret) { > + put_device(&device->dev); > + return -EINVAL; Why not returning "ret" here? > + } > + > + return 0; > +} > + > +int vchiq_device_unregister(struct device *dev, void *data) > +{ > + device_unregister(dev); > + return 0; > +} > + > +int vchiq_driver_register(struct vchiq_driver *vchiq_drv) > +{ > + vchiq_drv->driver.bus = &vchiq_bus_type; > + > + return driver_register(&vchiq_drv->driver); > +} > +EXPORT_SYMBOL_GPL(vchiq_driver_register); > + > +void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv) > +{ > + driver_unregister(&vchiq_drv->driver); > +} > +EXPORT_SYMBOL_GPL(vchiq_driver_unregister); > diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.h > new file mode 100644 > index 000000000000..0848c1b353f8 > --- /dev/null > +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_device.h > @@ -0,0 +1,39 @@ > +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ > +/* > + * Copyright (c) 2023 Ideas On Board Oy > + */ > + > +#ifndef _VCHIQ_DEVICE_H > +#define _VCHIQ_DEVICE_H > + > +#include > + > +struct vchiq_device { > + struct device dev; > + const char *name; > +}; > + > +struct vchiq_driver { > + struct device_driver driver; > +}; > + > +extern struct bus_type vchiq_bus_type; > + > +int vchiq_device_register(struct device *parent, const char *name); > +int vchiq_device_unregister(struct device *dev, void *data); > + > +int vchiq_driver_register(struct vchiq_driver *vchiq_drv); > +void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv); > + > +/** > + * module_vchiq_driver() - Helper macro for registering a vchiq driver > + * @__vchiq_driver: vchiq driver struct > + * > + * Helper macro for vchiq drivers which do not do anything special in > + * module init/exit. This eliminates a lot of boilerplate. Each module may only > + * use this macro once, and calling it replaces module_init() and module_exit() > + */ > +#define module_vchiq_driver(__vchiq_driver) \ > + module_driver(__vchiq_driver, vchiq_driver_register, vchiq_driver_unregister) > + > +#endif /* _VCHIQ_DEVICE_H */