1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2019 Solarflare Communications Inc.
5 */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #if EFSYS_OPT_PCI
11
12 __checkReturn efx_rc_t
efx_pci_config_next_ext_cap(__in efsys_pci_config_t * espcp,__in const efx_pci_ops_t * epop,__inout size_t * offsetp)13 efx_pci_config_next_ext_cap(
14 __in efsys_pci_config_t *espcp,
15 __in const efx_pci_ops_t *epop,
16 __inout size_t *offsetp)
17 {
18 efx_dword_t hdr;
19 efx_rc_t rc = 0;
20 size_t next;
21
22 if (offsetp == NULL) {
23 rc = EINVAL;
24 goto fail1;
25 }
26
27 if (*offsetp == 0) {
28 *offsetp = ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE;
29 } else {
30 rc = epop->epo_config_readd(espcp, *offsetp +
31 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
32 &hdr);
33 if (rc != 0) {
34 rc = EIO;
35 goto fail2;
36 }
37
38 next = EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_NEXT);
39 if (next < ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE)
40 rc = ENOENT;
41 else
42 *offsetp = next;
43 }
44
45 /*
46 * Returns 0 if the next capability is present otherwise ENOENT
47 * indicating that the function finished correctly.
48 */
49 return (rc);
50
51 fail2:
52 EFSYS_PROBE(fail2);
53 fail1:
54 EFSYS_PROBE1(fail1, efx_rc_t, rc);
55
56 return (rc);
57 }
58
59 __checkReturn efx_rc_t
efx_pci_config_find_next_ext_cap(__in efsys_pci_config_t * espcp,__in const efx_pci_ops_t * epop,__in uint16_t cap_id,__inout size_t * offsetp)60 efx_pci_config_find_next_ext_cap(
61 __in efsys_pci_config_t *espcp,
62 __in const efx_pci_ops_t *epop,
63 __in uint16_t cap_id,
64 __inout size_t *offsetp)
65 {
66 efx_dword_t hdr;
67 size_t position;
68 efx_rc_t rc;
69
70 if (offsetp == NULL) {
71 rc = EINVAL;
72 goto fail1;
73 }
74
75 position = *offsetp;
76
77 while (1) {
78 rc = efx_pci_config_next_ext_cap(espcp, epop, &position);
79 if (rc != 0) {
80 if (rc == ENOENT)
81 break;
82 else
83 goto fail2;
84 }
85
86 rc = epop->epo_config_readd(espcp, position +
87 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
88 &hdr);
89 if (rc != 0) {
90 rc = EIO;
91 goto fail3;
92 }
93
94 if (EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_ID) ==
95 cap_id) {
96 *offsetp = position;
97 rc = 0;
98 break;
99 }
100 }
101
102 /*
103 * Returns 0 if found otherwise ENOENT indicating that search finished
104 * correctly.
105 */
106 return (rc);
107
108 fail3:
109 EFSYS_PROBE(fail3);
110 fail2:
111 EFSYS_PROBE(fail2);
112 fail1:
113 EFSYS_PROBE1(fail1, efx_rc_t, rc);
114
115 return (rc);
116 }
117
118 __checkReturn efx_rc_t
efx_pci_find_next_xilinx_cap_table(__in efsys_pci_config_t * espcp,__in const efx_pci_ops_t * epop,__inout size_t * pci_cap_offsetp,__out unsigned int * xilinx_tbl_barp,__out efsys_dma_addr_t * xilinx_tbl_offsetp)119 efx_pci_find_next_xilinx_cap_table(
120 __in efsys_pci_config_t *espcp,
121 __in const efx_pci_ops_t *epop,
122 __inout size_t *pci_cap_offsetp,
123 __out unsigned int *xilinx_tbl_barp,
124 __out efsys_dma_addr_t *xilinx_tbl_offsetp)
125 {
126 size_t cap_offset;
127 efx_rc_t rc;
128
129 if (pci_cap_offsetp == NULL) {
130 rc = EINVAL;
131 goto fail1;
132 }
133
134 cap_offset = *pci_cap_offsetp;
135
136 while (1) {
137 unsigned int tbl_bar;
138 efsys_dma_addr_t tbl_offset;
139
140 rc = efx_pci_config_find_next_ext_cap(espcp, epop,
141 ESE_GZ_PCI_EXPRESS_XCAP_ID_VNDR, &cap_offset);
142 if (rc != 0) {
143 if (rc == ENOENT)
144 break;
145 else
146 goto fail2;
147 }
148
149 /*
150 * The found extended PCI capability is a vendor-specific
151 * capability, but not necessarily a Xilinx capabilities table
152 * locator. Try to read it and skip it if the capability is
153 * not the locator.
154 */
155 rc = efx_pci_read_ext_cap_xilinx_table(espcp, epop, cap_offset,
156 &tbl_bar, &tbl_offset);
157 if (rc == 0) {
158 *xilinx_tbl_barp = tbl_bar;
159 *xilinx_tbl_offsetp = tbl_offset;
160 *pci_cap_offsetp = cap_offset;
161 break;
162 } else {
163 if (rc == ENOENT)
164 continue;
165 else
166 goto fail3;
167 }
168 }
169
170 /*
171 * Returns 0 if found otherwise ENOENT indicating that search finished
172 * correctly.
173 */
174 return (rc);
175
176 fail3:
177 EFSYS_PROBE(fail3);
178 fail2:
179 EFSYS_PROBE(fail2);
180 fail1:
181 EFSYS_PROBE1(fail1, efx_rc_t, rc);
182
183 return (rc);
184 }
185
186 __checkReturn efx_rc_t
efx_pci_read_ext_cap_xilinx_table(__in efsys_pci_config_t * espcp,__in const efx_pci_ops_t * epop,__in size_t cap_offset,__out unsigned int * barp,__out efsys_dma_addr_t * offsetp)187 efx_pci_read_ext_cap_xilinx_table(
188 __in efsys_pci_config_t *espcp,
189 __in const efx_pci_ops_t *epop,
190 __in size_t cap_offset,
191 __out unsigned int *barp,
192 __out efsys_dma_addr_t *offsetp)
193 {
194 size_t vsec_offset = cap_offset + ESE_GZ_PCI_EXPRESS_XCAP_HDR_SIZE;
195 efx_dword_t cap_hdr;
196 efx_oword_t vsec;
197 uint32_t vsec_len;
198 uint32_t vsec_id;
199 uint32_t vsec_rev;
200 uint32_t offset_low;
201 uint32_t offset_high = 0;
202 unsigned int bar;
203 efsys_dma_addr_t offset;
204 efx_rc_t rc;
205
206 rc = epop->epo_config_readd(espcp, cap_offset +
207 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
208 &cap_hdr);
209 if (rc != 0) {
210 rc = EIO;
211 goto fail1;
212 }
213
214 if (EFX_DWORD_FIELD(cap_hdr, ESF_GZ_PCI_EXPRESS_XCAP_VER) !=
215 ESE_GZ_PCI_EXPRESS_XCAP_VER_VSEC) {
216 rc = EINVAL;
217 goto fail2;
218 }
219
220 rc = epop->epo_config_readd(espcp, vsec_offset +
221 (EFX_LOW_BIT(ESF_GZ_VSEC_ID) / 8),
222 &vsec.eo_dword[0]);
223 if (rc != 0) {
224 rc = EIO;
225 goto fail3;
226 }
227
228 vsec_len = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_LEN);
229 vsec_id = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_ID);
230 vsec_rev = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_VER);
231
232 /*
233 * Condition of the vendor-specific extended PCI capability not being
234 * a Xilinx capabilities table locator.
235 */
236 if (vsec_id != ESE_GZ_XILINX_VSEC_ID) {
237 rc = ENOENT;
238 goto fail4;
239 }
240
241 if (vsec_rev != ESE_GZ_VSEC_VER_XIL_CFGBAR ||
242 vsec_len < ESE_GZ_VSEC_LEN_MIN) {
243 rc = EINVAL;
244 goto fail5;
245 }
246
247 rc = epop->epo_config_readd(espcp, vsec_offset +
248 (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_BAR) / 8),
249 &vsec.eo_dword[1]);
250 if (rc != 0) {
251 rc = EIO;
252 goto fail6;
253 }
254
255 bar = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_BAR);
256 offset_low = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_LO);
257
258 if (vsec_len >= ESE_GZ_VSEC_LEN_HIGH_OFFT) {
259 rc = epop->epo_config_readd(espcp, vsec_offset +
260 (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_OFF_HI) / 8),
261 &vsec.eo_dword[2]);
262 if (rc != 0) {
263 rc = EIO;
264 goto fail7;
265 }
266
267 offset_high = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_HI);
268 }
269
270 /* High bits of low offset are discarded by the shift */
271 offset = offset_low << ESE_GZ_VSEC_TBL_OFF_LO_BYTES_SHIFT;
272
273 /*
274 * Avoid the 'left shift count >= width of type' warning on systems
275 * without uint64_t support.
276 */
277 #if EFSYS_HAS_UINT64
278 offset |= (uint64_t)offset_high << ESE_GZ_VSEC_TBL_OFF_HI_BYTES_SHIFT;
279 #else
280 _NOTE(ARGUNUSED(offset_high))
281 #endif
282
283 *offsetp = offset;
284 *barp = bar;
285
286 return (0);
287
288 fail7:
289 EFSYS_PROBE(fail7);
290 fail6:
291 EFSYS_PROBE(fail6);
292 fail5:
293 EFSYS_PROBE(fail5);
294 fail4:
295 EFSYS_PROBE(fail4);
296 fail3:
297 EFSYS_PROBE(fail3);
298 fail2:
299 EFSYS_PROBE(fail2);
300 fail1:
301 EFSYS_PROBE1(fail1, efx_rc_t, rc);
302
303 return (rc);
304 }
305
306 __checkReturn efx_rc_t
efx_pci_xilinx_cap_tbl_find(__in efsys_bar_t * esbp,__in uint32_t format_id,__in boolean_t skip_first,__inout efsys_dma_addr_t * entry_offsetp)307 efx_pci_xilinx_cap_tbl_find(
308 __in efsys_bar_t *esbp,
309 __in uint32_t format_id,
310 __in boolean_t skip_first,
311 __inout efsys_dma_addr_t *entry_offsetp)
312 {
313 efsys_dma_addr_t offset;
314 boolean_t skip = skip_first;
315 efx_qword_t header;
316 uint32_t format;
317 uint32_t last;
318 efx_rc_t rc;
319
320 if (entry_offsetp == NULL) {
321 rc = EINVAL;
322 goto fail1;
323 }
324
325 offset = *entry_offsetp;
326 rc = ENOENT;
327 /*
328 * SF-119689-TC Riverhead Host Interface section 4.2.2.
329 * describes the following discovery steps.
330 */
331 do {
332 /*
333 * Xilinx Capabilities Table requires 32bit aligned reads.
334 * See SF-119689-TC section 4.2.2 "Discovery Steps".
335 */
336 EFSYS_BAR_READD(esbp, offset +
337 (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_FORMAT) / 8),
338 &header.eq_dword[0], B_FALSE);
339 EFSYS_BAR_READD(esbp, offset +
340 (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_SIZE) / 8),
341 &header.eq_dword[1], B_FALSE);
342
343 format = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_FORMAT);
344 last = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_LAST);
345
346 if (skip == B_FALSE && format == format_id) {
347 *entry_offsetp = offset;
348 rc = 0;
349 break;
350 }
351
352 offset += EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_SIZE);
353 skip = B_FALSE;
354 } while (last == B_FALSE);
355
356 /*
357 * Returns 0 if found otherwise ENOENT indicating that
358 * search finished correctly.
359 */
360 return (rc);
361
362 fail1:
363 EFSYS_PROBE1(fail1, efx_rc_t, rc);
364
365 return (rc);
366 }
367
368 #endif /* EFSYS_OPT_PCI */
369