Commit 48a6c7bc authored by Nipun Gupta's avatar Nipun Gupta Committed by Greg Kroah-Hartman

cdx: add device attributes

Create sysfs entry for CDX devices.

Sysfs entries provided in each of the CDX device detected by
the CDX controller
 - vendor id
 - device id
 - remove
 - reset of the device.
 - driver override
Signed-off-by: default avatarPuneet Gupta <puneet.gupta@amd.com>
Signed-off-by: default avatarNipun Gupta <nipun.gupta@amd.com>
Signed-off-by: default avatarTarak Reddy <tarak.reddy@amd.com>
Reviewed-by: default avatarPieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Tested-by: default avatarNikhil Agarwal <nikhil.agarwal@amd.com>
Link: https://lore.kernel.org/r/20230313132636.31850-8-nipun.gupta@amd.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2a226927
...@@ -10,3 +10,47 @@ Description: ...@@ -10,3 +10,47 @@ Description:
For example:: For example::
# echo 1 > /sys/bus/cdx/rescan # echo 1 > /sys/bus/cdx/rescan
What: /sys/bus/cdx/devices/.../vendor
Date: March 2023
Contact: nipun.gupta@amd.com
Description:
Vendor ID for this CDX device, in hexadecimal. Vendor ID is
16 bit identifier which is specific to the device manufacturer.
Combination of Vendor ID and Device ID identifies a device.
What: /sys/bus/cdx/devices/.../device
Date: March 2023
Contact: nipun.gupta@amd.com
Description:
Device ID for this CDX device, in hexadecimal. Device ID is
16 bit identifier to identify a device type within the range
of a device manufacturer.
Combination of Vendor ID and Device ID identifies a device.
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.
For example::
# echo 1 > /sys/bus/cdx/.../reset
What: /sys/bus/cdx/devices/.../remove
Date: March 2023
Contact: tarak.reddy@amd.com
Description:
Writing y/1/on to this file removes the corresponding
device from the CDX bus. If the device is to be reconfigured
reconfigured in the Hardware, the device can be removed, so
that the device driver does not access the device while it is
being reconfigured.
For example::
# echo 1 > /sys/bus/cdx/devices/.../remove
...@@ -71,6 +71,39 @@ ...@@ -71,6 +71,39 @@
/* CDX controllers registered with the CDX bus */ /* CDX controllers registered with the CDX bus */
static DEFINE_XARRAY_ALLOC(cdx_controllers); static DEFINE_XARRAY_ALLOC(cdx_controllers);
/**
* cdx_dev_reset - Reset a CDX device
* @dev: CDX device
*
* Return: -errno on failure, 0 on success.
*/
int cdx_dev_reset(struct device *dev)
{
struct cdx_device *cdx_dev = to_cdx_device(dev);
struct cdx_controller *cdx = cdx_dev->cdx;
struct cdx_device_config dev_config = {0};
struct cdx_driver *cdx_drv;
int ret;
cdx_drv = to_cdx_driver(dev->driver);
/* Notify driver that device is being reset */
if (cdx_drv && cdx_drv->reset_prepare)
cdx_drv->reset_prepare(cdx_dev);
dev_config.type = CDX_DEV_RESET_CONF;
ret = cdx->ops->dev_configure(cdx, cdx_dev->bus_num,
cdx_dev->dev_num, &dev_config);
if (ret)
dev_err(dev, "cdx device reset failed\n");
/* Notify driver that device reset is complete */
if (cdx_drv && cdx_drv->reset_done)
cdx_drv->reset_done(cdx_dev);
return ret;
}
EXPORT_SYMBOL_GPL(cdx_dev_reset);
/** /**
* cdx_unregister_device - Unregister a CDX device * cdx_unregister_device - Unregister a CDX device
* @dev: CDX device * @dev: CDX device
...@@ -237,6 +270,99 @@ static int cdx_dma_configure(struct device *dev) ...@@ -237,6 +270,99 @@ static int cdx_dma_configure(struct device *dev)
return 0; return 0;
} }
/* show configuration fields */
#define cdx_config_attr(field, format_string) \
static ssize_t \
field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct cdx_device *cdx_dev = to_cdx_device(dev); \
return sysfs_emit(buf, format_string, cdx_dev->field); \
} \
static DEVICE_ATTR_RO(field)
cdx_config_attr(vendor, "0x%04x\n");
cdx_config_attr(device, "0x%04x\n");
static ssize_t remove_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
bool val;
if (kstrtobool(buf, &val) < 0)
return -EINVAL;
if (!val)
return -EINVAL;
if (device_remove_file_self(dev, attr)) {
int ret;
ret = cdx_unregister_device(dev, NULL);
if (ret)
return ret;
}
return count;
}
static DEVICE_ATTR_WO(remove);
static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
bool val;
int ret;
if (kstrtobool(buf, &val) < 0)
return -EINVAL;
if (!val)
return -EINVAL;
ret = cdx_dev_reset(dev);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_WO(reset);
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cdx_device *cdx_dev = to_cdx_device(dev);
int ret;
if (WARN_ON(dev->bus != &cdx_bus_type))
return -EINVAL;
ret = driver_set_override(dev, &cdx_dev->driver_override, buf, count);
if (ret)
return ret;
return count;
}
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cdx_device *cdx_dev = to_cdx_device(dev);
return sysfs_emit(buf, "%s\n", cdx_dev->driver_override);
}
static DEVICE_ATTR_RW(driver_override);
static struct attribute *cdx_dev_attrs[] = {
&dev_attr_remove.attr,
&dev_attr_reset.attr,
&dev_attr_vendor.attr,
&dev_attr_device.attr,
&dev_attr_driver_override.attr,
NULL,
};
ATTRIBUTE_GROUPS(cdx_dev);
static ssize_t rescan_store(struct bus_type *bus, static ssize_t rescan_store(struct bus_type *bus,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -280,6 +406,7 @@ struct bus_type cdx_bus_type = { ...@@ -280,6 +406,7 @@ struct bus_type cdx_bus_type = {
.shutdown = cdx_shutdown, .shutdown = cdx_shutdown,
.dma_configure = cdx_dma_configure, .dma_configure = cdx_dma_configure,
.bus_groups = cdx_bus_groups, .bus_groups = cdx_bus_groups,
.dev_groups = cdx_dev_groups,
}; };
EXPORT_SYMBOL_GPL(cdx_bus_type); EXPORT_SYMBOL_GPL(cdx_bus_type);
......
...@@ -45,6 +45,23 @@ void cdx_rpmsg_pre_remove(struct cdx_controller *cdx) ...@@ -45,6 +45,23 @@ void cdx_rpmsg_pre_remove(struct cdx_controller *cdx)
cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT); cdx_mcdi_wait_for_quiescence(cdx->priv, MCDI_RPC_TIMEOUT);
} }
static int cdx_configure_device(struct cdx_controller *cdx,
u8 bus_num, u8 dev_num,
struct cdx_device_config *dev_config)
{
int ret = 0;
switch (dev_config->type) {
case CDX_DEV_RESET_CONF:
ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int cdx_scan_devices(struct cdx_controller *cdx) static int cdx_scan_devices(struct cdx_controller *cdx)
{ {
struct cdx_mcdi *cdx_mcdi = cdx->priv; struct cdx_mcdi *cdx_mcdi = cdx->priv;
...@@ -104,6 +121,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx) ...@@ -104,6 +121,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
static struct cdx_ops cdx_ops = { static struct cdx_ops cdx_ops = {
.scan = cdx_scan_devices, .scan = cdx_scan_devices,
.dev_configure = cdx_configure_device,
}; };
static int xlnx_cdx_probe(struct platform_device *pdev) static int xlnx_cdx_probe(struct platform_device *pdev)
......
...@@ -123,3 +123,17 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, ...@@ -123,3 +123,17 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
return 0; return 0;
} }
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);
int ret;
MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_BUS, bus_num);
MCDI_SET_DWORD(inbuf, CDX_DEVICE_RESET_IN_DEVICE, dev_num);
ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_RESET, inbuf, sizeof(inbuf),
NULL, 0, NULL);
return ret;
}
...@@ -47,4 +47,15 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, ...@@ -47,4 +47,15 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
u8 bus_num, u8 dev_num, u8 bus_num, u8 dev_num,
struct cdx_dev_params *dev_params); struct cdx_dev_params *dev_params);
/**
* cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num
* @cdx: pointer to MCDI interface.
* @bus_num: Bus number.
* @dev_num: Device number.
*
* Return: 0 on success, <0 on failure
*/
int cdx_mcdi_reset_device(struct cdx_mcdi *cdx,
u8 bus_num, u8 dev_num);
#endif /* CDX_MCDI_FUNCTIONS_H */ #endif /* CDX_MCDI_FUNCTIONS_H */
...@@ -21,8 +21,20 @@ ...@@ -21,8 +21,20 @@
/* Forward declaration for CDX controller */ /* Forward declaration for CDX controller */
struct cdx_controller; struct cdx_controller;
enum {
CDX_DEV_RESET_CONF,
};
struct cdx_device_config {
u8 type;
};
typedef int (*cdx_scan_cb)(struct cdx_controller *cdx); typedef int (*cdx_scan_cb)(struct cdx_controller *cdx);
typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx,
u8 bus_num, u8 dev_num,
struct cdx_device_config *dev_config);
/** /**
* CDX_DEVICE_DRIVER_OVERRIDE - macro used to describe a CDX device with * CDX_DEVICE_DRIVER_OVERRIDE - macro used to describe a CDX device with
* override_only flags. * override_only flags.
...@@ -39,9 +51,12 @@ typedef int (*cdx_scan_cb)(struct cdx_controller *cdx); ...@@ -39,9 +51,12 @@ typedef int (*cdx_scan_cb)(struct cdx_controller *cdx);
/** /**
* struct cdx_ops - Callbacks supported by CDX controller. * struct cdx_ops - Callbacks supported by CDX controller.
* @scan: scan the devices 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 { struct cdx_ops {
cdx_scan_cb scan; cdx_scan_cb scan;
cdx_dev_configure_cb dev_configure;
}; };
/** /**
...@@ -101,6 +116,8 @@ struct cdx_device { ...@@ -101,6 +116,8 @@ struct cdx_device {
* @probe: Function called when a device is added * @probe: Function called when a device is added
* @remove: Function called when a device is removed * @remove: Function called when a device is removed
* @shutdown: Function called at shutdown time to quiesce the device * @shutdown: Function called at shutdown time to quiesce the device
* @reset_prepare: Function called before is reset to notify driver
* @reset_done: Function called after reset is complete to notify driver
* @driver_managed_dma: Device driver doesn't use kernel DMA API for DMA. * @driver_managed_dma: Device driver doesn't use kernel DMA API for DMA.
* For most device drivers, no need to care about this flag * For most device drivers, no need to care about this flag
* as long as all DMAs are handled through the kernel DMA API. * as long as all DMAs are handled through the kernel DMA API.
...@@ -115,6 +132,8 @@ struct cdx_driver { ...@@ -115,6 +132,8 @@ struct cdx_driver {
int (*probe)(struct cdx_device *dev); int (*probe)(struct cdx_device *dev);
int (*remove)(struct cdx_device *dev); int (*remove)(struct cdx_device *dev);
void (*shutdown)(struct cdx_device *dev); void (*shutdown)(struct cdx_device *dev);
void (*reset_prepare)(struct cdx_device *dev);
void (*reset_done)(struct cdx_device *dev);
bool driver_managed_dma; bool driver_managed_dma;
}; };
...@@ -144,4 +163,12 @@ void cdx_driver_unregister(struct cdx_driver *cdx_driver); ...@@ -144,4 +163,12 @@ void cdx_driver_unregister(struct cdx_driver *cdx_driver);
extern struct bus_type cdx_bus_type; extern struct bus_type cdx_bus_type;
/**
* cdx_dev_reset - Reset CDX device
* @dev: device pointer
*
* Return: 0 for success, -errno on failure
*/
int cdx_dev_reset(struct device *dev);
#endif /* _CDX_BUS_H_ */ #endif /* _CDX_BUS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment