1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 #include "ena_hw.h" 17 #include "ena.h" 18 19 uint32_t 20 ena_hw_bar_read32(const ena_t *ena, const uint16_t offset) 21 { 22 caddr_t addr = ena->ena_reg_base + offset; 23 return (ena_hw_abs_read32(ena, (uint32_t *)addr)); 24 } 25 26 uint32_t 27 ena_hw_abs_read32(const ena_t *ena, uint32_t *addr) 28 { 29 VERIFY3U(addr, >=, ena->ena_reg_base); 30 VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4)); 31 32 return (ddi_get32(ena->ena_reg_hdl, addr)); 33 } 34 35 void 36 ena_hw_bar_write32(const ena_t *ena, const uint16_t offset, const uint32_t val) 37 { 38 caddr_t addr = ena->ena_reg_base + offset; 39 ena_hw_abs_write32(ena, (uint32_t *)addr, val); 40 } 41 42 void 43 ena_hw_abs_write32(const ena_t *ena, uint32_t *addr, const uint32_t val) 44 { 45 VERIFY3P(ena, !=, NULL); 46 VERIFY3P(addr, !=, NULL); 47 VERIFY3U(addr, >=, ena->ena_reg_base); 48 VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4)); 49 50 ddi_put32(ena->ena_reg_hdl, addr, val); 51 } 52 53 int 54 enahw_resp_status_to_errno(ena_t *ena, enahw_resp_status_t status) 55 { 56 int ret = 0; 57 58 switch (status) { 59 case ENAHW_RESP_SUCCESS: 60 break; 61 62 case ENAHW_RESP_RESOURCE_ALLOCATION_FAILURE: 63 ret = ENOMEM; 64 break; 65 66 case ENAHW_RESP_UNSUPPORTED_OPCODE: 67 ret = ENOTSUP; 68 break; 69 70 case ENAHW_RESP_BAD_OPCODE: 71 case ENAHW_RESP_MALFORMED_REQUEST: 72 case ENAHW_RESP_ILLEGAL_PARAMETER: 73 ret = EINVAL; 74 break; 75 76 case ENAHW_RESP_RESOURCE_BUSY: 77 ret = EAGAIN; 78 break; 79 80 case ENAHW_RESP_UNKNOWN_ERROR: 81 default: 82 /* 83 * If the device presents us with an "unknown error" 84 * code, or the status code is undefined, then we log 85 * an error and convert it to EIO. 86 */ 87 ena_err(ena, "unexpected status code: %d", status); 88 ret = EIO; 89 break; 90 } 91 92 return (ret); 93 } 94 95 const char * 96 enahw_reset_reason(enahw_reset_reason_t reason) 97 { 98 switch (reason) { 99 case ENAHW_RESET_NORMAL: 100 return ("normal"); 101 case ENAHW_RESET_KEEP_ALIVE_TO: 102 return ("keep-alive timeout"); 103 case ENAHW_RESET_ADMIN_TO: 104 return ("admin timeout"); 105 case ENAHW_RESET_MISS_TX_CMPL: 106 return ("missed TX completion"); 107 case ENAHW_RESET_INV_RX_REQ_ID: 108 return ("invalid RX request ID"); 109 case ENAHW_RESET_INV_TX_REQ_ID: 110 return ("invalid TX request ID"); 111 case ENAHW_RESET_TOO_MANY_RX_DESCS: 112 return ("too many RX descs"); 113 case ENAHW_RESET_INIT_ERR: 114 return ("initialization error"); 115 case ENAHW_RESET_DRIVER_INVALID_STATE: 116 return ("invalid driver state"); 117 case ENAHW_RESET_OS_TRIGGER: 118 return ("OS trigger"); 119 case ENAHW_RESET_OS_NETDEV_WD: 120 return ("netdev watchdog"); 121 case ENAHW_RESET_SHUTDOWN: 122 return ("shutdown"); 123 case ENAHW_RESET_USER_TRIGGER: 124 return ("user trigger"); 125 case ENAHW_RESET_GENERIC: 126 return ("generic"); 127 case ENAHW_RESET_MISS_INTERRUPT: 128 return ("missed interrupt"); 129 case ENAHW_RESET_SUSPECTED_POLL_STARVATION: 130 return ("suspected poll starvation"); 131 case ENAHW_RESET_RX_DESCRIPTOR_MALFORMED: 132 return ("malformed RX descriptor"); 133 case ENAHW_RESET_TX_DESCRIPTOR_MALFORMED: 134 return ("malformed TX descriptor"); 135 case ENAHW_RESET_MISSING_ADMIN_INTERRUPT: 136 return ("missing admin interrupt"); 137 case ENAHW_RESET_DEVICE_REQUEST: 138 return ("device request"); 139 default: 140 return ("unknown"); 141 } 142 } 143 144 #ifdef DEBUG 145 static const ena_reg_t reg_cache_template[ENAHW_NUM_REGS] = { 146 { 147 .er_name = "Version", 148 .er_offset = ENAHW_REG_VERSION 149 }, 150 { 151 .er_name = "Controller Version", 152 .er_offset = ENAHW_REG_CONTROLLER_VERSION 153 }, 154 { 155 .er_name = "Caps", 156 .er_offset = ENAHW_REG_CAPS 157 }, 158 { 159 .er_name = "Extended Caps", 160 .er_offset = ENAHW_REG_CAPS_EXT 161 }, 162 { 163 .er_name = "Admin SQ Base Low", 164 .er_offset = ENAHW_REG_ASQ_BASE_LO 165 }, 166 { 167 .er_name = "Admin SQ Base High", 168 .er_offset = ENAHW_REG_ASQ_BASE_HI 169 }, 170 { 171 .er_name = "Admin SQ Caps", 172 .er_offset = ENAHW_REG_ASQ_CAPS 173 }, 174 { 175 .er_name = "Gap 0x1C", 176 .er_offset = ENAHW_REG_GAP_1C 177 }, 178 { 179 .er_name = "Admin CQ Base Low", 180 .er_offset = ENAHW_REG_ACQ_BASE_LO 181 }, 182 { 183 .er_name = "Admin CQ Base High", 184 .er_offset = ENAHW_REG_ACQ_BASE_HI 185 }, 186 { 187 .er_name = "Admin CQ Caps", 188 .er_offset = ENAHW_REG_ACQ_CAPS 189 }, 190 { 191 .er_name = "Admin SQ Doorbell", 192 .er_offset = ENAHW_REG_ASQ_DB 193 }, 194 { 195 .er_name = "Admin CQ Tail", 196 .er_offset = ENAHW_REG_ACQ_TAIL 197 }, 198 { 199 .er_name = "Admin Event Notification Queue Caps", 200 .er_offset = ENAHW_REG_AENQ_CAPS 201 }, 202 { 203 .er_name = "Admin Event Notification Queue Base Low", 204 .er_offset = ENAHW_REG_AENQ_BASE_LO 205 }, 206 { 207 .er_name = "Admin Event Notification Queue Base High", 208 .er_offset = ENAHW_REG_AENQ_BASE_HI 209 }, 210 { 211 .er_name = "Admin Event Notification Queue Head Doorbell", 212 .er_offset = ENAHW_REG_AENQ_HEAD_DB 213 }, 214 { 215 .er_name = "Admin Event Notification Queue Tail", 216 .er_offset = ENAHW_REG_AENQ_TAIL 217 }, 218 { 219 .er_name = "Gap 0x48", 220 .er_offset = ENAHW_REG_GAP_48 221 }, 222 { 223 .er_name = "Interrupt Mask (disable interrupts)", 224 .er_offset = ENAHW_REG_INTERRUPT_MASK 225 }, 226 { 227 .er_name = "Gap 0x50", 228 .er_offset = ENAHW_REG_GAP_50 229 }, 230 { 231 .er_name = "Device Control", 232 .er_offset = ENAHW_REG_DEV_CTL 233 }, 234 { 235 .er_name = "Device Status", 236 .er_offset = ENAHW_REG_DEV_STS 237 }, 238 { 239 .er_name = "MMIO Register Read", 240 .er_offset = ENAHW_REG_MMIO_REG_READ 241 }, 242 { 243 .er_name = "MMIO Response Address Low", 244 .er_offset = ENAHW_REG_MMIO_RESP_LO 245 }, 246 { 247 .er_name = "MMIO Response Address High", 248 .er_offset = ENAHW_REG_MMIO_RESP_HI 249 }, 250 { 251 .er_name = "RSS Indirection Entry Update", 252 .er_offset = ENAHW_REG_RSS_IND_ENTRY_UPDATE 253 }, 254 }; 255 256 void 257 ena_update_regcache(ena_t *ena) 258 { 259 for (uint_t i = 0; i < ENAHW_NUM_REGS; i++) { 260 ena_reg_t *r = &ena->ena_reg[i]; 261 262 r->er_value = ena_hw_bar_read32(ena, r->er_offset); 263 } 264 } 265 266 void 267 ena_init_regcache(ena_t *ena) 268 { 269 bcopy(reg_cache_template, ena->ena_reg, sizeof (ena->ena_reg)); 270 ena_update_regcache(ena); 271 } 272 #endif /* DEBUG */ 273