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_RIVERHEAD && EFSYS_OPT_PCI 11 12 /* 13 * Search for a EF100 resource locator from the given offset of an entry 14 * in a Xilinx capabilities table. 15 */ 16 static __checkReturn efx_rc_t 17 rhead_xilinx_cap_tbl_find_ef100_locator( 18 __in efsys_bar_t *esbp, 19 __in efsys_dma_addr_t tbl_offset, 20 __out efx_bar_region_t *ef100_ebrp) 21 { 22 efx_rc_t rc; 23 efsys_dma_addr_t entry_offset = tbl_offset; 24 25 rc = efx_pci_xilinx_cap_tbl_find(esbp, ESE_GZ_CFGBAR_ENTRY_EF100, 26 B_FALSE, &entry_offset); 27 if (rc != 0) { 28 /* EF100 locator not found (ENOENT) or other error */ 29 goto fail1; 30 } 31 32 rc = rhead_nic_xilinx_cap_tbl_read_ef100_locator(esbp, entry_offset, 33 ef100_ebrp); 34 if (rc != 0) 35 goto fail2; 36 37 return (0); 38 39 fail2: 40 EFSYS_PROBE(fail2); 41 fail1: 42 EFSYS_PROBE1(fail1, efx_rc_t, rc); 43 44 return (rc); 45 } 46 47 __checkReturn efx_rc_t 48 rhead_pci_nic_membar_lookup( 49 __in efsys_pci_config_t *espcp, 50 __in const efx_pci_ops_t *epop, 51 __out efx_bar_region_t *ebrp) 52 { 53 boolean_t xilinx_tbl_found = B_FALSE; 54 unsigned int xilinx_tbl_bar; 55 efsys_dma_addr_t xilinx_tbl_offset; 56 size_t pci_capa_offset = 0; 57 boolean_t bar_found = B_FALSE; 58 efx_rc_t rc = ENOENT; 59 efsys_bar_t xil_eb; 60 efsys_bar_t nic_eb; 61 efx_dword_t magic_ed; 62 uint32_t magic; 63 64 /* 65 * SF-119689-TC Riverhead Host Interface section 4.2.2. describes 66 * the following discovery steps. 67 */ 68 while (1) { 69 rc = efx_pci_find_next_xilinx_cap_table(espcp, epop, 70 &pci_capa_offset, 71 &xilinx_tbl_bar, 72 &xilinx_tbl_offset); 73 if (rc != 0) { 74 /* 75 * SF-119689-TC Riverhead Host Interface section 4.2.2. 76 * defines the following fallbacks for the memory bar 77 * and the offset when no Xilinx capabilities table is 78 * found. 79 */ 80 if (rc == ENOENT && xilinx_tbl_found == B_FALSE) { 81 ebrp->ebr_type = EFX_BAR_TYPE_MEM; 82 ebrp->ebr_index = EFX_MEM_BAR_RIVERHEAD; 83 ebrp->ebr_offset = 0; 84 ebrp->ebr_length = 0; 85 bar_found = B_TRUE; 86 break; 87 } else { 88 goto fail1; 89 } 90 91 } 92 93 xilinx_tbl_found = B_TRUE; 94 95 rc = epop->epo_find_mem_bar(espcp, xilinx_tbl_bar, &xil_eb); 96 if (rc != 0) 97 goto fail2; 98 99 rc = rhead_xilinx_cap_tbl_find_ef100_locator(&xil_eb, 100 xilinx_tbl_offset, 101 ebrp); 102 if (rc == 0) { 103 /* Found valid EF100 locator. */ 104 bar_found = B_TRUE; 105 break; 106 } else if (rc != ENOENT) { 107 /* Table access failed, so terminate search. */ 108 goto fail3; 109 } 110 } 111 112 if (bar_found == B_FALSE) 113 goto fail4; 114 115 rc = epop->epo_find_mem_bar(espcp, ebrp->ebr_index, &nic_eb); 116 if (rc != 0) 117 goto fail5; 118 119 EFSYS_BAR_READD(&nic_eb, ebrp->ebr_offset + ER_GZ_NIC_MAGIC_OFST, 120 &magic_ed, B_FALSE); 121 122 magic = EFX_DWORD_FIELD(magic_ed, ERF_GZ_NIC_MAGIC); 123 if (magic != EFE_GZ_NIC_MAGIC_EXPECTED) { 124 rc = EINVAL; 125 goto fail6; 126 } 127 128 return (0); 129 130 fail6: 131 EFSYS_PROBE(fail6); 132 fail5: 133 EFSYS_PROBE(fail5); 134 fail4: 135 EFSYS_PROBE(fail4); 136 fail3: 137 EFSYS_PROBE(fail3); 138 fail2: 139 EFSYS_PROBE(fail2); 140 fail1: 141 EFSYS_PROBE1(fail1, efx_rc_t, rc); 142 143 return (rc); 144 } 145 146 #endif /* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_PCI */ 147