cdx: Register cdx bus as a device on cdx subsystem

While scanning for CDX devices, register newly discovered bus as a
cdx device. CDX device attributes are visible based on device type.

Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
Link: https://lore.kernel.org/r/20231017160505.10640-5-abhijit.gangurde@amd.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Abhijit Gangurde 2023-10-17 21:35:02 +05:30 committed by Greg Kroah-Hartman
parent e3ed12f37e
commit ce558a391d
4 changed files with 93 additions and 7 deletions

View File

@ -125,8 +125,13 @@ static int cdx_unregister_device(struct device *dev,
{ {
struct cdx_device *cdx_dev = to_cdx_device(dev); struct cdx_device *cdx_dev = to_cdx_device(dev);
kfree(cdx_dev->driver_override); if (cdx_dev->is_bus) {
cdx_dev->driver_override = NULL; device_for_each_child(dev, NULL, cdx_unregister_device);
} else {
kfree(cdx_dev->driver_override);
cdx_dev->driver_override = NULL;
}
/* /*
* Do not free cdx_dev here as it would be freed in * Do not free cdx_dev here as it would be freed in
* cdx_device_release() called from within put_device(). * cdx_device_release() called from within put_device().
@ -201,6 +206,9 @@ static int cdx_bus_match(struct device *dev, struct device_driver *drv)
const struct cdx_device_id *found_id = NULL; const struct cdx_device_id *found_id = NULL;
const struct cdx_device_id *ids; const struct cdx_device_id *ids;
if (cdx_dev->is_bus)
return false;
ids = cdx_drv->match_id_table; ids = cdx_drv->match_id_table;
/* When driver_override is set, only bind to the matching driver */ /* When driver_override is set, only bind to the matching driver */
@ -265,10 +273,11 @@ static int cdx_dma_configure(struct device *dev)
{ {
struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver); struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver);
struct cdx_device *cdx_dev = to_cdx_device(dev); struct cdx_device *cdx_dev = to_cdx_device(dev);
struct cdx_controller *cdx = cdx_dev->cdx;
u32 input_id = cdx_dev->req_id; u32 input_id = cdx_dev->req_id;
int ret; int ret;
ret = of_dma_configure_id(dev, dev->parent->of_node, 0, &input_id); ret = of_dma_configure_id(dev, cdx->dev->of_node, 0, &input_id);
if (ret && ret != -EPROBE_DEFER) { if (ret && ret != -EPROBE_DEFER) {
dev_err(dev, "of_dma_configure_id() failed\n"); dev_err(dev, "of_dma_configure_id() failed\n");
return ret; return ret;
@ -374,6 +383,18 @@ static ssize_t driver_override_show(struct device *dev,
} }
static DEVICE_ATTR_RW(driver_override); static DEVICE_ATTR_RW(driver_override);
static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct cdx_device *cdx_dev;
cdx_dev = to_cdx_device(dev);
if (!cdx_dev->is_bus)
return a->mode;
return 0;
}
static struct attribute *cdx_dev_attrs[] = { static struct attribute *cdx_dev_attrs[] = {
&dev_attr_remove.attr, &dev_attr_remove.attr,
&dev_attr_reset.attr, &dev_attr_reset.attr,
@ -382,7 +403,16 @@ static struct attribute *cdx_dev_attrs[] = {
&dev_attr_driver_override.attr, &dev_attr_driver_override.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(cdx_dev);
static const struct attribute_group cdx_dev_group = {
.attrs = cdx_dev_attrs,
.is_visible = cdx_dev_attrs_are_visible,
};
static const struct attribute_group *cdx_dev_groups[] = {
&cdx_dev_group,
NULL,
};
static ssize_t rescan_store(const struct bus_type *bus, static ssize_t rescan_store(const struct bus_type *bus,
const char *buf, size_t count) const char *buf, size_t count)
@ -479,7 +509,6 @@ static void cdx_device_release(struct device *dev)
int cdx_device_add(struct cdx_dev_params *dev_params) int cdx_device_add(struct cdx_dev_params *dev_params)
{ {
struct cdx_controller *cdx = dev_params->cdx; struct cdx_controller *cdx = dev_params->cdx;
struct device *parent = cdx->dev;
struct cdx_device *cdx_dev; struct cdx_device *cdx_dev;
int ret; int ret;
@ -503,7 +532,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
/* Initialize generic device */ /* Initialize generic device */
device_initialize(&cdx_dev->dev); device_initialize(&cdx_dev->dev);
cdx_dev->dev.parent = parent; cdx_dev->dev.parent = dev_params->parent;
cdx_dev->dev.bus = &cdx_bus_type; cdx_dev->dev.bus = &cdx_bus_type;
cdx_dev->dev.dma_mask = &cdx_dev->dma_mask; cdx_dev->dev.dma_mask = &cdx_dev->dma_mask;
cdx_dev->dev.release = cdx_device_release; cdx_dev->dev.release = cdx_device_release;
@ -532,6 +561,42 @@ fail:
} }
EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER);
struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num)
{
struct cdx_device *cdx_dev;
int ret;
cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL);
if (!cdx_dev)
return NULL;
device_initialize(&cdx_dev->dev);
cdx_dev->cdx = cdx;
cdx_dev->dev.parent = cdx->dev;
cdx_dev->dev.bus = &cdx_bus_type;
cdx_dev->dev.release = cdx_device_release;
cdx_dev->is_bus = true;
cdx_dev->bus_num = bus_num;
dev_set_name(&cdx_dev->dev, "cdx-%02x",
((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (bus_num & CDX_BUS_NUM_MASK)));
ret = device_add(&cdx_dev->dev);
if (ret) {
dev_err(&cdx_dev->dev, "cdx bus device add failed: %d\n", ret);
goto device_add_fail;
}
return &cdx_dev->dev;
device_add_fail:
put_device(&cdx_dev->dev);
return NULL;
}
EXPORT_SYMBOL_NS_GPL(cdx_bus_add, CDX_BUS_CONTROLLER);
int cdx_register_controller(struct cdx_controller *cdx) int cdx_register_controller(struct cdx_controller *cdx)
{ {
int ret; int ret;

View File

@ -13,7 +13,7 @@
/** /**
* struct cdx_dev_params - CDX device parameters * struct cdx_dev_params - CDX device parameters
* @cdx: CDX controller associated with the device * @cdx: CDX controller associated with the device
* @parent: Associated CDX controller * @parent: Associated CDX Bus device
* @vendor: Vendor ID for CDX device * @vendor: Vendor ID for CDX device
* @device: Device ID for CDX device * @device: Device ID for CDX device
* @bus_num: Bus number for this CDX device * @bus_num: Bus number for this CDX device
@ -24,6 +24,7 @@
*/ */
struct cdx_dev_params { struct cdx_dev_params {
struct cdx_controller *cdx; struct cdx_controller *cdx;
struct device *parent;
u16 vendor; u16 vendor;
u16 device; u16 device;
u8 bus_num; u8 bus_num;
@ -59,4 +60,15 @@ void cdx_unregister_controller(struct cdx_controller *cdx);
*/ */
int cdx_device_add(struct cdx_dev_params *dev_params); int cdx_device_add(struct cdx_dev_params *dev_params);
/**
* cdx_bus_add - Add a CDX bus. This function adds a bus on the CDX bus
* subsystem. It creates a CDX device for the corresponding bus and
* also registers an associated Linux generic device.
* @cdx: Associated CDX controller
* @us_num: Bus number
*
* Return: associated Linux generic device pointer on success or NULL on failure.
*/
struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num);
#endif /* _CDX_H_ */ #endif /* _CDX_H_ */

View File

@ -79,8 +79,14 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
num_cdx_bus = (u8)ret; num_cdx_bus = (u8)ret;
for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) { for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) {
struct device *bus_dev;
u8 num_cdx_dev; u8 num_cdx_dev;
/* Add the bus on cdx subsystem */
bus_dev = cdx_bus_add(cdx, bus_num);
if (!bus_dev)
continue;
/* MCDI FW Read: Fetch the number of devices present */ /* MCDI FW Read: Fetch the number of devices present */
ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num); ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num);
if (ret < 0) { if (ret < 0) {
@ -103,6 +109,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
continue; continue;
} }
dev_params.cdx = cdx; dev_params.cdx = cdx;
dev_params.parent = bus_dev;
/* Add the device to the cdx bus */ /* Add the device to the cdx bus */
ret = cdx_device_add(&dev_params); ret = cdx_device_add(&dev_params);

View File

@ -88,6 +88,7 @@ struct cdx_controller {
* @dma_mask: Default DMA mask * @dma_mask: Default DMA mask
* @flags: CDX device flags * @flags: CDX device flags
* @req_id: Requestor ID associated with CDX device * @req_id: Requestor ID associated with CDX device
* @is_bus: Is this bus device
* @driver_override: driver name to force a match; do not set directly, * @driver_override: driver name to force a match; do not set directly,
* because core frees it; use driver_set_override() to * because core frees it; use driver_set_override() to
* set or clear it. * set or clear it.
@ -104,6 +105,7 @@ struct cdx_device {
u64 dma_mask; u64 dma_mask;
u16 flags; u16 flags;
u32 req_id; u32 req_id;
bool is_bus;
const char *driver_override; const char *driver_override;
}; };