]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/drivers/net/sfc/base/siena_mcdi.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / sfc / base / siena_mcdi.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2012-2019 Solarflare Communications Inc.
5 */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
11
12 #define SIENA_MCDI_PDU(_emip) \
13 (((emip)->emi_port == 1) \
14 ? MC_SMEM_P0_PDU_OFST >> 2 \
15 : MC_SMEM_P1_PDU_OFST >> 2)
16
17 #define SIENA_MCDI_DOORBELL(_emip) \
18 (((emip)->emi_port == 1) \
19 ? MC_SMEM_P0_DOORBELL_OFST >> 2 \
20 : MC_SMEM_P1_DOORBELL_OFST >> 2)
21
22 #define SIENA_MCDI_STATUS(_emip) \
23 (((emip)->emi_port == 1) \
24 ? MC_SMEM_P0_STATUS_OFST >> 2 \
25 : MC_SMEM_P1_STATUS_OFST >> 2)
26
27
28 void
29 siena_mcdi_send_request(
30 __in efx_nic_t *enp,
31 __in_bcount(hdr_len) void *hdrp,
32 __in size_t hdr_len,
33 __in_bcount(sdu_len) void *sdup,
34 __in size_t sdu_len)
35 {
36 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
37 efx_dword_t dword;
38 unsigned int pdur;
39 unsigned int dbr;
40 unsigned int pos;
41
42 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
43
44 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
45 pdur = SIENA_MCDI_PDU(emip);
46 dbr = SIENA_MCDI_DOORBELL(emip);
47
48 /* Write the header */
49 EFSYS_ASSERT3U(hdr_len, ==, sizeof (efx_dword_t));
50 dword = *(efx_dword_t *)hdrp;
51 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE);
52
53 /* Write the payload */
54 for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
55 dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
56 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
57 pdur + 1 + (pos >> 2), &dword, B_FALSE);
58 }
59
60 /* Ring the doorbell */
61 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
62 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
63 }
64
65 efx_rc_t
66 siena_mcdi_poll_reboot(
67 __in efx_nic_t *enp)
68 {
69 #if 1
70 /*
71 * XXX Bug 25922, bug 26099: This function is not being used
72 * properly. Until its callers are fixed, it should always
73 * return 0.
74 */
75 _NOTE(ARGUNUSED(enp))
76 return (0);
77 #else
78 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
79 unsigned int rebootr;
80 efx_dword_t dword;
81 uint32_t value;
82
83 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
84 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
85 rebootr = SIENA_MCDI_STATUS(emip);
86
87 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
88 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
89
90 if (value == 0)
91 return (0);
92
93 EFX_ZERO_DWORD(dword);
94 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
95
96 if (value == MC_STATUS_DWORD_ASSERT)
97 return (EINTR);
98 else
99 return (EIO);
100 #endif
101 }
102
103 extern __checkReturn boolean_t
104 siena_mcdi_poll_response(
105 __in efx_nic_t *enp)
106 {
107 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
108 efx_dword_t hdr;
109 unsigned int pdur;
110
111 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
112 pdur = SIENA_MCDI_PDU(emip);
113
114 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
115 return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
116 }
117
118 void
119 siena_mcdi_read_response(
120 __in efx_nic_t *enp,
121 __out_bcount(length) void *bufferp,
122 __in size_t offset,
123 __in size_t length)
124 {
125 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
126 unsigned int pdur;
127 unsigned int pos = 0;
128 efx_dword_t data;
129 size_t remaining = length;
130
131 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
132 pdur = SIENA_MCDI_PDU(emip);
133
134 while (remaining > 0) {
135 size_t chunk = MIN(remaining, sizeof (data));
136
137 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
138 pdur + ((offset + pos) >> 2), &data, B_FALSE);
139 memcpy((uint8_t *)bufferp + pos, &data, chunk);
140 pos += chunk;
141 remaining -= chunk;
142 }
143 }
144
145 __checkReturn efx_rc_t
146 siena_mcdi_init(
147 __in efx_nic_t *enp,
148 __in const efx_mcdi_transport_t *mtp)
149 {
150 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
151 efx_oword_t oword;
152 unsigned int portnum;
153 efx_rc_t rc;
154
155 _NOTE(ARGUNUSED(mtp))
156
157 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
158
159 /* Determine the port number to use for MCDI */
160 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
161 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
162
163 if (portnum == 0) {
164 /* Presumably booted from ROM; only MCDI port 1 will work */
165 emip->emi_port = 1;
166 } else if (portnum <= 2) {
167 emip->emi_port = portnum;
168 } else {
169 rc = EINVAL;
170 goto fail1;
171 }
172
173 /* Siena BootROM and firmware only support MCDIv1 */
174 emip->emi_max_version = 1;
175
176 /*
177 * Wipe the atomic reboot status so subsequent MCDI requests succeed.
178 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
179 * assertion handler.
180 */
181 (void) siena_mcdi_poll_reboot(enp);
182
183 return (0);
184
185 fail1:
186 EFSYS_PROBE1(fail1, efx_rc_t, rc);
187
188 return (rc);
189 }
190
191 void
192 siena_mcdi_fini(
193 __in efx_nic_t *enp)
194 {
195 _NOTE(ARGUNUSED(enp))
196 }
197
198 __checkReturn efx_rc_t
199 siena_mcdi_feature_supported(
200 __in efx_nic_t *enp,
201 __in efx_mcdi_feature_id_t id,
202 __out boolean_t *supportedp)
203 {
204 efx_rc_t rc;
205
206 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
207
208 switch (id) {
209 case EFX_MCDI_FEATURE_FW_UPDATE:
210 case EFX_MCDI_FEATURE_LINK_CONTROL:
211 case EFX_MCDI_FEATURE_MACADDR_CHANGE:
212 case EFX_MCDI_FEATURE_MAC_SPOOFING:
213 *supportedp = B_TRUE;
214 break;
215 default:
216 rc = ENOTSUP;
217 goto fail1;
218 }
219
220 return (0);
221
222 fail1:
223 EFSYS_PROBE1(fail1, efx_rc_t, rc);
224
225 return (rc);
226 }
227
228 /* Default timeout for MCDI command processing. */
229 #define SIENA_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000)
230
231 void
232 siena_mcdi_get_timeout(
233 __in efx_nic_t *enp,
234 __in efx_mcdi_req_t *emrp,
235 __out uint32_t *timeoutp)
236 {
237 _NOTE(ARGUNUSED(enp, emrp))
238
239 *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US;
240 }
241
242
243 #endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */