Skip to content

Commit e3cfd49

Browse files
abhijitG-xlnxgregkh
authored andcommitted
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 <nipun.gupta@amd.com> Signed-off-by: Nipun Gupta <nipun.gupta@amd.com> Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com> Link: https://lore.kernel.org/r/20231017160505.10640-6-abhijit.gangurde@amd.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ce558a3 commit e3cfd49

File tree

7 files changed

+203
-0
lines changed

7 files changed

+203
-0
lines changed

Documentation/ABI/testing/sysfs-bus-cdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ Description:
2828
of a device manufacturer.
2929
Combination of Vendor ID and Device ID identifies a device.
3030

31+
What: /sys/bus/cdx/devices/.../enable
32+
Date: October 2023
33+
Contact: abhijit.gangurde@amd.com
34+
Description:
35+
CDX bus should be disabled before updating the devices in FPGA.
36+
Writing n/0/off will attempt to disable the CDX bus and.
37+
writing y/1/on will attempt to enable the CDX bus. Reading this file
38+
gives the current state of the bus, 1 for enabled and 0 for disabled.
39+
40+
For example::
41+
42+
# echo 1 > /sys/bus/cdx/.../enable
43+
3144
What: /sys/bus/cdx/devices/.../reset
3245
Date: March 2023
3346
Contact: nipun.gupta@amd.com

drivers/cdx/cdx.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,12 @@ static int cdx_unregister_device(struct device *dev,
124124
void *data)
125125
{
126126
struct cdx_device *cdx_dev = to_cdx_device(dev);
127+
struct cdx_controller *cdx = cdx_dev->cdx;
127128

128129
if (cdx_dev->is_bus) {
129130
device_for_each_child(dev, NULL, cdx_unregister_device);
131+
if (cdx_dev->enabled && cdx->ops->bus_disable)
132+
cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
130133
} else {
131134
kfree(cdx_dev->driver_override);
132135
cdx_dev->driver_override = NULL;
@@ -383,6 +386,41 @@ static ssize_t driver_override_show(struct device *dev,
383386
}
384387
static DEVICE_ATTR_RW(driver_override);
385388

389+
static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
390+
const char *buf, size_t count)
391+
{
392+
struct cdx_device *cdx_dev = to_cdx_device(dev);
393+
struct cdx_controller *cdx = cdx_dev->cdx;
394+
bool enable;
395+
int ret;
396+
397+
if (kstrtobool(buf, &enable) < 0)
398+
return -EINVAL;
399+
400+
if (enable == cdx_dev->enabled)
401+
return count;
402+
403+
if (enable && cdx->ops->bus_enable)
404+
ret = cdx->ops->bus_enable(cdx, cdx_dev->bus_num);
405+
else if (!enable && cdx->ops->bus_disable)
406+
ret = cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
407+
else
408+
ret = -EOPNOTSUPP;
409+
410+
if (!ret)
411+
cdx_dev->enabled = enable;
412+
413+
return ret < 0 ? ret : count;
414+
}
415+
416+
static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf)
417+
{
418+
struct cdx_device *cdx_dev = to_cdx_device(dev);
419+
420+
return sysfs_emit(buf, "%u\n", cdx_dev->enabled);
421+
}
422+
static DEVICE_ATTR_RW(enable);
423+
386424
static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n)
387425
{
388426
struct device *dev = kobj_to_dev(kobj);
@@ -395,6 +433,18 @@ static umode_t cdx_dev_attrs_are_visible(struct kobject *kobj, struct attribute
395433
return 0;
396434
}
397435

436+
static umode_t cdx_bus_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n)
437+
{
438+
struct device *dev = kobj_to_dev(kobj);
439+
struct cdx_device *cdx_dev;
440+
441+
cdx_dev = to_cdx_device(dev);
442+
if (cdx_dev->is_bus)
443+
return a->mode;
444+
445+
return 0;
446+
}
447+
398448
static struct attribute *cdx_dev_attrs[] = {
399449
&dev_attr_remove.attr,
400450
&dev_attr_reset.attr,
@@ -409,8 +459,19 @@ static const struct attribute_group cdx_dev_group = {
409459
.is_visible = cdx_dev_attrs_are_visible,
410460
};
411461

462+
static struct attribute *cdx_bus_dev_attrs[] = {
463+
&dev_attr_enable.attr,
464+
NULL,
465+
};
466+
467+
static const struct attribute_group cdx_bus_dev_group = {
468+
.attrs = cdx_bus_dev_attrs,
469+
.is_visible = cdx_bus_attrs_are_visible,
470+
};
471+
412472
static const struct attribute_group *cdx_dev_groups[] = {
413473
&cdx_dev_group,
474+
&cdx_bus_dev_group,
414475
NULL,
415476
};
416477

@@ -588,8 +649,19 @@ struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num)
588649
goto device_add_fail;
589650
}
590651

