1 /* SPDX-License-Identifier: GPL-2.0 2 * 3 * Copyright 2008-2013 Solarflare Communications Inc. 4 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 5 */ 6 7 #ifndef CDX_MCDI_H 8 #define CDX_MCDI_H 9 10 #include <linux/mutex.h> 11 #include <linux/kref.h> 12 13 #include "bitfield.h" 14 #include "mc_cdx_pcol.h" 15 16 #ifdef DEBUG 17 #define CDX_WARN_ON_ONCE_PARANOID(x) WARN_ON_ONCE(x) 18 #define CDX_WARN_ON_PARANOID(x) WARN_ON(x) 19 #else 20 #define CDX_WARN_ON_ONCE_PARANOID(x) do {} while (0) 21 #define CDX_WARN_ON_PARANOID(x) do {} while (0) 22 #endif 23 24 /** 25 * enum cdx_mcdi_mode - MCDI transaction mode 26 * @MCDI_MODE_EVENTS: wait for an mcdi response callback. 27 * @MCDI_MODE_FAIL: we think MCDI is dead, so fail-fast all calls 28 */ 29 enum cdx_mcdi_mode { 30 MCDI_MODE_EVENTS, 31 MCDI_MODE_FAIL, 32 }; 33 34 #define MCDI_RPC_TIMEOUT (10 * HZ) 35 #define MCDI_RPC_LONG_TIMEOU (60 * HZ) 36 #define MCDI_RPC_POST_RST_TIME (10 * HZ) 37 38 #define MCDI_BUF_LEN (8 + MCDI_CTL_SDU_LEN_MAX) 39 40 /** 41 * enum cdx_mcdi_cmd_state - State for an individual MCDI command 42 * @MCDI_STATE_QUEUED: Command not started and is waiting to run. 43 * @MCDI_STATE_RETRY: Command was submitted and MC rejected with no resources, 44 * as MC have too many outstanding commands. Command will be retried once 45 * another command returns. 46 * @MCDI_STATE_RUNNING: Command was accepted and is running. 47 * @MCDI_STATE_RUNNING_CANCELLED: Command is running but the issuer cancelled 48 * the command. 49 * @MCDI_STATE_FINISHED: Processing of this command has completed. 50 */ 51 52 enum cdx_mcdi_cmd_state { 53 MCDI_STATE_QUEUED, 54 MCDI_STATE_RETRY, 55 MCDI_STATE_RUNNING, 56 MCDI_STATE_RUNNING_CANCELLED, 57 MCDI_STATE_FINISHED, 58 }; 59 60 /** 61 * struct cdx_mcdi - CDX MCDI Firmware interface, to interact 62 * with CDX controller. 63 * @mcdi: MCDI interface 64 * @mcdi_ops: MCDI operations 65 */ 66 struct cdx_mcdi { 67 /* MCDI interface */ 68 struct cdx_mcdi_data *mcdi; 69 const struct cdx_mcdi_ops *mcdi_ops; 70 }; 71 72 struct cdx_mcdi_ops { 73 void (*mcdi_request)(struct cdx_mcdi *cdx, 74 const struct cdx_dword *hdr, size_t hdr_len, 75 const struct cdx_dword *sdu, size_t sdu_len); 76 unsigned int (*mcdi_rpc_timeout)(struct cdx_mcdi *cdx, unsigned int cmd); 77 }; 78 79 typedef void cdx_mcdi_async_completer(struct cdx_mcdi *cdx, 80 unsigned long cookie, int rc, 81 struct cdx_dword *outbuf, 82 size_t outlen_actual); 83 84 /** 85 * struct cdx_mcdi_cmd - An outstanding MCDI command 86 * @ref: Reference count. There will be one reference if the command is 87 * in the mcdi_iface cmd_list, another if it's on a cleanup list, 88 * and a third if it's queued in the work queue. 89 * @list: The data for this entry in mcdi->cmd_list 90 * @cleanup_list: The data for this entry in a cleanup list 91 * @work: The work item for this command, queued in mcdi->workqueue 92 * @mcdi: The mcdi_iface for this command 93 * @state: The state of this command 94 * @inlen: inbuf length 95 * @inbuf: Input buffer 96 * @quiet: Whether to silence errors 97 * @reboot_seen: Whether a reboot has been seen during this command, 98 * to prevent duplicates 99 * @seq: Sequence number 100 * @started: Jiffies this command was started at 101 * @cookie: Context for completion function 102 * @completer: Completion function 103 * @handle: Command handle 104 * @cmd: Command number 105 * @rc: Return code 106 * @outlen: Length of output buffer 107 * @outbuf: Output buffer 108 */ 109 struct cdx_mcdi_cmd { 110 struct kref ref; 111 struct list_head list; 112 struct list_head cleanup_list; 113 struct work_struct work; 114 struct cdx_mcdi_iface *mcdi; 115 enum cdx_mcdi_cmd_state state; 116 size_t inlen; 117 const struct cdx_dword *inbuf; 118 bool quiet; 119 bool reboot_seen; 120 u8 seq; 121 unsigned long started; 122 unsigned long cookie; 123 cdx_mcdi_async_completer *completer; 124 unsigned int handle; 125 unsigned int cmd; 126 int rc; 127 size_t outlen; 128 struct cdx_dword *outbuf; 129 /* followed by inbuf data if necessary */ 130 }; 131 132 /** 133 * struct cdx_mcdi_iface - MCDI protocol context 134 * @cdx: The associated NIC 135 * @iface_lock: Serialise access to this structure 136 * @outstanding_cleanups: Count of cleanups 137 * @cmd_list: List of outstanding and running commands 138 * @workqueue: Workqueue used for delayed processing 139 * @cmd_complete_wq: Waitqueue for command completion 140 * @db_held_by: Command the MC doorbell is in use by 141 * @seq_held_by: Command each sequence number is in use by 142 * @prev_handle: The last used command handle 143 * @mode: Poll for mcdi completion, or wait for an mcdi_event 144 * @prev_seq: The last used sequence number 145 * @new_epoch: Indicates start of day or start of MC reboot recovery 146 * @logging_buffer: Buffer that may be used to build MCDI tracing messages 147 * @logging_enabled: Whether to trace MCDI 148 */ 149 struct cdx_mcdi_iface { 150 struct cdx_mcdi *cdx; 151 /* Serialise access */ 152 struct mutex iface_lock; 153 unsigned int outstanding_cleanups; 154 struct list_head cmd_list; 155 struct workqueue_struct *workqueue; 156 wait_queue_head_t cmd_complete_wq; 157 struct cdx_mcdi_cmd *db_held_by; 158 struct cdx_mcdi_cmd *seq_held_by[16]; 159 unsigned int prev_handle; 160 enum cdx_mcdi_mode mode; 161 u8 prev_seq; 162 bool new_epoch; 163 #ifdef CONFIG_MCDI_LOGGING 164 bool logging_enabled; 165 char *logging_buffer; 166 #endif 167 }; 168 169 /** 170 * struct cdx_mcdi_data - extra state for NICs that implement MCDI 171 * @iface: Interface/protocol state 172 * @fn_flags: Flags for this function, as returned by %MC_CMD_DRV_ATTACH. 173 */ 174 struct cdx_mcdi_data { 175 struct cdx_mcdi_iface iface; 176 u32 fn_flags; 177 }; 178 179 static inline struct cdx_mcdi_iface *cdx_mcdi_if(struct cdx_mcdi *cdx) 180 { 181 return cdx->mcdi ? &cdx->mcdi->iface : NULL; 182 } 183 184 int cdx_mcdi_init(struct cdx_mcdi *cdx); 185 void cdx_mcdi_finish(struct cdx_mcdi *cdx); 186 187 void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len); 188 int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, 189 const struct cdx_dword *inbuf, size_t inlen, 190 struct cdx_dword *outbuf, size_t outlen, size_t *outlen_actual); 191 int cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, 192 const struct cdx_dword *inbuf, size_t inlen, 193 cdx_mcdi_async_completer *complete, 194 unsigned long cookie); 195 int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, 196 unsigned int timeout_jiffies); 197 198 /* 199 * We expect that 16- and 32-bit fields in MCDI requests and responses 200 * are appropriately aligned, but 64-bit fields are only 201 * 32-bit-aligned. 202 */ 203 #define MCDI_DECLARE_BUF(_name, _len) struct cdx_dword _name[DIV_ROUND_UP(_len, 4)] = {{0}} 204 #define _MCDI_PTR(_buf, _offset) \ 205 ((u8 *)(_buf) + (_offset)) 206 #define MCDI_PTR(_buf, _field) \ 207 _MCDI_PTR(_buf, MC_CMD_ ## _field ## _OFST) 208 #define _MCDI_CHECK_ALIGN(_ofst, _align) \ 209 ((void)BUILD_BUG_ON_ZERO((_ofst) & ((_align) - 1)), \ 210 (_ofst)) 211 #define _MCDI_DWORD(_buf, _field) \ 212 ((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2)) 213 214 #define MCDI_BYTE(_buf, _field) \ 215 ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \ 216 *MCDI_PTR(_buf, _field)) 217 #define MCDI_WORD(_buf, _field) \ 218 ((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2), \ 219 le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field))) 220 #define MCDI_SET_DWORD(_buf, _field, _value) \ 221 CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), CDX_DWORD, _value) 222 #define MCDI_DWORD(_buf, _field) \ 223 CDX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), CDX_DWORD) 224 #define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1) \ 225 CDX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), \ 226 MC_CMD_ ## _name1, _value1) 227 #define MCDI_SET_QWORD(_buf, _field, _value) \ 228 do { \ 229 CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[0], \ 230 CDX_DWORD, (u32)(_value)); \ 231 CDX_POPULATE_DWORD_1(_MCDI_DWORD(_buf, _field)[1], \ 232 CDX_DWORD, (u64)(_value) >> 32); \ 233 } while (0) 234 #define MCDI_QWORD(_buf, _field) \ 235 (CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[0], CDX_DWORD) | \ 236 (u64)CDX_DWORD_FIELD(_MCDI_DWORD(_buf, _field)[1], CDX_DWORD) << 32) 237 238 #endif /* CDX_MCDI_H */ 239