From ab1d8dda32e9507ca3bfb6b43661aeaa27f7bd82 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Tue, 26 Aug 2025 10:08:51 +0530 Subject: cdx: don't select CONFIG_GENERIC_MSI_IRQ x86 does not use CONFIG_GENERIC_MSI_IRQ, and trying to enable it anyway results in a build failure: In file included from include/linux/ssb/ssb.h:10, from drivers/ssb/pcihost_wrapper.c:18: include/linux/gpio/driver.h:41:33: error: field 'msiinfo' has incomplete type 41 | msi_alloc_info_t msiinfo; | ^~~~~~~ In file included from include/linux/kvm_host.h:19, from arch/x86/events/intel/core.c:17: include/linux/msi.h:528:33: error: field 'alloc_info' has incomplete type 528 | msi_alloc_info_t alloc_info; Change the driver to actually build without this symbol and remove the incorrect 'select' statements. Fixes: e8b18c11731d ("cdx: Fix missing GENERIC_MSI_IRQ on compile test") Reviewed-by: Robin Murphy Reviewed-by: Nikhil Agarwal Signed-off-by: Arnd Bergmann Signed-off-by: Nipun Gupta Link: https://lore.kernel.org/r/20250826043852.2206008-1-nipun.gupta@amd.com Signed-off-by: Alex Williamson --- drivers/cdx/controller/cdx_controller.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/cdx/controller/cdx_controller.c') diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index fca83141e3e6..5e3fd89b6b56 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -193,7 +193,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev) cdx->ops = &cdx_ops; /* Create MSI domain */ - cdx->msi_domain = cdx_msi_domain_init(&pdev->dev); + 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; -- cgit v1.2.3 From 54fd6bd42e7bd351802ff1d193a2e33e4bfb1836 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Mon, 8 Sep 2025 17:26:45 +0530 Subject: cdx: Split mcdi.h and reorganize headers Move bitfield.h from the CDX controller directory to include/linux/cdx to make them accessible to other drivers. As part of this refactoring, split mcdi.h into two headers: - mcdi.h: retains interface-level declarations - mcdid.h: contains internal definitions and macros This is in preparation for VersalNET EDAC driver that relies on it. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Borislav Petkov (AMD) Acked-by: Nikhil Agarwal Link: https://lore.kernel.org/20250908115649.22903-1-shubhrajyoti.datta@amd.com --- drivers/cdx/controller/bitfield.h | 90 ------------ drivers/cdx/controller/cdx_controller.c | 2 +- drivers/cdx/controller/cdx_rpmsg.c | 2 +- drivers/cdx/controller/mcdi.c | 5 +- drivers/cdx/controller/mcdi.h | 242 -------------------------------- drivers/cdx/controller/mcdi_functions.c | 1 - drivers/cdx/controller/mcdi_functions.h | 3 +- drivers/cdx/controller/mcdid.h | 63 +++++++++ include/linux/cdx/bitfield.h | 90 ++++++++++++ include/linux/cdx/mcdi.h | 192 +++++++++++++++++++++++++ 10 files changed, 352 insertions(+), 338 deletions(-) delete mode 100644 drivers/cdx/controller/bitfield.h delete mode 100644 drivers/cdx/controller/mcdi.h create mode 100644 drivers/cdx/controller/mcdid.h create mode 100644 include/linux/cdx/bitfield.h create mode 100644 include/linux/cdx/mcdi.h (limited to 'drivers/cdx/controller/cdx_controller.c') 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 - -/* 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 fca83141e3e6..3f8b9041babf 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -14,7 +14,7 @@ #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) { diff --git a/drivers/cdx/controller/cdx_rpmsg.c b/drivers/cdx/controller/cdx_rpmsg.c index 04b578a0be17..d4f763323aac 100644 --- a/drivers/cdx/controller/cdx_rpmsg.c +++ b/drivers/cdx/controller/cdx_rpmsg.c @@ -15,7 +15,7 @@ #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" }, diff --git a/drivers/cdx/controller/mcdi.c b/drivers/cdx/controller/mcdi.c index e760f8d347cc..90bf9f7c257b 100644 --- a/drivers/cdx/controller/mcdi.c +++ b/drivers/cdx/controller/mcdi.c @@ -23,9 +23,10 @@ #include #include #include +#include -#include "bitfield.h" -#include "mcdi.h" +#include +#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); 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 -#include -#include - -#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 885c69e6ebe5..8ae2d99be81e 100644 --- a/drivers/cdx/controller/mcdi_functions.c +++ b/drivers/cdx/controller/mcdi_functions.c @@ -5,7 +5,6 @@ #include -#include "mcdi.h" #include "mcdi_functions.h" int cdx_mcdi_get_num_buses(struct cdx_mcdi *cdx) diff --git a/drivers/cdx/controller/mcdi_functions.h b/drivers/cdx/controller/mcdi_functions.h index b9942affdc6b..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 +#include "mcdid.h" #include "../cdx.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 +#include +#include + +#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 */ diff --git a/include/linux/cdx/bitfield.h b/include/linux/cdx/bitfield.h new file mode 100644 index 000000000000..567f8ec47582 --- /dev/null +++ b/include/linux/cdx/bitfield.h @@ -0,0 +1,90 @@ +/* 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 + +/* 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/include/linux/cdx/mcdi.h b/include/linux/cdx/mcdi.h new file mode 100644 index 000000000000..46e3f63b062a --- /dev/null +++ b/include/linux/cdx/mcdi.h @@ -0,0 +1,192 @@ +/* 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 +#include +#include + +#include "linux/cdx/bitfield.h" + +/** + * 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) + +/** + * 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; +}; + +/* + * 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_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) +#endif /* CDX_MCDI_H */ -- cgit v1.2.3