1 /** 2 * aQuantia Corporation Network Driver 3 * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * (1) Redistributions of source code must retain the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer. 12 * 13 * (2) Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * (3) The name of the author may not be used to endorse or promote 19 * products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * @file aq_fw2x.c 35 * Firmware v2.x specific functions. 36 * @date 2017.12.11 @author roman.agafonov@aquantia.com 37 */ 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/errno.h> 42 43 #include "aq_common.h" 44 45 46 #include "aq_hw.h" 47 #include "aq_hw_llh.h" 48 #include "aq_hw_llh_internal.h" 49 50 #include "aq_fw.h" 51 52 #include "aq_dbg.h" 53 54 typedef enum { 55 CAPS_LO_10BASET_HD = 0x00, 56 CAPS_LO_10BASET_FD, 57 CAPS_LO_100BASETX_HD, 58 CAPS_LO_100BASET4_HD, 59 CAPS_LO_100BASET2_HD, 60 CAPS_LO_100BASETX_FD, 61 CAPS_LO_100BASET2_FD, 62 CAPS_LO_1000BASET_HD, 63 CAPS_LO_1000BASET_FD, 64 CAPS_LO_2P5GBASET_FD, 65 CAPS_LO_5GBASET_FD, 66 CAPS_LO_10GBASET_FD, 67 } fw2x_caps_lo; 68 69 typedef enum { 70 CAPS_HI_RESERVED1 = 0x00, 71 CAPS_HI_10BASET_EEE, 72 CAPS_HI_RESERVED2, 73 CAPS_HI_PAUSE, 74 CAPS_HI_ASYMMETRIC_PAUSE, 75 CAPS_HI_100BASETX_EEE, 76 CAPS_HI_RESERVED3, 77 CAPS_HI_RESERVED4, 78 CAPS_HI_1000BASET_FD_EEE, 79 CAPS_HI_2P5GBASET_FD_EEE, 80 CAPS_HI_5GBASET_FD_EEE, 81 CAPS_HI_10GBASET_FD_EEE, 82 CAPS_HI_RESERVED5, 83 CAPS_HI_RESERVED6, 84 CAPS_HI_RESERVED7, 85 CAPS_HI_RESERVED8, 86 CAPS_HI_RESERVED9, 87 CAPS_HI_CABLE_DIAG, 88 CAPS_HI_TEMPERATURE, 89 CAPS_HI_DOWNSHIFT, 90 CAPS_HI_PTP_AVB_EN, 91 CAPS_HI_MEDIA_DETECT, 92 CAPS_HI_LINK_DROP, 93 CAPS_HI_SLEEP_PROXY, 94 CAPS_HI_WOL, 95 CAPS_HI_MAC_STOP, 96 CAPS_HI_EXT_LOOPBACK, 97 CAPS_HI_INT_LOOPBACK, 98 CAPS_HI_EFUSE_AGENT, 99 CAPS_HI_WOL_TIMER, 100 CAPS_HI_STATISTICS, 101 CAPS_HI_TRANSACTION_ID, 102 } fw2x_caps_hi; 103 104 typedef enum aq_fw2x_rate 105 { 106 FW2X_RATE_100M = 0x20, 107 FW2X_RATE_1G = 0x100, 108 FW2X_RATE_2G5 = 0x200, 109 FW2X_RATE_5G = 0x400, 110 FW2X_RATE_10G = 0x800, 111 } aq_fw2x_rate; 112 113 114 typedef struct fw2x_msm_statistics 115 { 116 uint32_t uprc; 117 uint32_t mprc; 118 uint32_t bprc; 119 uint32_t erpt; 120 uint32_t uptc; 121 uint32_t mptc; 122 uint32_t bptc; 123 uint32_t erpr; 124 uint32_t mbtc; 125 uint32_t bbtc; 126 uint32_t mbrc; 127 uint32_t bbrc; 128 uint32_t ubrc; 129 uint32_t ubtc; 130 uint32_t ptc; 131 uint32_t prc; 132 } fw2x_msm_statistics; 133 134 typedef struct fw2x_phy_cable_diag_data 135 { 136 u32 lane_data[4]; 137 } fw2x_phy_cable_diag_data; 138 139 typedef struct fw2x_capabilities { 140 u32 caps_lo; 141 u32 caps_hi; 142 } fw2x_capabilities; 143 144 typedef struct fw2x_mailbox // struct fwHostInterface 145 { 146 u32 version; 147 u32 transaction_id; 148 s32 error; 149 fw2x_msm_statistics msm; // msmStatistics_t msm; 150 u16 phy_h_bit; 151 u16 phy_fault_code; 152 s16 phy_temperature; 153 u8 cable_len; 154 u8 reserved1; 155 fw2x_phy_cable_diag_data diag_data; 156 u32 reserved[8]; 157 158 fw2x_capabilities caps; 159 160 /* ... */ 161 } fw2x_mailbox; 162 163 164 // EEE caps 165 #define FW2X_FW_CAP_EEE_100M (1ULL << (32 + CAPS_HI_100BASETX_EEE)) 166 #define FW2X_FW_CAP_EEE_1G (1ULL << (32 + CAPS_HI_1000BASET_FD_EEE)) 167 #define FW2X_FW_CAP_EEE_2G5 (1ULL << (32 + CAPS_HI_2P5GBASET_FD_EEE)) 168 #define FW2X_FW_CAP_EEE_5G (1ULL << (32 + CAPS_HI_5GBASET_FD_EEE)) 169 #define FW2X_FW_CAP_EEE_10G (1ULL << (32 + CAPS_HI_10GBASET_FD_EEE)) 170 171 // Flow Control 172 #define FW2X_FW_CAP_PAUSE (1ULL << (32 + CAPS_HI_PAUSE)) 173 #define FW2X_FW_CAP_ASYM_PAUSE (1ULL << (32 + CAPS_HI_ASYMMETRIC_PAUSE)) 174 175 // Link Drop 176 #define FW2X_CAP_LINK_DROP (1ull << (32 + CAPS_HI_LINK_DROP)) 177 178 // MSM Statistics 179 #define FW2X_CAP_STATISTICS (1ull << (32 + CAPS_HI_STATISTICS)) 180 181 182 #define FW2X_RATE_MASK (FW2X_RATE_100M | FW2X_RATE_1G | FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G) 183 #define FW2X_EEE_MASK (FW2X_FW_CAP_EEE_100M | FW2X_FW_CAP_EEE_1G | FW2X_FW_CAP_EEE_2G5 | FW2X_FW_CAP_EEE_5G | FW2X_FW_CAP_EEE_10G) 184 185 186 #define FW2X_MPI_LED_ADDR 0x31c 187 #define FW2X_MPI_CONTROL_ADDR 0x368 188 #define FW2X_MPI_STATE_ADDR 0x370 189 190 #define FW2X_FW_MIN_VER_LED 0x03010026U 191 192 #define FW2X_LED_BLINK 0x2U 193 #define FW2X_LED_DEFAULT 0x0U 194 195 // Firmware v2-3.x specific functions. 196 //@{ 197 int fw2x_reset(struct aq_hw* hw); 198 199 int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed); 200 int fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e* mode, aq_fw_link_speed_t* speed, aq_fw_link_fc_t* fc); 201 202 int fw2x_get_mac_addr(struct aq_hw* hw, u8* mac); 203 int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats); 204 //@} 205 206 207 208 static u64 read64_(struct aq_hw* hw, u32 addr) 209 { 210 u64 lo = AQ_READ_REG(hw, addr); 211 u64 hi = AQ_READ_REG(hw, addr + 4); 212 return (lo | (hi << 32)); 213 } 214 215 static uint64_t get_mpi_ctrl_(struct aq_hw* hw) 216 { 217 return read64_(hw, FW2X_MPI_CONTROL_ADDR); 218 } 219 220 static uint64_t get_mpi_state_(struct aq_hw* hw) 221 { 222 return read64_(hw, FW2X_MPI_STATE_ADDR); 223 } 224 225 static void set_mpi_ctrl_(struct aq_hw* hw, u64 value) 226 { 227 AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR, (u32)value); 228 AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR + 4, (u32)(value >> 32)); 229 } 230 231 232 int fw2x_reset(struct aq_hw* hw) 233 { 234 fw2x_capabilities caps = {0}; 235 AQ_DBG_ENTER(); 236 int err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr + offsetof(fw2x_mailbox, caps), (u32*)&caps, sizeof caps/sizeof(u32)); 237 if (err == EOK) { 238 hw->fw_caps = caps.caps_lo | ((u64)caps.caps_hi << 32); 239 trace(dbg_init, "fw2x> F/W capabilities mask = %llx", (unsigned long long)hw->fw_caps); 240 } else { 241 trace_error(dbg_init, "fw2x> can't get F/W capabilities mask, error %d", err); 242 } 243 244 AQ_DBG_EXIT(EOK); 245 return (EOK); 246 } 247 248 249 static 250 aq_fw2x_rate link_speed_mask_to_fw2x_(u32 speed) 251 { 252 u32 rate = 0; 253 254 AQ_DBG_ENTER(); 255 if (speed & aq_fw_10G) 256 rate |= FW2X_RATE_10G; 257 258 if (speed & aq_fw_5G) 259 rate |= FW2X_RATE_5G; 260 261 if (speed & aq_fw_2G5) 262 rate |= FW2X_RATE_2G5; 263 264 if (speed & aq_fw_1G) 265 rate |= FW2X_RATE_1G; 266 267 if (speed & aq_fw_100M) 268 rate |= FW2X_RATE_100M; 269 270 AQ_DBG_EXIT(rate); 271 return ((aq_fw2x_rate)rate); 272 } 273 274 275 int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed) 276 { 277 u64 mpi_ctrl = get_mpi_ctrl_(hw); 278 279 AQ_DBG_ENTERA("speed=%d", speed); 280 switch (mode) { 281 case MPI_INIT: 282 mpi_ctrl &= ~FW2X_RATE_MASK; 283 mpi_ctrl |= link_speed_mask_to_fw2x_(speed); 284 mpi_ctrl &= ~FW2X_CAP_LINK_DROP; 285 #if 0 // #todo #flowcontrol #pause #eee 286 if (pHal->pCfg->eee) 287 mpi_ctrl |= FW2X_EEE_MASK; 288 #endif 289 if (hw->fc.fc_rx) 290 mpi_ctrl |= FW2X_FW_CAP_PAUSE; 291 if (hw->fc.fc_tx) 292 mpi_ctrl |= FW2X_FW_CAP_ASYM_PAUSE; 293 break; 294 295 case MPI_DEINIT: 296 mpi_ctrl &= ~(FW2X_RATE_MASK | FW2X_EEE_MASK); 297 mpi_ctrl &= ~(FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE); 298 break; 299 300 default: 301 trace_error(dbg_init, "fw2x> unknown MPI state %d", mode); 302 return (-EINVAL); 303 } 304 305 set_mpi_ctrl_(hw, mpi_ctrl); 306 AQ_DBG_EXIT(EOK); 307 return (EOK); 308 } 309 310 int fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e* mode, aq_fw_link_speed_t* link_speed, aq_fw_link_fc_t* fc) 311 { 312 u64 mpi_state = get_mpi_state_(hw); 313 u32 rates = mpi_state & FW2X_RATE_MASK; 314 315 // AQ_DBG_ENTER(); 316 317 if (mode) { 318 u64 mpi_ctrl = get_mpi_ctrl_(hw); 319 if (mpi_ctrl & FW2X_RATE_MASK) 320 *mode = MPI_INIT; 321 else 322 *mode = MPI_DEINIT; 323 } 324 325 aq_fw_link_speed_t speed = aq_fw_none; 326 327 if (rates & FW2X_RATE_10G) 328 speed = aq_fw_10G; 329 else if (rates & FW2X_RATE_5G) 330 speed = aq_fw_5G; 331 else if (rates & FW2X_RATE_2G5) 332 speed = aq_fw_2G5; 333 else if (rates & FW2X_RATE_1G) 334 speed = aq_fw_1G; 335 else if (rates & FW2X_RATE_100M) 336 speed = aq_fw_100M; 337 338 if (link_speed) 339 *link_speed = speed; 340 341 *fc = (mpi_state & (FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE)) >> (32 + CAPS_HI_PAUSE); 342 343 344 // AQ_DBG_EXIT(0); 345 return (EOK); 346 } 347 348 349 int fw2x_get_mac_addr(struct aq_hw* hw, u8* mac) 350 { 351 int err = -EFAULT; 352 u32 mac_addr[2]; 353 354 AQ_DBG_ENTER(); 355 356 u32 efuse_shadow_addr = AQ_READ_REG(hw, 0x364); 357 if (efuse_shadow_addr == 0) { 358 trace_error(dbg_init, "couldn't read eFUSE Shadow Address"); 359 AQ_DBG_EXIT(-EFAULT); 360 return (-EFAULT); 361 } 362 363 err = aq_hw_fw_downld_dwords(hw, efuse_shadow_addr + (40 * 4), 364 mac_addr, ARRAY_SIZE(mac_addr)); 365 if (err < 0) { 366 mac_addr[0] = 0; 367 mac_addr[1] = 0; 368 AQ_DBG_EXIT(err); 369 return (err); 370 } 371 372 mac_addr[0] = bswap32(mac_addr[0]); 373 mac_addr[1] = bswap32(mac_addr[1]); 374 375 memcpy(mac, (u8*)mac_addr, ETHER_ADDR_LEN); 376 377 AQ_DBG_EXIT(EOK); 378 return (EOK); 379 } 380 381 static inline 382 void fw2x_stats_to_fw_stats_(struct aq_hw_stats_s* dst, const fw2x_msm_statistics* src) 383 { 384 dst->uprc = src->uprc; 385 dst->mprc = src->mprc; 386 dst->bprc = src->bprc; 387 dst->erpt = src->erpt; 388 dst->uptc = src->uptc; 389 dst->mptc = src->mptc; 390 dst->bptc = src->bptc; 391 dst->erpr = src->erpr; 392 dst->mbtc = src->mbtc; 393 dst->bbtc = src->bbtc; 394 dst->mbrc = src->mbrc; 395 dst->bbrc = src->bbrc; 396 dst->ubrc = src->ubrc; 397 dst->ubtc = src->ubtc; 398 dst->ptc = src->ptc; 399 dst->prc = src->prc; 400 } 401 402 403 static bool toggle_mpi_ctrl_and_wait_(struct aq_hw* hw, u64 mask, u32 timeout_ms, u32 try_count) 404 { 405 u64 ctrl = get_mpi_ctrl_(hw); 406 u64 state = get_mpi_state_(hw); 407 408 // AQ_DBG_ENTER(); 409 // First, check that control and state values are consistent 410 if ((ctrl & mask) != (state & mask)) { 411 trace_warn(dbg_fw, "fw2x> MPI control (%#llx) and state (%#llx) are not consistent for mask %#llx!", 412 (unsigned long long)ctrl, (unsigned long long)state, (unsigned long long)mask); 413 AQ_DBG_EXIT(false); 414 return (false); 415 } 416 417 // Invert bits (toggle) in control register 418 ctrl ^= mask; 419 set_mpi_ctrl_(hw, ctrl); 420 421 // Clear all bits except masked 422 ctrl &= mask; 423 424 // Wait for FW reflecting change in state register 425 while (try_count-- != 0) { 426 if ((get_mpi_state_(hw) & mask) == ctrl) 427 { 428 // AQ_DBG_EXIT(true); 429 return (true); 430 } 431 msec_delay(timeout_ms); 432 } 433 434 trace_detail(dbg_fw, "f/w2x> timeout while waiting for response in state register for bit %#llx!", (unsigned long long)mask); 435 // AQ_DBG_EXIT(false); 436 return (false); 437 } 438 439 440 int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats) 441 { 442 int err = 0; 443 fw2x_msm_statistics fw2x_stats = {0}; 444 445 // AQ_DBG_ENTER(); 446 447 if ((hw->fw_caps & FW2X_CAP_STATISTICS) == 0) { 448 trace_warn(dbg_fw, "fw2x> statistics not supported by F/W"); 449 return (-ENOTSUP); 450 } 451 452 // Say to F/W to update the statistics 453 if (!toggle_mpi_ctrl_and_wait_(hw, FW2X_CAP_STATISTICS, 1, 25)) { 454 trace_error(dbg_fw, "fw2x> statistics update timeout"); 455 AQ_DBG_EXIT(-ETIME); 456 return (-ETIME); 457 } 458 459 err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr + offsetof(fw2x_mailbox, msm), 460 (u32*)&fw2x_stats, sizeof fw2x_stats/sizeof(u32)); 461 462 fw2x_stats_to_fw_stats_(stats, &fw2x_stats); 463 464 if (err != EOK) 465 trace_error(dbg_fw, "fw2x> download statistics data FAILED, error %d", err); 466 467 // AQ_DBG_EXIT(err); 468 return (err); 469 } 470 471 static int fw2x_led_control(struct aq_hw* hw, u32 onoff) 472 { 473 int err = 0; 474 475 AQ_DBG_ENTER(); 476 477 aq_hw_fw_version ver_expected = { .raw = FW2X_FW_MIN_VER_LED}; 478 if (aq_hw_ver_match(&ver_expected, &hw->fw_version)) 479 AQ_WRITE_REG(hw, FW2X_MPI_LED_ADDR, (onoff)? 480 ((FW2X_LED_BLINK) | (FW2X_LED_BLINK << 2) | (FW2X_LED_BLINK << 4)): 481 (FW2X_LED_DEFAULT)); 482 483 AQ_DBG_EXIT(err); 484 return (err); 485 } 486 487 struct aq_firmware_ops aq_fw2x_ops = 488 { 489 .reset = fw2x_reset, 490 491 .set_mode = fw2x_set_mode, 492 .get_mode = fw2x_get_mode, 493 494 .get_mac_addr = fw2x_get_mac_addr, 495 .get_stats = fw2x_get_stats, 496 497 .led_control = fw2x_led_control, 498 }; 499