652+
if (cdx->ops->bus_enable) {
653+
ret = cdx->ops->bus_enable(cdx, bus_num);
654+
if (ret && ret != -EALREADY) {
655+
dev_err(cdx->dev, "cdx bus enable failed: %d\n", ret);
656+
goto bus_enable_fail;
657+
}
658+
}
659+
660+
cdx_dev->enabled = true;
591661
return &cdx_dev->dev;
592662

663+
bus_enable_fail:
664+
device_del(&cdx_dev->dev);
593665
device_add_fail:
594666
put_device(&cdx_dev->dev);
595667

drivers/cdx/controller/cdx_controller.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ static const struct cdx_mcdi_ops mcdi_ops = {
3333
.mcdi_request = cdx_mcdi_request,
3434
};
3535

36+
static int cdx_bus_enable(struct cdx_controller *cdx, u8 bus_num)
37+
{
38+
return cdx_mcdi_bus_enable(cdx->priv, bus_num);
39+
}
40+
41+
static int cdx_bus_disable(struct cdx_controller *cdx, u8 bus_num)
42+
{
43+
return cdx_mcdi_bus_disable(cdx->priv, bus_num);
44+
}
45+
3646
void cdx_rpmsg_post_probe(struct cdx_controller *cdx)
3747
{
3848
/* Register CDX controller with CDX bus driver */
@@ -128,6 +138,8 @@ static int cdx_scan_devices(struct cdx_controller *cdx)
128138
}
129139

130140
static struct cdx_ops cdx_ops = {
141+
.bus_enable = cdx_bus_enable,
142+
.bus_disable = cdx_bus_disable,
131143
.scan = cdx_scan_devices,
132144
.dev_configure = cdx_configure_device,
133145
};

drivers/cdx/controller/mc_cdx_pcol.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,60 @@
455455
#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST 84
456456
#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN 4
457457

