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: Puneet Gupta <puneet.gupta@amd.com> Signed-off-by: Nipun Gupta <nipun.gupta@amd.com> Signed-off-by: Tarak Reddy <tarak.reddy@amd.com> Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com> Tested-by: Nikhil Agarwal <nikhil.agarwal@amd.com> Link: https://lore.kernel.org/r/20230313132636.31850-8-nipun.gupta@amd.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
2a226927d9
commit
48a6c7bced
|
@ -10,3 +10,47 @@ Description:
|
|||
For example::
|
||||
|
||||
# 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 @@
|
|||
/* CDX controllers registered with the CDX bus */
|
||||
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
|
||||
* @dev: CDX device
|
||||
|
@ -237,6 +270,99 @@ static int cdx_dma_configure(struct device *dev)
|
|||
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,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
|
@ -280,6 +406,7 @@ struct bus_type cdx_bus_type = {
|
|||
.shutdown = cdx_shutdown,
|
||||
.dma_configure = cdx_dma_configure,
|
||||
.bus_groups = cdx_bus_groups,
|
||||
.dev_groups = cdx_dev_groups,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cdx_bus_type);
|
||||
|
||||
|
|
|
@ -45,6 +45,23 @@ void cdx_rpmsg_pre_remove(struct cdx_controller *cdx)
|
|||
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)
|
||||
{
|
||||
struct cdx_mcdi *cdx_mcdi = cdx->priv;
|
||||
|
@ -104,6 +121,7 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
|
|||
|
||||
static struct cdx_ops cdx_ops = {
|
||||
.scan = cdx_scan_devices,
|
||||
.dev_configure = cdx_configure_device,
|
||||
};
|
||||
|
||||
static int xlnx_cdx_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -123,3 +123,17 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
|
|||
|
||||
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,
|
|||
u8 bus_num, u8 dev_num,
|
||||
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 */
|
||||
|
|
|
@ -21,8 +21,20 @@
|
|||
/* Forward declaration for 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_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
|
||||
* override_only flags.
|
||||
|
@ -39,9 +51,12 @@ typedef int (*cdx_scan_cb)(struct cdx_controller *cdx);
|
|||
/**
|
||||
* struct cdx_ops - Callbacks supported by CDX 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_scan_cb scan;
|
||||
cdx_dev_configure_cb dev_configure;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -101,6 +116,8 @@ struct cdx_device {
|
|||
* @probe: Function called when a device is added
|
||||
* @remove: Function called when a device is removed
|
||||
* @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.
|
||||
* For most device drivers, no need to care about this flag
|
||||
* as long as all DMAs are handled through the kernel DMA API.
|
||||
|
@ -115,6 +132,8 @@ struct cdx_driver {
|
|||
int (*probe)(struct cdx_device *dev);
|
||||
int (*remove)(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;
|
||||
};
|
||||
|
||||
|
@ -144,4 +163,12 @@ void cdx_driver_unregister(struct cdx_driver *cdx_driver);
|
|||
|
||||
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_ */
|
||||
|
|
Loading…
Reference in New Issue