1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2019 Solarflare Communications Inc.
12 __checkReturn efx_rc_t
13 efx_pci_config_next_ext_cap(
14 __in efsys_pci_config_t *espcp,
15 __inout size_t *offsetp)
21 if (offsetp == NULL) {
27 *offsetp = ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE;
29 EFSYS_PCI_CONFIG_READD(espcp, *offsetp +
30 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
37 next = EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_NEXT);
38 if (next < ESE_GZ_PCI_BASE_CONFIG_SPACE_SIZE)
45 * Returns 0 if the next capability is present otherwise ENOENT
46 * indicating that the function finished correctly.
53 EFSYS_PROBE1(fail1, efx_rc_t, rc);
58 __checkReturn efx_rc_t
59 efx_pci_config_find_next_ext_cap(
60 __in efsys_pci_config_t *espcp,
62 __inout size_t *offsetp)
68 if (offsetp == NULL) {
76 rc = efx_pci_config_next_ext_cap(espcp, &position);
84 EFSYS_PCI_CONFIG_READD(espcp, position +
85 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
92 if (EFX_DWORD_FIELD(hdr, ESF_GZ_PCI_EXPRESS_XCAP_ID) ==
101 * Returns 0 if found otherwise ENOENT indicating that search finished
111 EFSYS_PROBE1(fail1, efx_rc_t, rc);
116 __checkReturn efx_rc_t
117 efx_pci_find_next_xilinx_cap_table(
118 __in efsys_pci_config_t *espcp,
119 __inout size_t *pci_cap_offsetp,
120 __out unsigned int *xilinx_tbl_barp,
121 __out efsys_dma_addr_t *xilinx_tbl_offsetp)
126 if (pci_cap_offsetp == NULL) {
131 cap_offset = *pci_cap_offsetp;
134 unsigned int tbl_bar;
135 efsys_dma_addr_t tbl_offset;
137 rc = efx_pci_config_find_next_ext_cap(espcp,
138 ESE_GZ_PCI_EXPRESS_XCAP_ID_VNDR, &cap_offset);
147 * The found extended PCI capability is a vendor-specific
148 * capability, but not necessarily a Xilinx capabilities table
149 * locator. Try to read it and skip it if the capability is
152 rc = efx_pci_read_ext_cap_xilinx_table(espcp, cap_offset,
153 &tbl_bar, &tbl_offset);
155 *xilinx_tbl_barp = tbl_bar;
156 *xilinx_tbl_offsetp = tbl_offset;
157 *pci_cap_offsetp = cap_offset;
168 * Returns 0 if found otherwise ENOENT indicating that search finished
178 EFSYS_PROBE1(fail1, efx_rc_t, rc);
183 __checkReturn efx_rc_t
184 efx_pci_read_ext_cap_xilinx_table(
185 __in efsys_pci_config_t *espcp,
186 __in size_t cap_offset,
187 __out unsigned int *barp,
188 __out efsys_dma_addr_t *offsetp)
190 size_t vsec_offset = cap_offset + ESE_GZ_PCI_EXPRESS_XCAP_HDR_SIZE;
197 uint32_t offset_high = 0;
199 efsys_dma_addr_t offset;
202 EFSYS_PCI_CONFIG_READD(espcp, cap_offset +
203 (EFX_LOW_BIT(ESF_GZ_PCI_EXPRESS_XCAP_ID) / 8),
210 if (EFX_DWORD_FIELD(cap_hdr, ESF_GZ_PCI_EXPRESS_XCAP_VER) !=
211 ESE_GZ_PCI_EXPRESS_XCAP_VER_VSEC) {
216 EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
217 (EFX_LOW_BIT(ESF_GZ_VSEC_ID) / 8),
218 &vsec.eo_dword[0], &rc);
224 vsec_len = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_LEN);
225 vsec_id = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_ID);
226 vsec_rev = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_VER);
229 * Condition of the vendor-specific extended PCI capability not being
230 * a Xilinx capabilities table locator.
232 if (vsec_id != ESE_GZ_XILINX_VSEC_ID) {
237 if (vsec_rev != ESE_GZ_VSEC_VER_XIL_CFGBAR ||
238 vsec_len < ESE_GZ_VSEC_LEN_MIN) {
243 EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
244 (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_BAR) / 8),
245 &vsec.eo_dword[1], &rc);
251 bar = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_BAR);
252 offset_low = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_LO);
254 if (vsec_len >= ESE_GZ_VSEC_LEN_HIGH_OFFT) {
255 EFSYS_PCI_CONFIG_READD(espcp, vsec_offset +
256 (EFX_LOW_BIT(ESF_GZ_VSEC_TBL_OFF_HI) / 8),
257 &vsec.eo_dword[2], &rc);
263 offset_high = EFX_OWORD_FIELD32(vsec, ESF_GZ_VSEC_TBL_OFF_HI);
266 /* High bits of low offset are discarded by the shift */
267 offset = offset_low << ESE_GZ_VSEC_TBL_OFF_LO_BYTES_SHIFT;
270 * Avoid the 'left shift count >= width of type' warning on systems
271 * without uint64_t support.
274 offset |= (uint64_t)offset_high << ESE_GZ_VSEC_TBL_OFF_HI_BYTES_SHIFT;
276 _NOTE(ARGUNUSED(offset_high))
297 EFSYS_PROBE1(fail1, efx_rc_t, rc);
302 __checkReturn efx_rc_t
303 efx_pci_xilinx_cap_tbl_find(
304 __in efsys_bar_t *esbp,
305 __in uint32_t format_id,
306 __in boolean_t skip_first,
307 __inout efsys_dma_addr_t *entry_offsetp)
309 efsys_dma_addr_t offset = *entry_offsetp;
310 boolean_t skip = skip_first;
316 if (entry_offsetp == NULL) {
323 * SF-119689-TC Riverhead Host Interface section 4.2.2.
324 * describes the following discovery steps.
328 * Xilinx Capabilities Table requires 32bit aligned reads.
329 * See SF-119689-TC section 4.2.2 "Discovery Steps".
331 EFSYS_BAR_READD(esbp, offset +
332 (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_FORMAT) / 8),
333 &header.eq_dword[0], B_FALSE);
334 EFSYS_BAR_READD(esbp, offset +
335 (EFX_LOW_BIT(ESF_GZ_CFGBAR_ENTRY_SIZE) / 8),
336 &header.eq_dword[1], B_FALSE);
338 format = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_FORMAT);
339 last = EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_LAST);
341 if (skip == B_FALSE && format == format_id) {
342 *entry_offsetp = offset;
347 offset += EFX_QWORD_FIELD32(header, ESF_GZ_CFGBAR_ENTRY_SIZE);
349 } while (last == B_FALSE);
352 * Returns 0 if found otherwise ENOENT indicating that
353 * search finished correctly.
358 EFSYS_PROBE1(fail1, efx_rc_t, rc);
363 #endif /* EFSYS_OPT_PCI */