458+
/***********************************/
459+
/*
460+
* MC_CMD_CDX_BUS_DOWN
461+
* Asserting reset on the CDX bus causes all devices on the bus to be quiesced.
462+
* DMA bus mastering is disabled and any pending DMA request are flushed. Once
463+
* the response is returned, the devices are guaranteed to no longer issue DMA
464+
* requests or raise MSI interrupts. Further device MMIO accesses may have
465+
* undefined results. While the bus reset is asserted, any of the enumeration
466+
* or device configuration MCDIs will fail with EAGAIN. It is only legal to
467+
* reload the relevant PL region containing CDX devices if the corresponding CDX
468+
* bus is in reset. Depending on the implementation, the firmware may or may
469+
* not enforce this restriction and it is up to the caller to make sure this
470+
* requirement is satisfied.
471+
*/
472+
#define MC_CMD_CDX_BUS_DOWN 0x4
473+
#define MC_CMD_CDX_BUS_DOWN_MSGSET 0x4
474+
475+
/* MC_CMD_CDX_BUS_DOWN_IN msgrequest */
476+
#define MC_CMD_CDX_BUS_DOWN_IN_LEN 4
477+
/* Bus number to put in reset, in range 0 to BUS_COUNT-1 */
478+
#define MC_CMD_CDX_BUS_DOWN_IN_BUS_OFST 0
479+
#define MC_CMD_CDX_BUS_DOWN_IN_BUS_LEN 4
480+
481+
/*
482+
* MC_CMD_CDX_BUS_DOWN_OUT msgresponse: The bus is quiesced, no further
483+
* upstream traffic for devices on this bus.
484+
*/
485+
#define MC_CMD_CDX_BUS_DOWN_OUT_LEN 0
486+
487+
/***********************************/
488+
/*
489+
* MC_CMD_CDX_BUS_UP
490+
* After bus reset is de-asserted, devices are in a state which is functionally
491+
* equivalent to each device having been reset with MC_CMD_CDX_DEVICE_RESET. In
492+
* other words, device logic is reset in a hardware-specific way, MMIO accesses
493+
* are forwarded to the device, DMA bus mastering is disabled and needs to be
494+
* re-enabled with MC_CMD_CDX_DEVICE_DMA_ENABLE once the driver is ready to
495+
* start servicing DMA. If the underlying number of devices or device resources
496+
* changed (e.g. if PL was reloaded) while the bus was in reset, the bus driver
497+
* is expected to re-enumerate the bus. Returns EALREADY if the bus was already
498+
* up before the call.
499+
*/
500+
#define MC_CMD_CDX_BUS_UP 0x5
501+
#define MC_CMD_CDX_BUS_UP_MSGSET 0x5
502+
503+
/* MC_CMD_CDX_BUS_UP_IN msgrequest */
504+
#define MC_CMD_CDX_BUS_UP_IN_LEN 4
505+
/* Bus number to take out of reset, in range 0 to BUS_COUNT-1 */
506+
#define MC_CMD_CDX_BUS_UP_IN_BUS_OFST 0
507+
#define MC_CMD_CDX_BUS_UP_IN_BUS_LEN 4
508+
509+
/* MC_CMD_CDX_BUS_UP_OUT msgresponse: The bus can now be enumerated. */
510+
#define MC_CMD_CDX_BUS_UP_OUT_LEN 0
511+
458512
/***********************************/
459513
/*
460514
* MC_CMD_CDX_DEVICE_RESET

drivers/cdx/controller/mcdi_functions.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,30 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
124124
return 0;
125125
}
126126

127+
int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num)
128+
{
129+
MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_UP_IN_LEN);
130+
int ret;
131+
132+
MCDI_SET_DWORD(inbuf, CDX_BUS_UP_IN_BUS, bus_num);
133+
ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_UP, inbuf, sizeof(inbuf),
134+
NULL, 0, NULL);
135+
136+
return ret;
137+
}
138+
139+
int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num)
140+
{
141+
MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_DOWN_IN_LEN);
142+
int ret;
143+
144+
MCDI_SET_DWORD(inbuf, CDX_BUS_DOWN_IN_BUS, bus_num);
145+
ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_BUS_DOWN, inbuf, sizeof(inbuf),
146+
NULL, 0, NULL);
147+
148+
return ret;
149+
}
150+
127151
int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num)
128152
{
129153
MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN);

drivers/cdx/controller/mcdi_functions.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
4747
u8 bus_num, u8 dev_num,
4848
struct cdx_dev_params *dev_params);
4949

50+
/**
51+
* cdx_mcdi_bus_enable - Enable CDX bus represented by bus_num
52+
* @cdx: pointer to MCDI interface.
53+
* @bus_num: Bus number.
54+
*
55+
* Return: 0 on success, <0 on failure
56+
*/
57+
int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num);
58+
59+
/**
60+
* cdx_mcdi_bus_disable - Disable CDX bus represented by bus_num
61+
* @cdx: pointer to MCDI interface.
62+
* @bus_num: Bus number.
63+
*
64+
* Return: 0 on success, <0 on failure
65+
*/
66+
int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num);
67+
5068
/**
5169
* cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num
5270
* @cdx: pointer to MCDI interface.

include/linux/cdx/cdx_bus.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct cdx_device_config {
2828
u8 type;
2929
};
3030

31+
typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num);
32+
33+
typedef int (*cdx_bus_disable_cb)(struct cdx_controller *cdx, u8 bus_num);
34+
3135
typedef int (*cdx_scan_cb)(struct cdx_controller *cdx);
3236

3337
typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx,
@@ -49,11 +53,15 @@ typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx,
4953

5054
/**
5155
* struct cdx_ops - Callbacks supported by CDX controller.
56+
* @bus_enable: enable bus on the controller
57+
* @bus_disable: disable bus on the controller
5258
* @scan: scan the devices on the controller
5359
* @dev_configure: configuration like reset, master_enable,
5460
* msi_config etc for a CDX device
5561
*/
5662
struct cdx_ops {
63+
cdx_bus_enable_cb bus_enable;
64+
cdx_bus_disable_cb bus_disable;
5765
cdx_scan_cb scan;
5866
cdx_dev_configure_cb dev_configure;
5967
};
@@ -89,6 +97,7 @@ struct cdx_controller {
8997
* @flags: CDX device flags
9098
* @req_id: Requestor ID associated with CDX device
9199
* @is_bus: Is this bus device
100+
* @enabled: is this bus enabled
92101
* @driver_override: driver name to force a match; do not set directly,
93102
* because core frees it; use driver_set_override() to
94103
* set or clear it.
@@ -106,6 +115,7 @@ struct cdx_device {
106115
u16 flags;
107116
u32 req_id;
108117
bool is_bus;
118+
bool enabled;
109119
const char *driver_override;
110120
};
111121

0 commit comments

Comments
 (0)