diff options
Diffstat (limited to 'drivers/cdx/controller')
| -rw-r--r-- | drivers/cdx/controller/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/cdx/controller/bitfield.h | 90 | ||||
| -rw-r--r-- | drivers/cdx/controller/cdx_controller.c | 82 | ||||
| -rw-r--r-- | drivers/cdx/controller/cdx_rpmsg.c | 8 | ||||
| -rw-r--r-- | drivers/cdx/controller/mc_cdx_pcol.h | 118 | ||||
| -rw-r--r-- | drivers/cdx/controller/mcdi.c | 47 | ||||
| -rw-r--r-- | drivers/cdx/controller/mcdi.h | 242 | ||||
| -rw-r--r-- | drivers/cdx/controller/mcdi_functions.c | 123 | ||||
| -rw-r--r-- | drivers/cdx/controller/mcdi_functions.h | 67 | ||||
| -rw-r--r-- | drivers/cdx/controller/mcdid.h | 63 |
10 files changed, 468 insertions, 373 deletions
diff --git a/drivers/cdx/controller/Kconfig b/drivers/cdx/controller/Kconfig index 61bf17fbe433..a480b62cbd1f 100644 --- a/drivers/cdx/controller/Kconfig +++ b/drivers/cdx/controller/Kconfig @@ -9,6 +9,7 @@ if CDX_BUS config CDX_CONTROLLER tristate "CDX bus controller" + depends on HAS_DMA select REMOTEPROC select RPMSG help diff --git a/drivers/cdx/controller/bitfield.h b/drivers/cdx/controller/bitfield.h deleted file mode 100644 index 567f8ec47582..000000000000 --- a/drivers/cdx/controller/bitfield.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * - * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2013 Solarflare Communications Inc. - * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. - */ - -#ifndef CDX_BITFIELD_H -#define CDX_BITFIELD_H - -#include <linux/bitfield.h> - -/* Lowest bit numbers and widths */ -#define CDX_DWORD_LBN 0 -#define CDX_DWORD_WIDTH 32 - -/* Specified attribute (e.g. LBN) of the specified field */ -#define CDX_VAL(field, attribute) field ## _ ## attribute -/* Low bit number of the specified field */ -#define CDX_LOW_BIT(field) CDX_VAL(field, LBN) -/* Bit width of the specified field */ -#define CDX_WIDTH(field) CDX_VAL(field, WIDTH) -/* High bit number of the specified field */ -#define CDX_HIGH_BIT(field) (CDX_LOW_BIT(field) + CDX_WIDTH(field) - 1) - -/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */ -struct cdx_dword { - __le32 cdx_u32; -}; - -/* Value expanders for printk */ -#define CDX_DWORD_VAL(dword) \ - ((unsigned int)le32_to_cpu((dword).cdx_u32)) - -/* - * Extract bit field portion [low,high) from the 32-bit little-endian - * element which contains bits [min,max) - */ -#define CDX_DWORD_FIELD(dword, field) \ - (FIELD_GET(GENMASK(CDX_HIGH_BIT(field), CDX_LOW_BIT(field)), \ - le32_to_cpu((dword).cdx_u32))) - -/* - * Creates the portion of the named bit field that lies within the - * range [min,max). - */ -#define CDX_INSERT_FIELD(field, value) \ - (FIELD_PREP(GENMASK(CDX_HIGH_BIT(field), \ - CDX_LOW_BIT(field)), value)) - -/* - * Creates the portion of the named bit fields that lie within the - * range [min,max). - */ -#define CDX_INSERT_FIELDS(field1, value1, \ - field2, value2, \ - field3, value3, \ - field4, value4, \ - field5, value5, \ - field6, value6, \ - field7, value7) \ - (CDX_INSERT_FIELD(field1, (value1)) | \ - CDX_INSERT_FIELD(field2, (value2)) | \ - CDX_INSERT_FIELD(field3, (value3)) | \ - CDX_INSERT_FIELD(field4, (value4)) | \ - CDX_INSERT_FIELD(field5, (value5)) | \ - CDX_INSERT_FIELD(field6, (value6)) | \ - CDX_INSERT_FIELD(field7, (value7))) - -#define CDX_POPULATE_DWORD(dword, ...) \ - (dword).cdx_u32 = cpu_to_le32(CDX_INSERT_FIELDS(__VA_ARGS__)) - -/* Populate a dword field with various numbers of arguments */ -#define CDX_POPULATE_DWORD_7 CDX_POPULATE_DWORD -#define CDX_POPULATE_DWORD_6(dword, ...) \ - CDX_POPULATE_DWORD_7(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_POPULATE_DWORD_5(dword, ...) \ - CDX_POPULATE_DWORD_6(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_POPULATE_DWORD_4(dword, ...) \ - CDX_POPULATE_DWORD_5(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_POPULATE_DWORD_3(dword, ...) \ - CDX_POPULATE_DWORD_4(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_POPULATE_DWORD_2(dword, ...) \ - CDX_POPULATE_DWORD_3(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_POPULATE_DWORD_1(dword, ...) \ - CDX_POPULATE_DWORD_2(dword, CDX_DWORD, 0, __VA_ARGS__) -#define CDX_SET_DWORD(dword) \ - CDX_POPULATE_DWORD_1(dword, CDX_DWORD, 0xffffffff) - -#endif /* CDX_BITFIELD_H */ diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index dc52f95f8978..280f207735da 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -5,14 +5,16 @@ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. */ -#include <linux/of_platform.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/cdx/cdx_bus.h> +#include <linux/irqdomain.h> #include "cdx_controller.h" #include "../cdx.h" #include "mcdi_functions.h" -#include "mcdi.h" +#include "mcdid.h" static unsigned int cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd) { @@ -32,6 +34,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 */ @@ -49,12 +61,29 @@ static int cdx_configure_device(struct cdx_controller *cdx, u8 bus_num, u8 dev_num, struct cdx_device_config *dev_config) { + u16 msi_index; int ret = 0; + u32 data; + u64 addr; switch (dev_config->type) { + case CDX_DEV_MSI_CONF: + msi_index = dev_config->msi.msi_index; + data = dev_config->msi.data; + addr = dev_config->msi.addr; + + ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data); + break; case CDX_DEV_RESET_CONF: ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num); break; + case CDX_DEV_BUS_MASTER_CONF: + ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num, + dev_config->bus_master_enable); + break; + case CDX_DEV_MSI_ENABLE: + ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable); + break; default: ret = -EINVAL; } @@ -78,8 +107,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) { @@ -102,6 +137,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); @@ -120,6 +156,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, }; @@ -154,17 +192,25 @@ static int xlnx_cdx_probe(struct platform_device *pdev) cdx->priv = cdx_mcdi; cdx->ops = &cdx_ops; + /* Create MSI domain */ + if (IS_ENABLED(CONFIG_GENERIC_MSI_IRQ)) + cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); + if (!cdx->msi_domain) { + ret = dev_err_probe(&pdev->dev, -ENODEV, "cdx_msi_domain_init() failed"); + goto cdx_msi_fail; + } + ret = cdx_setup_rpmsg(pdev); if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to register CDX RPMsg transport\n"); + dev_err_probe(&pdev->dev, ret, "Failed to register CDX RPMsg transport\n"); goto cdx_rpmsg_fail; } - dev_info(&pdev->dev, "Successfully registered CDX controller with RPMsg as transport\n"); return 0; cdx_rpmsg_fail: + irq_domain_remove(cdx->msi_domain); +cdx_msi_fail: kfree(cdx); cdx_alloc_fail: cdx_mcdi_finish(cdx_mcdi); @@ -174,19 +220,18 @@ mcdi_init_fail: return ret; } -static int xlnx_cdx_remove(struct platform_device *pdev) +static void xlnx_cdx_remove(struct platform_device *pdev) { struct cdx_controller *cdx = platform_get_drvdata(pdev); struct cdx_mcdi *cdx_mcdi = cdx->priv; cdx_destroy_rpmsg(pdev); + irq_domain_remove(cdx->msi_domain); kfree(cdx); cdx_mcdi_finish(cdx_mcdi); kfree(cdx_mcdi); - - return 0; } static const struct of_device_id cdx_match_table[] = { @@ -199,32 +244,15 @@ MODULE_DEVICE_TABLE(of, cdx_match_table); static struct platform_driver cdx_pdriver = { .driver = { .name = "cdx-controller", - .pm = NULL, .of_match_table = cdx_match_table, }, .probe = xlnx_cdx_probe, .remove = xlnx_cdx_remove, }; -static int __init cdx_controller_init(void) -{ - int ret; - - ret = platform_driver_register(&cdx_pdriver); - if (ret) - pr_err("platform_driver_register() failed: %d\n", ret); - - return ret; -} - -static void __exit cdx_controller_exit(void) -{ - platform_driver_unregister(&cdx_pdriver); -} - -module_init(cdx_controller_init); -module_exit(cdx_controller_exit); +module_platform_driver(cdx_pdriver); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("CDX controller for AMD devices"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("CDX_BUS_CONTROLLER"); diff --git a/drivers/cdx/controller/cdx_rpmsg.c b/drivers/cdx/controller/cdx_rpmsg.c index f37e639d6ce3..59aabd99fa8f 100644 --- a/drivers/cdx/controller/cdx_rpmsg.c +++ b/drivers/cdx/controller/cdx_rpmsg.c @@ -7,14 +7,15 @@ #include <linux/rpmsg.h> #include <linux/remoteproc.h> -#include <linux/of_platform.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/cdx/cdx_bus.h> #include <linux/module.h> #include "../cdx.h" #include "cdx_controller.h" #include "mcdi_functions.h" -#include "mcdi.h" +#include "mcdid.h" static struct rpmsg_device_id cdx_rpmsg_id_table[] = { { .name = "mcdi_ipc" }, @@ -128,8 +129,7 @@ static int cdx_rpmsg_probe(struct rpmsg_device *rpdev) chinfo.src = RPMSG_ADDR_ANY; chinfo.dst = rpdev->dst; - strscpy(chinfo.name, cdx_rpmsg_id_table[0].name, - strlen(cdx_rpmsg_id_table[0].name)); + strscpy(chinfo.name, cdx_rpmsg_id_table[0].name, sizeof(chinfo.name)); cdx_mcdi->ept = rpmsg_create_ept(rpdev, cdx_rpmsg_cb, NULL, chinfo); if (!cdx_mcdi->ept) { diff --git a/drivers/cdx/controller/mc_cdx_pcol.h b/drivers/cdx/controller/mc_cdx_pcol.h index 4ccb7b52951b..832a44af963e 100644 --- a/drivers/cdx/controller/mc_cdx_pcol.h +++ b/drivers/cdx/controller/mc_cdx_pcol.h @@ -455,6 +455,66 @@ #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_GET_DEVICE_CONFIG_OUT_V2 msgresponse */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN 92 +/* Requester ID used by device for GIC ITS DeviceID */ +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST 88 +#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_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 @@ -563,6 +623,64 @@ #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH 1 /***********************************/ +/* + * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG + * Populates the MSI message to be used by the hardware to raise the specified + * interrupt vector. Versal-net implementation specific limitations are that + * only 4 CDX devices with MSI interrupt capability are supported and all + * vectors within a device must use the same write address. The command will + * return EINVAL if any of these limitations is violated. + */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG 0x9 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET 0x9 +#undef MC_CMD_0x9_PRIVILEGE_CTG + +#define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN 28 +/* Device bus number, in range 0 to BUS_COUNT-1 */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST 0 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN 4 +/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST 4 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN 4 +/* + * Device-relative MSI vector number. Must be < MSI_COUNT reported for the + * device. + */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST 8 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN 4 +/* Reserved (alignment) */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST 12 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN 4 +/* + * MSI address to be used by the hardware. Typically, on ARM systems this + * address is translated by the IOMMU (if enabled) and it is the responsibility + * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA + * here. + */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST 16 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN 8 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST 16 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN 4 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN 128 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH 32 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST 20 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN 4 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN 160 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH 32 +/* + * MSI data to be used by the hardware. On versal-net, only the lower 16-bits + * are used, the remaining bits are ignored and should be set to zero. + */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST 24 +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN 4 + +/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */ +#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN 0 + +/***********************************/ /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */ #define MC_CMD_V2_EXTN 0x7f diff --git a/drivers/cdx/controller/mcdi.c b/drivers/cdx/controller/mcdi.c index 1eedc5eeb315..2e82ffc18d89 100644 --- a/drivers/cdx/controller/mcdi.c +++ b/drivers/cdx/controller/mcdi.c @@ -23,13 +23,10 @@ #include <linux/log2.h> #include <linux/net_tstamp.h> #include <linux/wait.h> +#include <linux/cdx/bitfield.h> -#include "bitfield.h" -#include "mcdi.h" - -struct cdx_mcdi_copy_buffer { - struct cdx_dword buffer[DIV_ROUND_UP(MCDI_CTL_SDU_LEN_MAX, 4)]; -}; +#include <linux/cdx/mcdi.h> +#include "mcdid.h" static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd); static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx); @@ -103,6 +100,19 @@ static unsigned long cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd return cdx->mcdi_ops->mcdi_rpc_timeout(cdx, cmd); } +/** + * cdx_mcdi_init - Initialize MCDI (Management Controller Driver Interface) state + * @cdx: Handle to the CDX MCDI structure + * + * This function allocates and initializes internal MCDI structures and resources + * for the CDX device, including the workqueue, locking primitives, and command + * tracking mechanisms. It sets the initial operating mode and prepares the device + * for MCDI operations. + * + * Return: + * * 0 - on success + * * -ENOMEM - if memory allocation or workqueue creation fails + */ int cdx_mcdi_init(struct cdx_mcdi *cdx) { struct cdx_mcdi_iface *mcdi; @@ -132,7 +142,16 @@ fail2: fail: return rc; } +EXPORT_SYMBOL_GPL(cdx_mcdi_init); +/** + * cdx_mcdi_finish - Cleanup MCDI (Management Controller Driver Interface) state + * @cdx: Handle to the CDX MCDI structure + * + * This function is responsible for cleaning up the MCDI (Management Controller Driver Interface) + * resources associated with a cdx_mcdi structure. Also destroys the mcdi workqueue. + * + */ void cdx_mcdi_finish(struct cdx_mcdi *cdx) { struct cdx_mcdi_iface *mcdi; @@ -147,6 +166,7 @@ void cdx_mcdi_finish(struct cdx_mcdi *cdx) kfree(cdx->mcdi); cdx->mcdi = NULL; } +EXPORT_SYMBOL_GPL(cdx_mcdi_finish); static bool cdx_mcdi_flushed(struct cdx_mcdi_iface *mcdi, bool ignore_cleanups) { @@ -557,6 +577,19 @@ static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi, cdx_mcdi_cmd_start_or_queue(mcdi, cmd); } +/** + * cdx_mcdi_process_cmd - Process an incoming MCDI response + * @cdx: Handle to the CDX MCDI structure + * @outbuf: Pointer to the response buffer received from the management controller + * @len: Length of the response buffer in bytes + * + * This function handles a response from the management controller. It locates the + * corresponding command using the sequence number embedded in the header, + * completes the command if it is still pending, and initiates any necessary cleanup. + * + * The function assumes that the response buffer is well-formed and at least one + * dword in size. + */ void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len) { struct cdx_mcdi_iface *mcdi; @@ -594,6 +627,7 @@ void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int le cdx_mcdi_process_cleanup_list(mcdi->cdx, &cleanup_list); } +EXPORT_SYMBOL_GPL(cdx_mcdi_process_cmd); static void cdx_mcdi_cmd_work(struct work_struct *context) { @@ -761,6 +795,7 @@ int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, return cdx_mcdi_rpc_sync(cdx, cmd, inbuf, inlen, outbuf, outlen, outlen_actual, false); } +EXPORT_SYMBOL_GPL(cdx_mcdi_rpc); /** * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously diff --git a/drivers/cdx/controller/mcdi.h b/drivers/cdx/controller/mcdi.h deleted file mode 100644 index 54a65e9760ae..000000000000 --- a/drivers/cdx/controller/mcdi.h +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 - * - * Copyright 2008-2013 Solarflare Communications Inc. - * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. - */ - -#ifndef CDX_MCDI_H -#define CDX_MCDI_H - -#include <linux/mutex.h> -#include <linux/kref.h> -#include <linux/rpmsg.h> - -#include "bitfield.h" -#include "mc_cdx_pcol.h" - -#ifdef DEBUG -#define CDX_WARN_ON_ONCE_PARANOID(x) WARN_ON_ONCE(x) -#define CDX_WARN_ON_PARANOID(x) WARN_ON(x) -#else -#define CDX_WARN_ON_ONCE_PARANOID(x) do {} while (0) -#define CDX_WARN_ON_PARANOID(x) do {} while (0) -#endif - -/** - * enum cdx_mcdi_mode - MCDI transaction mode - * @MCDI_MODE_EVENTS: wait for an mcdi response callback. - * @MCDI_MODE_FAIL: we think MCDI is dead, so fail-fast all calls - */ -enum cdx_mcdi_mode { - MCDI_MODE_EVENTS, - MCDI_MODE_FAIL, -}; - -#define MCDI_RPC_TIMEOUT (10 * HZ) -#define MCDI_RPC_LONG_TIMEOU (60 * HZ) -#define MCDI_RPC_POST_RST_TIME (10 * HZ) - -#define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) - -/** - * enum cdx_mcdi_cmd_state - State for an individual MCDI command - * @MCDI_STATE_QUEUED: Command not started and is waiting to run. - * @MCDI_STATE_RETRY: Command was submitted and MC rejected with no resources, - * as MC have too many outstanding commands. Command will be retried once - * another command returns. - * @MCDI_STATE_RUNNING: Command was accepted and is running. - * @MCDI_STATE_RUNNING_CANCELLED: Command is running but the issuer cancelled - * the command. - * @MCDI_STATE_FINISHED: Processing of this command has completed. - */ - -enum cdx_mcdi_cmd_state { - MCDI_STATE_QUEUED, - MCDI_STATE_RETRY, - MCDI_STATE_RUNNING, - MCDI_STATE_RUNNING_CANCELLED, - MCDI_STATE_FINISHED, -}; - -/** - * struct cdx_mcdi - CDX MCDI Firmware interface, to interact - * with CDX controller. - * @mcdi: MCDI interface - * @mcdi_ops: MCDI operations - * @r5_rproc : R5 Remoteproc device handle - * @rpdev: RPMsg device - * @ept: RPMsg endpoint - * @work: Post probe work - */ -struct cdx_mcdi { - /* MCDI interface */ - struct cdx_mcdi_data *mcdi; - const struct cdx_mcdi_ops *mcdi_ops; - - struct rproc *r5_rproc; - struct rpmsg_device *rpdev; - struct rpmsg_endpoint *ept; - struct work_struct work; -}; - -struct cdx_mcdi_ops { - void (*mcdi_request)(struct cdx_mcdi *cdx, - const struct cdx_dword *hdr, size_t hdr_len, - const struct cdx_dword *sdu, size_t sdu_len); - unsigned int (*mcdi_rpc_timeout)(struct cdx_mcdi *cdx, unsigned int cmd); -}; - -typedef void cdx_mcdi_async_completer(struct cdx_mcdi *cdx, - unsigned long cookie, int rc, - struct cdx_dword *outbuf, - size_t outlen_actual); - -/** - * struct cdx_mcdi_cmd - An outstanding MCDI command - * @ref: Reference count. There will be one reference if the command is - * in the mcdi_iface cmd_list, another if it's on a cleanup list, - * and a third if it's queued in the work queue. - * @list: The data for this entry in mcdi->cmd_list - * @cleanup_list: The data for this entry in a cleanup list - * @work: The work item for this command, queued in mcdi->workqueue - * @mcdi: The mcdi_iface for this command - * @state: The state of this command - * @inlen: inbuf length - * @inbuf: Input buffer - * @quiet: Whether to silence errors - * @reboot_seen: Whether a reboot has been seen during this command, - * to prevent duplicates - * @seq: Sequence number - * @started: Jiffies this command was started at - * @cookie: Context for completion function - * @completer: Completion function - * @handle: Command handle - * @cmd: Command number - * @rc: Return code - * @outlen: Length of output buffer - * @outbuf: Output buffer - */ -struct cdx_mcdi_cmd { - struct kref ref; - struct list_head list; - struct list_head cleanup_list; - struct work_struct work; - struct cdx_mcdi_iface *mcdi; - enum cdx_mcdi_cmd_state state; - size_t inlen; - const struct cdx_dword *inbuf; - bool quiet; - bool reboot_seen; - u8 seq; - unsigned long started; - unsigned long cookie; - cdx_mcdi_async_completer *completer; - unsigned int handle; - unsigned int cmd; - int rc; - size_t outlen; - struct cdx_dword *outbuf; - /* followed by inbuf data if necessary */ -}; - -/** - * struct cdx_mcdi_iface - MCDI protocol context - * @cdx: The associated NIC - * @iface_lock: Serialise access to this structure - * @outstanding_cleanups: Count of cleanups - * @cmd_list: List of outstanding and running commands - * @workqueue: Workqueue used for delayed processing - * @cmd_complete_wq: Waitqueue for command completion - * @db_held_by: Command the MC doorbell is in use by - * @seq_held_by: Command each sequence number is in use by - * @prev_handle: The last used command handle - * @mode: Poll for mcdi completion, or wait for an mcdi_event - * @prev_seq: The last used sequence number - * @new_epoch: Indicates start of day or start of MC reboot recovery - */ -struct cdx_mcdi_iface { - struct cdx_mcdi *cdx; - /* Serialise access */ - struct mutex iface_lock; - unsigned int outstanding_cleanups; - struct list_head cmd_list; - struct workqueue_struct *workqueue; - wait_queue_head_t cmd_complete_wq; - struct cdx_mcdi_cmd *db_held_by; - struct cdx_mcdi_cmd *seq_held_by[16]; - unsigned int prev_handle; - enum cdx_mcdi_mode mode; - u8 prev_seq; - bool new_epoch; -}; - -/** - * struct cdx_mcdi_data - extra state for NICs that implement MCDI - * @iface: Interface/protocol state - * @fn_flags: Flags for this function, as returned by %MC_CMD_DRV_ATTACH. - */ -struct cdx_mcdi_data { - struct cdx_mcdi_iface iface; - u32 fn_flags; -}; - -static inline struct cdx_mcdi_iface *cdx_mcdi_if(struct cdx_mcdi *cdx) -{ - return cdx->mcdi ? &cdx->mcdi->iface : NULL; -} - -int cdx_mcdi_init(struct cdx_mcdi *cdx); -void cdx_mcdi_finish(struct cdx_mcdi *cdx); - -void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len); -int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, - const struct cdx_dword *inbuf, size_t inlen, - struct cdx_dword *outbuf, size_t outlen, size_t *outlen_actual); -int cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, - const struct cdx_dword *inbuf, size_t inlen, - cdx_mcdi_async_completer *complete, - unsigned long cookie); -int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, - unsigned int timeout_jiffies); - -/* - * We expect that 16- and 32-bit fields in MCDI requests and responses - * are appropriately aligned, but 64-bit fields are only - * 32-bit-aligned. - */ -#define MCDI_DECLARE_BUF(_name, _len) struct cdx_dword _name[DIV_ROUND_UP(_len, 4)] = {{0}} -#define _MCDI_PTR(_buf, _offset) \ - ((u8 *)(_buf) + (_offset)) -#define MCDI_PTR(_buf, _field) \ - _MCDI_PTR(_buf, MC_CMD_ ## _field ## _OFST) -#define _MCDI_CHECK_ALIGN(_ofst, _align) \ - ((void)BUILD_BUG_ON_ZERO((_ofst) & ((_align) - 1)), \ - (_ofst)) -#define _MCDI_DWORD(_buf, _field) \ - ((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2)) - -#define MCDI_BYTE(_buf, _field) \ - ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ - *MCDI_PTR(_buf, _field)) -#define MCDI_WORD(_buf, _field) \ - ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2), \ - le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) -#define MCDI_SET_DWORD(_buf, _field, _value) \ - CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), CDX_DWORD, _value) -#define MCDI_DWORD(_buf, _field) \ - CDX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), CDX_DWORD) -#define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \ - CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \ - MC_CMD_ ## _name1, _value1) -#define MCDI_SET_QWORD(_buf, _field, _value) \ - do { \ - CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[0], \ - CDX_DWORD, (u32)(_value)); \ - CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[1], \ - CDX_DWORD, (u64)(_value) >> 32); \ - } while (0) -#define MCDI_QWORD(_buf, _field) \ - (CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[0], CDX_DWORD) | \ - (u64)CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[1], CDX_DWORD) << 32) - -#endif /* CDX_MCDI_H */ diff --git a/drivers/cdx/controller/mcdi_functions.c b/drivers/cdx/controller/mcdi_functions.c index 0158f26533dd..8ae2d99be81e 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -5,7 +5,6 @@ #include <linux/module.h> -#include "mcdi.h" #include "mcdi_functions.h" int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx) @@ -49,7 +48,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, struct cdx_dev_params *dev_params) { - MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN); MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN); struct resource *res = &dev_params->res[0]; size_t outlen; @@ -64,7 +63,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, if (ret) return ret; - if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN) + if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN) return -EIO; dev_params->bus_num = bus_num; @@ -73,6 +72,9 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID); dev_params->req_id = req_id; + dev_params->msi_dev_id = MCDI_DWORD(outbuf, + CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID); + dev_params->res_count = 0; if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) { res[dev_params->res_count].start = @@ -120,10 +122,60 @@ 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); + dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT); 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_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, + u32 msi_vector, u64 msi_address, u32 msi_data) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN); + int ret; + + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector); + MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data); + + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, 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); @@ -137,3 +189,68 @@ int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num) return ret; } + +static int cdx_mcdi_ctrl_flag_get(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, u32 *flags) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN); + size_t outlen; + int ret; + + MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_BUS, bus_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_GET_IN_DEVICE, dev_num); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_GET, inbuf, + sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); + if (ret) + return ret; + + if (outlen != MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_LEN) + return -EIO; + + *flags = MCDI_DWORD(outbuf, CDX_DEVICE_CONTROL_GET_OUT_FLAGS); + + return 0; +} + +static int cdx_mcdi_ctrl_flag_set(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, bool enable, int bit_pos) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_CONTROL_SET_IN_LEN); + u32 flags; + int ret; + + /* + * Get flags and then set/reset bit at bit_pos according to + * the input params. + */ + ret = cdx_mcdi_ctrl_flag_get(cdx, bus_num, dev_num, &flags); + if (ret) + return ret; + + flags = flags & (u32)(~(BIT(bit_pos))); + if (enable) + flags |= (1 << bit_pos); + + MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_BUS, bus_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_DEVICE, dev_num); + MCDI_SET_DWORD(inbuf, CDX_DEVICE_CONTROL_SET_IN_FLAGS, flags); + ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_CONTROL_SET, inbuf, + sizeof(inbuf), NULL, 0, NULL); + + return ret; +} + +int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, bool enable) +{ + return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, + MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN); +} + +int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, bool enable) +{ + return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable, + MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN); +} diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h index 7440ace5539a..57fd1bae706b 100644 --- a/drivers/cdx/controller/mcdi_functions.h +++ b/drivers/cdx/controller/mcdi_functions.h @@ -8,7 +8,8 @@ #ifndef CDX_MCDI_FUNCTIONS_H #define CDX_MCDI_FUNCTIONS_H -#include "mcdi.h" +#include <linux/cdx/mcdi.h> +#include "mcdid.h" #include "../cdx.h" /** @@ -48,6 +49,44 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, 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_write_msi - Write MSI configuration for CDX device + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * @dev_num: Device number. + * @msi_vector: Device-relative MSI vector number. + * Must be < MSI_COUNT reported for the device. + * @msi_address: MSI address to be used by the hardware. Typically, on ARM + * systems this address is translated by the IOMMU (if enabled) and + * it is the responsibility of the entity managing the IOMMU (APU kernel) + * to supply the correct IOVA here. + * @msi_data: MSI data to be used by the hardware. On versal-net, only the + * lower 16-bits are used, the remaining bits are ignored and should be + * set to zero. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num, + u32 msi_vector, u64 msi_address, u32 msi_data); + +/** * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num * @cdx: pointer to MCDI interface. * @bus_num: Bus number. @@ -58,4 +97,30 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx, int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num); +/** + * cdx_mcdi_bus_master_enable - Set/Reset bus mastering for cdx device + * represented by bus_num:dev_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * @dev_num: Device number. + * @enable: Enable bus mastering if set, disable otherwise. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, bool enable); + +/** + * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented + * by bus_num:dev_num + * @cdx: pointer to MCDI interface. + * @bus_num: Bus number. + * @dev_num: Device number. + * @enable: Enable msi's if set, disable otherwise. + * + * Return: 0 on success, <0 on failure + */ +int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num, + u8 dev_num, bool enable); + #endif /* CDX_MCDI_FUNCTIONS_H */ diff --git a/drivers/cdx/controller/mcdid.h b/drivers/cdx/controller/mcdid.h new file mode 100644 index 000000000000..7fc29f099265 --- /dev/null +++ b/drivers/cdx/controller/mcdid.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright 2008-2013 Solarflare Communications Inc. + * Copyright (C) 2022-2025, Advanced Micro Devices, Inc. + */ + +#ifndef CDX_MCDID_H +#define CDX_MCDID_H + +#include <linux/mutex.h> +#include <linux/kref.h> +#include <linux/rpmsg.h> + +#include "mc_cdx_pcol.h" + +#ifdef DEBUG +#define CDX_WARN_ON_ONCE_PARANOID(x) WARN_ON_ONCE(x) +#define CDX_WARN_ON_PARANOID(x) WARN_ON(x) +#else +#define CDX_WARN_ON_ONCE_PARANOID(x) do {} while (0) +#define CDX_WARN_ON_PARANOID(x) do {} while (0) +#endif + +#define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) + +static inline struct cdx_mcdi_iface *cdx_mcdi_if(struct cdx_mcdi *cdx) +{ + return cdx->mcdi ? &cdx->mcdi->iface : NULL; +} + +int cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, + const struct cdx_dword *inbuf, size_t inlen, + cdx_mcdi_async_completer *complete, + unsigned long cookie); +int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, + unsigned int timeout_jiffies); + +/* + * We expect that 16- and 32-bit fields in MCDI requests and responses + * are appropriately aligned, but 64-bit fields are only + * 32-bit-aligned. + */ +#define MCDI_BYTE(_buf, _field) \ + ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ + *MCDI_PTR(_buf, _field)) +#define MCDI_WORD(_buf, _field) \ + ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2), \ + le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) +#define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \ + CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \ + MC_CMD_ ## _name1, _value1) +#define MCDI_SET_QWORD(_buf, _field, _value) \ + do { \ + CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[0], \ + CDX_DWORD, (u32)(_value)); \ + CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[1], \ + CDX_DWORD, (u64)(_value) >> 32); \ + } while (0) +#define MCDI_QWORD(_buf, _field) \ + (CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[0], CDX_DWORD) | \ + (u64)CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[1], CDX_DWORD) << 32) + +#endif /* CDX_MCDID_H */ |
