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 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 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 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 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 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