From 54b406e10f0334ee0245d5129c8def444a49cd9b Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:34:59 +0530 Subject: cdx: Remove cdx controller list from cdx bus system Remove xarray list of cdx controller. Instead, use platform bus to locate the cdx controller using compat string used by cdx controller platform driver. Also, use ida to allocate a unique id for the controller. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-2-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers/cdx') diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index d2cad4c670a0..0252fc92433d 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,8 +70,10 @@ #define CDX_DEFAULT_DMA_MASK (~0ULL) #define MAX_CDX_CONTROLLERS 16 -/* CDX controllers registered with the CDX bus */ -static DEFINE_XARRAY_ALLOC(cdx_controllers); +/* IDA for CDX controllers registered with the CDX bus */ +static DEFINE_IDA(cdx_controller_ida); + +static char *compat_node_name = "xlnx,versal-net-cdx"; /** * cdx_dev_reset - Reset a CDX device @@ -384,7 +386,8 @@ static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { struct cdx_controller *cdx; - unsigned long index; + struct platform_device *pd; + struct device_node *np; bool val; if (kstrtobool(buf, &val) < 0) @@ -397,12 +400,19 @@ static ssize_t rescan_store(const struct bus_type *bus, cdx_unregister_devices(&cdx_bus_type); /* Rescan all the devices */ - xa_for_each(&cdx_controllers, index, cdx) { - int ret; + for_each_compatible_node(np, NULL, compat_node_name) { + if (!np) + return -EINVAL; - ret = cdx->ops->scan(cdx); - if (ret) - dev_err(cdx->dev, "cdx bus scanning failed\n"); + pd = of_find_device_by_node(np); + if (!pd) + return -EINVAL; + + cdx = platform_get_drvdata(pd); + if (cdx && cdx->controller_registered && cdx->ops->scan) + cdx->ops->scan(cdx); + + put_device(&pd->dev); } return count; @@ -520,17 +530,20 @@ int cdx_register_controller(struct cdx_controller *cdx) { int ret; - ret = xa_alloc(&cdx_controllers, &cdx->id, cdx, - XA_LIMIT(0, MAX_CDX_CONTROLLERS - 1), GFP_KERNEL); - if (ret) { + ret = ida_alloc_range(&cdx_controller_ida, 0, MAX_CDX_CONTROLLERS - 1, GFP_KERNEL); + if (ret < 0) { dev_err(cdx->dev, "No free index available. Maximum controllers already registered\n"); cdx->id = (u8)MAX_CDX_CONTROLLERS; return ret; } + cdx->id = ret; + /* Scan all the devices */ - cdx->ops->scan(cdx); + if (cdx->ops->scan) + cdx->ops->scan(cdx); + cdx->controller_registered = true; return 0; } @@ -541,8 +554,9 @@ void cdx_unregister_controller(struct cdx_controller *cdx) if (cdx->id >= MAX_CDX_CONTROLLERS) return; + cdx->controller_registered = false; device_for_each_child(cdx->dev, NULL, cdx_unregister_device); - xa_erase(&cdx_controllers, cdx->id); + ida_free(&cdx_controller_ida, cdx->id); } EXPORT_SYMBOL_GPL(cdx_unregister_controller); -- cgit v1.2.3 From f0af816834667b626dc5a3aa09cced82c46f0e62 Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:00 +0530 Subject: cdx: Introduce lock to protect controller ops Add a mutex lock to prevent race between controller ops initiated by the bus subsystem and the controller registration/unregistration. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-3-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/cdx') diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 0252fc92433d..75760388f5e7 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -72,6 +72,8 @@ /* IDA for CDX controllers registered with the CDX bus */ static DEFINE_IDA(cdx_controller_ida); +/* Lock to protect controller ops */ +static DEFINE_MUTEX(cdx_controller_lock); static char *compat_node_name = "xlnx,versal-net-cdx"; @@ -396,6 +398,8 @@ static ssize_t rescan_store(const struct bus_type *bus, if (!val) return -EINVAL; + mutex_lock(&cdx_controller_lock); + /* Unregister all the devices on the bus */ cdx_unregister_devices(&cdx_bus_type); @@ -415,6 +419,8 @@ static ssize_t rescan_store(const struct bus_type *bus, put_device(&pd->dev); } + mutex_unlock(&cdx_controller_lock); + return count; } static BUS_ATTR_WO(rescan); @@ -538,12 +544,14 @@ int cdx_register_controller(struct cdx_controller *cdx) return ret; } + mutex_lock(&cdx_controller_lock); cdx->id = ret; /* Scan all the devices */ if (cdx->ops->scan) cdx->ops->scan(cdx); cdx->controller_registered = true; + mutex_unlock(&cdx_controller_lock); return 0; } @@ -554,9 +562,13 @@ void cdx_unregister_controller(struct cdx_controller *cdx) if (cdx->id >= MAX_CDX_CONTROLLERS) return; + mutex_lock(&cdx_controller_lock); + cdx->controller_registered = false; device_for_each_child(cdx->dev, NULL, cdx_unregister_device); ida_free(&cdx_controller_ida, cdx->id); + + mutex_unlock(&cdx_controller_lock); } EXPORT_SYMBOL_GPL(cdx_unregister_controller); -- cgit v1.2.3 From e3ed12f37e261a0b35cf0b4ae505adf7ea0f48ec Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:01 +0530 Subject: cdx: Create symbol namespaces for cdx subsystem Create CDX_BUS and CDX_BUS_CONTROLLER symbol namespace for cdx bus subsystem. CDX controller modules are required to import symbols from CDX_BUS_CONTROLLER namespace and other than controller modules to import from CDX_BUS namespace. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-4-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/Makefile | 2 ++ drivers/cdx/cdx.c | 6 +++--- drivers/cdx/controller/cdx_controller.c | 1 + drivers/vfio/cdx/main.c | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/cdx') diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile index 0324e4914f6e..5d1ea482419f 100644 --- a/drivers/cdx/Makefile +++ b/drivers/cdx/Makefile @@ -5,4 +5,6 @@ # Copyright (C) 2022-2023, Advanced Micro Devices, Inc. # +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS + obj-$(CONFIG_CDX_BUS) += cdx.o controller/ diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 75760388f5e7..ee0913f04758 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -530,7 +530,7 @@ fail: return ret; } -EXPORT_SYMBOL_GPL(cdx_device_add); +EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); int cdx_register_controller(struct cdx_controller *cdx) { @@ -555,7 +555,7 @@ int cdx_register_controller(struct cdx_controller *cdx) return 0; } -EXPORT_SYMBOL_GPL(cdx_register_controller); +EXPORT_SYMBOL_NS_GPL(cdx_register_controller, CDX_BUS_CONTROLLER); void cdx_unregister_controller(struct cdx_controller *cdx) { @@ -570,7 +570,7 @@ void cdx_unregister_controller(struct cdx_controller *cdx) mutex_unlock(&cdx_controller_lock); } -EXPORT_SYMBOL_GPL(cdx_unregister_controller); +EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER); static int __init cdx_bus_init(void) { diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index bb4ae7970e21..3f86663fbacf 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -229,3 +229,4 @@ module_exit(cdx_controller_exit); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("CDX controller for AMD devices"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CDX_BUS_CONTROLLER); diff --git a/drivers/vfio/cdx/main.c b/drivers/vfio/cdx/main.c index de56686581ae..b3e482fa717b 100644 --- a/drivers/vfio/cdx/main.c +++ b/drivers/vfio/cdx/main.c @@ -231,3 +231,4 @@ module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver"); +MODULE_IMPORT_NS(CDX_BUS); -- cgit v1.2.3 From ce558a391d80b9f47a462107977e8e81fe2f2962 Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:02 +0530 Subject: 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 Link: https://lore.kernel.org/r/20231017160505.10640-5-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/cdx/cdx.c | 77 ++++++++++++++++++++++++++++++--- drivers/cdx/cdx.h | 14 +++++- drivers/cdx/controller/cdx_controller.c | 7 +++ include/linux/cdx/cdx_bus.h | 2 + 4 files changed, 93 insertions(+), 7 deletions(-) (limited to 'drivers/cdx') diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index ee0913f04758..cf5306580c21 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -125,8 +125,13 @@ static int cdx_unregister_device(struct device *dev, { struct cdx_device *cdx_dev = to_cdx_device(dev); - kfree(cdx_dev->driver_override); - cdx_dev->driver_override = NULL; + if (cdx_dev->is_bus) { + 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 * 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 *ids; + if (cdx_dev->is_bus) + return false; + ids = cdx_drv->match_id_table; /* 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_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; u32 input_id = cdx_dev->req_id; 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) { dev_err(dev, "of_dma_configure_id() failed\n"); return ret; @@ -374,6 +383,18 @@ static ssize_t driver_override_show(struct device *dev, } 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[] = { &dev_attr_remove.attr, &dev_attr_reset.attr, @@ -382,7 +403,16 @@ static struct attribute *cdx_dev_attrs[] = { &dev_attr_driver_override.attr, 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, 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) { struct cdx_controller *cdx = dev_params->cdx; - struct device *parent = cdx->dev; struct cdx_device *cdx_dev; int ret; @@ -503,7 +532,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) /* Initialize generic device */ 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.dma_mask = &cdx_dev->dma_mask; cdx_dev->dev.release = cdx_device_release; @@ -532,6 +561,42 @@ fail: } 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 ret; diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h index c436ac7ac86f..1f593deb4c9e 100644 --- a/drivers/cdx/cdx.h +++ b/drivers/cdx/cdx.h @@ -13,7 +13,7 @@ /** * struct cdx_dev_params - CDX device parameters * @cdx: CDX controller associated with the device - * @parent: Associated CDX controller + * @parent: Associated CDX Bus device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device * @bus_num: Bus number for this CDX device @@ -24,6 +24,7 @@ */ struct cdx_dev_params { struct cdx_controller *cdx; + struct device *parent; u16 vendor; u16 device; 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); +/** + * 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_ */ diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index 3f86663fbacf..b4e0d6b40339 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -79,8 +79,14 @@ static int cdx_scan_devices(struct cdx_controller *cdx) num_cdx_bus = (u8)ret; for (bus_num = 0; bus_num < num_cdx_bus; bus_num++) { + struct device *bus_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 */ ret = cdx_mcdi_get_num_devs(cdx_mcdi, bus_num); if (ret < 0) { @@ -103,6 +109,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx) continue; } dev_params.cdx = cdx; + dev_params.parent = bus_dev; /* Add the device to the cdx bus */ ret = cdx_device_add(&dev_params); diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index 82c27b8c94e1..b5e4b7e05666 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -88,6 +88,7 @@ struct cdx_controller { * @dma_mask: Default DMA mask * @flags: CDX device flags * @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, * because core frees it; use driver_set_override() to * set or clear it. @@ -104,6 +105,7 @@ struct cdx_device { u64 dma_mask; u16 flags; u32 req_id; + bool is_bus; const char *driver_override; }; -- cgit v1.2.3 From e3cfd49cb9491ac1cc233a4b9e098688b4ab281d Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:03 +0530 Subject: cdx: add support for bus enable and disable CDX bus needs to be disabled before updating/writing devices in the FPGA. Once the devices are written, the bus shall be rescanned. This change provides sysfs entry to enable/disable the CDX bus. Co-developed-by: Nipun Gupta Signed-off-by: Nipun Gupta Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-6-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 13 ++++++ drivers/cdx/cdx.c | 72 +++++++++++++++++++++++++++++++++ drivers/cdx/controller/cdx_controller.c | 12 ++++++ drivers/cdx/controller/mc_cdx_pcol.h | 54 +++++++++++++++++++++++++ drivers/cdx/controller/mcdi_functions.c | 24 +++++++++++ drivers/cdx/controller/mcdi_functions.h | 18 +++++++++ include/linux/cdx/cdx_bus.h | 10 +++++ 7 files changed, 203 insertions(+) (limited to 'drivers/cdx') diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index 7af477f49998..c12bdaa4152a 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -28,6 +28,19 @@ Description: of a device manufacturer. Combination of Vendor ID and Device ID identifies a device. +What: /sys/bus/cdx/devices/.../enable +Date: October 2023 +Contact: abhijit.gangurde@amd.com +Description: + CDX bus should be disabled before updating the devices in FPGA. + Writing n/0/off will attempt to disable the CDX bus and. + writing y/1/on will attempt to enable the CDX bus. Reading this file + gives the current state of the bus, 1 for enabled and 0 for disabled. + + For example:: + + # echo 1 > /sys/bus/cdx/.../enable + What: /sys/bus/cdx/devices/.../reset Date: March 2023 Contact: nipun.gupta@amd.com diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index cf5306580c21..8eb484c37e97 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -124,9 +124,12 @@ static int cdx_unregister_device(struct device *dev, void *data) { struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; if (cdx_dev->is_bus) { device_for_each_child(dev, NULL, cdx_unregister_device); + if (cdx_dev->enabled && cdx->ops->bus_disable) + cdx->ops->bus_disable(cdx, cdx_dev->bus_num); } else { kfree(cdx_dev->driver_override); cdx_dev->driver_override = NULL; @@ -383,6 +386,41 @@ static ssize_t driver_override_show(struct device *dev, } static DEVICE_ATTR_RW(driver_override); +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + struct cdx_controller *cdx = cdx_dev->cdx; + bool enable; + int ret; + + if (kstrtobool(buf, &enable) < 0) + return -EINVAL; + + if (enable == cdx_dev->enabled) + return count; + + if (enable && cdx->ops->bus_enable) + ret = cdx->ops->bus_enable(cdx, cdx_dev->bus_num); + else if (!enable && cdx->ops->bus_disable) + ret = cdx->ops->bus_disable(cdx, cdx_dev->bus_num); + else + ret = -EOPNOTSUPP; + + if (!ret) + cdx_dev->enabled = enable; + + return ret < 0 ? ret : count; +} + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + return sysfs_emit(buf, "%u\n", cdx_dev->enabled); +} +static DEVICE_ATTR_RW(enable); + static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = kobj_to_dev(kobj); @@ -395,6 +433,18 @@ static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute return 0; } +static umode_t cdx_bus_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[] = { &dev_attr_remove.attr, &dev_attr_reset.attr, @@ -409,8 +459,19 @@ static const struct attribute_group cdx_dev_group = { .is_visible = cdx_dev_attrs_are_visible, }; +static struct attribute *cdx_bus_dev_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static const struct attribute_group cdx_bus_dev_group = { + .attrs = cdx_bus_dev_attrs, + .is_visible = cdx_bus_attrs_are_visible, +}; + static const struct attribute_group *cdx_dev_groups[] = { &cdx_dev_group, + &cdx_bus_dev_group, NULL, }; @@ -588,8 +649,19 @@ struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) goto device_add_fail; } + if (cdx->ops->bus_enable) { + ret = cdx->ops->bus_enable(cdx, bus_num); + if (ret && ret != -EALREADY) { + dev_err(cdx->dev, "cdx bus enable failed: %d\n", ret); + goto bus_enable_fail; + } + } + + cdx_dev->enabled = true; return &cdx_dev->dev; +bus_enable_fail: + device_del(&cdx_dev->dev); device_add_fail: put_device(&cdx_dev->dev); diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index b4e0d6b40339..f2a691efd1f1 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -33,6 +33,16 @@ static const struct cdx_mcdi_ops mcdi_ops = { .mcdi_request = cdx_mcdi_request, }; +static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num) +{ + return cdx_mcdi_bus_enable(cdx->priv, bus_num); +} + +static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num) +{ + return cdx_mcdi_bus_disable(cdx->priv, bus_num); +} + void cdx_rpmsg_post_probe(struct cdx_controller *cdx) { /* Register CDX controller with CDX bus driver */ @@ -128,6 +138,8 @@ static int cdx_scan_devices(struct cdx_controller *cdx) } static struct cdx_ops cdx_ops = { + .bus_enable = cdx_bus_enable, + .bus_disable = cdx_bus_disable, .scan = cdx_scan_devices, .dev_configure = cdx_configure_device, }; diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h index 4ccb7b52951b..2de019406b57 100644 --- a/drivers/cdx/controller/mc_cdx_pcol.h +++ b/drivers/cdx/controller/mc_cdx_pcol.h @@ -455,6 +455,60 @@ #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4 +/***********************************/ +/* + * MC_CMD_CDX_BUS_DOWN + * Asserting reset on the CDX bus causes all devices on the bus to be quiesced. + * DMA bus mastering is disabled and any pending DMA request are flushed. Once + * the response is returned, the devices are guaranteed to no longer issue DMA + * requests or raise MSI interrupts. Further device MMIO accesses may have + * undefined results. While the bus reset is asserted, any of the enumeration + * or device configuration MCDIs will fail with EAGAIN. It is only legal to + * reload the relevant PL region containing CDX devices if the corresponding CDX + * bus is in reset. Depending on the implementation, the firmware may or may + * not enforce this restriction and it is up to the caller to make sure this + * requirement is satisfied. + */ +#define MC_CMD_CDX_BUS_DOWN 0x4 +#define MC_CMD_CDX_BUS_DOWN_MSGSET 0x4 + +/* MC_CMD_CDX_BUS_DOWN_IN msgrequest */ +#define MC_CMD_CDX_BUS_DOWN_IN_LEN 4 +/* Bus number to put in reset, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_BUS_DOWN_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_DOWN_IN_BUS_LEN 4 + +/* + * MC_CMD_CDX_BUS_DOWN_OUT msgresponse: The bus is quiesced, no further + * upstream traffic for devices on this bus. + */ +#define MC_CMD_CDX_BUS_DOWN_OUT_LEN 0 + +/***********************************/ +/* + * MC_CMD_CDX_BUS_UP + * After bus reset is de-asserted, devices are in a state which is functionally + * equivalent to each device having been reset with MC_CMD_CDX_DEVICE_RESET. In + * other words, device logic is reset in a hardware-specific way, MMIO accesses + * are forwarded to the device, DMA bus mastering is disabled and needs to be + * re-enabled with MC_CMD_CDX_DEVICE_DMA_ENABLE once the driver is ready to + * start servicing DMA. If the underlying number of devices or device resources + * changed (e.g. if PL was reloaded) while the bus was in reset, the bus driver + * is expected to re-enumerate the bus. Returns EALREADY if the bus was already + * up before the call. + */ +#define MC_CMD_CDX_BUS_UP 0x5 +#define MC_CMD_CDX_BUS_UP_MSGSET 0x5 + +/* MC_CMD_CDX_BUS_UP_IN msgrequest */ +#define MC_CMD_CDX_BUS_UP_IN_LEN 4 +/* Bus number to take out of reset, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_BUS_UP_IN_BUS_OFST 0 +#define MC_CMD_CDX_BUS_UP_IN_BUS_LEN 4 + +/* MC_CMD_CDX_BUS_UP_OUT msgresponse: The bus can now be enumerated. */ +#define MC_CMD_CDX_BUS_UP_OUT_LEN 0 + /***********************************/ /* * MC_CMD_CDX_DEVICE_RESET diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c index 0158f26533dd..0e1e35d91242 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -124,6 +124,30 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, return 0; } +int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf), + NULL, 0, NULL); + + return ret; +} + +int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf), + NULL, 0, NULL); + + return ret; +} + int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) { MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN); diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h index 7440ace5539a..28973d5ec3ab 100644 --- a/drivers/cdx/controller/mcdi_functions.h +++ b/drivers/cdx/controller/mcdi_functions.h @@ -47,6 +47,24 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, struct cdx_dev_params *dev_params); +/** + * cdx_mcdi_bus_enable - Enable CDX bus represented by bus_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num); + +/** + * cdx_mcdi_bus_disable - Disable CDX bus represented by bus_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num); + /** * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num * @cdx: pointer to MCDI interface. diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index b5e4b7e05666..18e95076d1d5 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -28,6 +28,10 @@ struct cdx_device_config { u8 type; }; +typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num); + +typedef int (*cdx_bus_disable_cb)(struct cdx_controller *cdx, u8 bus_num); + typedef int (*cdx_scan_cb)(struct cdx_controller *cdx); typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, @@ -49,11 +53,15 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, /** * struct cdx_ops - Callbacks supported by CDX controller. + * @bus_enable: enable bus on the controller + * @bus_disable: disable bus on the controller * @scan: scan the devices on the controller * @dev_configure: configuration like reset, master_enable, * msi_config etc for a CDX device */ struct cdx_ops { + cdx_bus_enable_cb bus_enable; + cdx_bus_disable_cb bus_disable; cdx_scan_cb scan; cdx_dev_configure_cb dev_configure; }; @@ -89,6 +97,7 @@ struct cdx_controller { * @flags: CDX device flags * @req_id: Requestor ID associated with CDX device * @is_bus: Is this bus device + * @enabled: is this bus enabled * @driver_override: driver name to force a match; do not set directly, * because core frees it; use driver_set_override() to * set or clear it. @@ -106,6 +115,7 @@ struct cdx_device { u16 flags; u32 req_id; bool is_bus; + bool enabled; const char *driver_override; }; -- cgit v1.2.3 From 0174f5810401ae6390bfe15354346b5ea660d40c Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:04 +0530 Subject: cdx: add sysfs for bus reset Add sysfs interface reset to reset all the devices on the CDX bus. Signed-off-by: Abhijit Gangurde Link: https://lore.kernel.org/r/20231017160505.10640-7-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 8 ++++---- drivers/cdx/cdx.c | 26 ++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers/cdx') diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index c12bdaa4152a..c2c54abffed5 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -45,10 +45,10 @@ What: /sys/bus/cdx/devices/.../reset Date: March 2023 Contact: nipun.gupta@amd.com Description: - Writing y/1/on to this file resets the CDX device. - On resetting the device, the corresponding driver is notified - twice, once before the device is being reset, and again after - the reset has been complete. + Writing y/1/on to this file resets the CDX device or all devices + on the bus. On resetting the device, the corresponding driver is + notified twice, once before the device is being reset, and again + after the reset has been complete. For example:: diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 8eb484c37e97..e22a7138292e 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -110,6 +110,20 @@ int cdx_dev_reset(struct device *dev) } EXPORT_SYMBOL_GPL(cdx_dev_reset); +/** + * reset_cdx_device - Reset a CDX device + * @dev: CDX device + * @data: This is always passed as NULL, and is not used in this API, + * but is required here as the device_for_each_child() API expects + * the passed function to have this as an argument. + * + * Return: -errno on failure, 0 on success. + */ +static int reset_cdx_device(struct device *dev, void *data) +{ + return cdx_dev_reset(dev); +} + /** * cdx_unregister_device - Unregister a CDX device * @dev: CDX device @@ -343,6 +357,7 @@ static DEVICE_ATTR_WO(remove); static ssize_t reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct cdx_device *cdx_dev = to_cdx_device(dev); bool val; int ret; @@ -352,11 +367,13 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, if (!val) return -EINVAL; - ret = cdx_dev_reset(dev); - if (ret) - return ret; + if (cdx_dev->is_bus) + /* Reset all the devices attached to cdx bus */ + ret = device_for_each_child(dev, NULL, reset_cdx_device); + else + ret = cdx_dev_reset(dev); - return count; + return ret < 0 ? ret : count; } static DEVICE_ATTR_WO(reset); @@ -461,6 +478,7 @@ static const struct attribute_group cdx_dev_group = { static struct attribute *cdx_bus_dev_attrs[] = { &dev_attr_enable.attr, + &dev_attr_reset.attr, NULL, }; -- cgit v1.2.3 From fa10f413091a43f801f82b3cf484f15d6fc9266f Mon Sep 17 00:00:00 2001 From: Abhijit Gangurde Date: Tue, 17 Oct 2023 21:35:05 +0530 Subject: cdx: add sysfs for subsystem, class and revision CDX controller provides subsystem vendor, subsystem device, class and revision info of the device along with vendor and device ID in native endian format. CDX Bus system uses this information to bind the cdx device to the cdx device driver. Co-developed-by: Puneet Gupta Signed-off-by: Puneet Gupta Co-developed-by: Nipun Gupta Signed-off-by: Nipun Gupta Signed-off-by: Abhijit Gangurde Reviewed-by: Pieter Jansen van Vuuren Tested-by: Nikhil Agarwal Link: https://lore.kernel.org/r/20231017160505.10640-8-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-cdx | 45 +++++++++++++++++++++++++++++++++ drivers/cdx/cdx.c | 29 ++++++++++++++++++++- drivers/cdx/cdx.h | 8 ++++++ drivers/cdx/controller/mcdi_functions.c | 7 +++++ include/linux/cdx/cdx_bus.h | 27 ++++++++++++++++++-- include/linux/mod_devicetable.h | 10 ++++++++ scripts/mod/devicetable-offsets.c | 4 +++ scripts/mod/file2alias.c | 8 ++++++ 8 files changed, 135 insertions(+), 3 deletions(-) (limited to 'drivers/cdx') diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index c2c54abffed5..8c067ff99e54 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -28,6 +28,36 @@ Description: of a device manufacturer. Combination of Vendor ID and Device ID identifies a device. +What: /sys/bus/cdx/devices/.../subsystem_vendor +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + Subsystem Vendor ID for this CDX device, in hexadecimal. + Subsystem Vendor ID is 16 bit identifier specific to the + card manufacturer. + +What: /sys/bus/cdx/devices/.../subsystem_device +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + Subsystem Device ID for this CDX device, in hexadecimal + Subsystem Device ID is 16 bit identifier specific to the + card manufacturer. + +What: /sys/bus/cdx/devices/.../class +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + This file contains the class of the CDX device, in hexadecimal. + Class is 24 bit identifier specifies the functionality of the device. + +What: /sys/bus/cdx/devices/.../revision +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + This file contains the revision field of the CDX device, in hexadecimal. + Revision is 8 bit revision identifier of the device. + What: /sys/bus/cdx/devices/.../enable Date: October 2023 Contact: abhijit.gangurde@amd.com @@ -67,3 +97,18 @@ Description: For example:: # echo 1 > /sys/bus/cdx/devices/.../remove + +What: /sys/bus/cdx/devices/.../modalias +Date: July 2023 +Contact: nipun.gupta@amd.com +Description: + This attribute indicates the CDX ID of the device. + That is in the format: + cdx:vXXXXdXXXXsvXXXXsdXXXXcXXXXXX, + where: + + - vXXXX contains the vendor ID; + - dXXXX contains the device ID; + - svXXXX contains the subsystem vendor ID; + - sdXXXX contains the subsystem device ID; + - cXXXXXX contains the device class. diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index e22a7138292e..3dcda7513818 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -179,7 +179,10 @@ cdx_match_one_device(const struct cdx_device_id *id, { /* Use vendor ID and device ID for matching */ if ((id->vendor == CDX_ANY_ID || id->vendor == dev->vendor) && - (id->device == CDX_ANY_ID || id->device == dev->device)) + (id->device == CDX_ANY_ID || id->device == dev->device) && + (id->subvendor == CDX_ANY_ID || id->subvendor == dev->subsystem_vendor) && + (id->subdevice == CDX_ANY_ID || id->subdevice == dev->subsystem_device) && + !((id->class ^ dev->class) & id->class_mask)) return id; return NULL; } @@ -329,6 +332,10 @@ static DEVICE_ATTR_RO(field) cdx_config_attr(vendor, "0x%04x\n"); cdx_config_attr(device, "0x%04x\n"); +cdx_config_attr(subsystem_vendor, "0x%04x\n"); +cdx_config_attr(subsystem_device, "0x%04x\n"); +cdx_config_attr(revision, "0x%02x\n"); +cdx_config_attr(class, "0x%06x\n"); static ssize_t remove_store(struct device *dev, struct device_attribute *attr, @@ -377,6 +384,17 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_WO(reset); +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cdx_device *cdx_dev = to_cdx_device(dev); + + return sprintf(buf, "cdx:v%04Xd%04Xsv%04Xsd%04Xc%06X\n", cdx_dev->vendor, + cdx_dev->device, cdx_dev->subsystem_vendor, cdx_dev->subsystem_device, + cdx_dev->class); +} +static DEVICE_ATTR_RO(modalias); + static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -467,6 +485,11 @@ static struct attribute *cdx_dev_attrs[] = { &dev_attr_reset.attr, &dev_attr_vendor.attr, &dev_attr_device.attr, + &dev_attr_subsystem_vendor.attr, + &dev_attr_subsystem_device.attr, + &dev_attr_class.attr, + &dev_attr_revision.attr, + &dev_attr_modalias.attr, &dev_attr_driver_override.attr, NULL, }; @@ -604,6 +627,10 @@ int cdx_device_add(struct cdx_dev_params *dev_params) cdx_dev->req_id = dev_params->req_id; cdx_dev->vendor = dev_params->vendor; cdx_dev->device = dev_params->device; + cdx_dev->subsystem_vendor = dev_params->subsys_vendor; + cdx_dev->subsystem_device = dev_params->subsys_device; + cdx_dev->class = dev_params->class; + cdx_dev->revision = dev_params->revision; cdx_dev->bus_num = dev_params->bus_num; cdx_dev->dev_num = dev_params->dev_num; cdx_dev->cdx = dev_params->cdx; diff --git a/drivers/cdx/cdx.h b/drivers/cdx/cdx.h index 1f593deb4c9e..300ad8be7a34 100644 --- a/drivers/cdx/cdx.h +++ b/drivers/cdx/cdx.h @@ -16,22 +16,30 @@ * @parent: Associated CDX Bus device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device + * @subsys_vendor: Sub vendor ID for CDX device + * @subsys_device: Sub device ID for CDX device * @bus_num: Bus number for this CDX device * @dev_num: Device number for this device * @res: array of MMIO region entries * @res_count: number of valid MMIO regions * @req_id: Requestor ID associated with CDX device + * @class: Class of the CDX Device + * @revision: Revision of the CDX device */ struct cdx_dev_params { struct cdx_controller *cdx; struct device *parent; u16 vendor; u16 device; + u16 subsys_vendor; + u16 subsys_device; u8 bus_num; u8 dev_num; struct resource res[MAX_CDX_DEV_RESOURCES]; u8 res_count; u32 req_id; + u32 class; + u8 revision; }; /** diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c index 0e1e35d91242..65dca2aa1d3f 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -120,6 +120,13 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, dev_params->vendor = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_VENDOR_ID); dev_params->device = MCDI_WORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_ID); + dev_params->subsys_vendor = MCDI_WORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_VENDOR_ID); + dev_params->subsys_device = MCDI_WORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_SUBSYS_DEVICE_ID); + dev_params->class = MCDI_DWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF; + dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION); return 0; } diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index 18e95076d1d5..cf9738e3a957 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -38,6 +38,19 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, u8 bus_num, u8 dev_num, struct cdx_device_config *dev_config); +/** + * CDX_DEVICE - macro used to describe a specific CDX device + * @vend: the 16 bit CDX Vendor ID + * @dev: the 16 bit CDX Device ID + * + * This macro is used to create a struct cdx_device_id that matches a + * specific device. The subvendor and subdevice fields will be set to + * CDX_ANY_ID. + */ +#define CDX_DEVICE(vend, dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = CDX_ANY_ID, .subdevice = CDX_ANY_ID + /** * CDX_DEVICE_DRIVER_OVERRIDE - macro used to describe a CDX device with * override_only flags. @@ -46,10 +59,12 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx, * @driver_override: the 32 bit CDX Device override_only * * This macro is used to create a struct cdx_device_id that matches only a - * driver_override device. + * driver_override device. The subvendor and subdevice fields will be set to + * CDX_ANY_ID. */ #define CDX_DEVICE_DRIVER_OVERRIDE(vend, dev, driver_override) \ - .vendor = (vend), .device = (dev), .override_only = (driver_override) + .vendor = (vend), .device = (dev), .subvendor = CDX_ANY_ID,\ + .subdevice = CDX_ANY_ID, .override_only = (driver_override) /** * struct cdx_ops - Callbacks supported by CDX controller. @@ -88,6 +103,10 @@ struct cdx_controller { * @cdx: CDX controller associated with the device * @vendor: Vendor ID for CDX device * @device: Device ID for CDX device + * @subsystem_vendor: Subsystem Vendor ID for CDX device + * @subsystem_device: Subsystem Device ID for CDX device + * @class: Class for the CDX device + * @revision: Revision of the CDX device * @bus_num: Bus number for this CDX device * @dev_num: Device number for this device * @res: array of MMIO region entries @@ -107,6 +126,10 @@ struct cdx_device { struct cdx_controller *cdx; u16 vendor; u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + u32 class; + u8 revision; u8 bus_num; u8 dev_num; struct resource res[MAX_CDX_DEV_RESOURCES]; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b0678b093cb2..aa3c28781248 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -935,6 +935,12 @@ enum { * struct cdx_device_id - CDX device identifier * @vendor: Vendor ID * @device: Device ID + * @subvendor: Subsystem vendor ID (or CDX_ANY_ID) + * @subdevice: Subsystem device ID (or CDX_ANY_ID) + * @class: Device class + * Most drivers do not need to specify class/class_mask + * as vendor/device is normally sufficient. + * @class_mask: Limit which sub-fields of the class field are compared. * @override_only: Match only when dev->driver_override is this driver. * * Type of entries in the "device Id" table for CDX devices supported by @@ -943,6 +949,10 @@ enum { struct cdx_device_id { __u16 vendor; __u16 device; + __u16 subvendor; + __u16 subdevice; + __u32 class; + __u32 class_mask; __u32 override_only; }; diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index abe65f8968dd..7a659aa3114a 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -265,6 +265,10 @@ int main(void) DEVID(cdx_device_id); DEVID_FIELD(cdx_device_id, vendor); DEVID_FIELD(cdx_device_id, device); + DEVID_FIELD(cdx_device_id, subvendor); + DEVID_FIELD(cdx_device_id, subdevice); + DEVID_FIELD(cdx_device_id, class); + DEVID_FIELD(cdx_device_id, class_mask); DEVID_FIELD(cdx_device_id, override_only); return 0; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 7056751c29b1..2b28faca9585 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1458,6 +1458,10 @@ static int do_cdx_entry(const char *filename, void *symval, { DEF_FIELD(symval, cdx_device_id, vendor); DEF_FIELD(symval, cdx_device_id, device); + DEF_FIELD(symval, cdx_device_id, subvendor); + DEF_FIELD(symval, cdx_device_id, subdevice); + DEF_FIELD(symval, cdx_device_id, class); + DEF_FIELD(symval, cdx_device_id, class_mask); DEF_FIELD(symval, cdx_device_id, override_only); switch (override_only) { @@ -1475,6 +1479,10 @@ static int do_cdx_entry(const char *filename, void *symval, ADD(alias, "v", vendor != CDX_ANY_ID, vendor); ADD(alias, "d", device != CDX_ANY_ID, device); + ADD(alias, "sv", subvendor != CDX_ANY_ID, subvendor); + ADD(alias, "sd", subdevice != CDX_ANY_ID, subdevice); + ADD(alias, "c", class_mask == 0xFFFFFF, class); + return 1; } -- cgit v1.2.3