1a57d3929SIgor Russkikh /* 2a57d3929SIgor Russkikh * aQuantia Corporation Network Driver 3a57d3929SIgor Russkikh * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved 4a57d3929SIgor Russkikh * 5a57d3929SIgor Russkikh * This program is free software; you can redistribute it and/or modify it 6a57d3929SIgor Russkikh * under the terms and conditions of the GNU General Public License, 7a57d3929SIgor Russkikh * version 2, as published by the Free Software Foundation. 8a57d3929SIgor Russkikh */ 9a57d3929SIgor Russkikh 10a57d3929SIgor Russkikh /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for 11a57d3929SIgor Russkikh * Atlantic hardware abstraction layer. 12a57d3929SIgor Russkikh */ 13a57d3929SIgor Russkikh 14a57d3929SIgor Russkikh #include "../aq_hw.h" 15a57d3929SIgor Russkikh #include "../aq_hw_utils.h" 16a57d3929SIgor Russkikh #include "../aq_pci_func.h" 17a57d3929SIgor Russkikh #include "../aq_ring.h" 18a57d3929SIgor Russkikh #include "../aq_vec.h" 19a57d3929SIgor Russkikh #include "hw_atl_utils.h" 20a57d3929SIgor Russkikh #include "hw_atl_llh.h" 21a57d3929SIgor Russkikh 22a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 23a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 243ee5c887SYana Esina #define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 25a57d3929SIgor Russkikh 26a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 27a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C 28a57d3929SIgor Russkikh 29a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 30a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 31a57d3929SIgor Russkikh 3244e00dd8SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); 3344e00dd8SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 3444e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state); 3544e00dd8SIgor Russkikh 36a57d3929SIgor Russkikh static int aq_fw2x_init(struct aq_hw_s *self) 37a57d3929SIgor Russkikh { 38a57d3929SIgor Russkikh int err = 0; 39a57d3929SIgor Russkikh 40a57d3929SIgor Russkikh /* check 10 times by 1ms */ 41a57d3929SIgor Russkikh AQ_HW_WAIT_FOR(0U != (self->mbox_addr = 42a57d3929SIgor Russkikh aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), 43a57d3929SIgor Russkikh 1000U, 10U); 443ee5c887SYana Esina AQ_HW_WAIT_FOR(0U != (self->rpc_addr = 453ee5c887SYana Esina aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)), 463ee5c887SYana Esina 1000U, 100U); 473ee5c887SYana Esina 48a57d3929SIgor Russkikh return err; 49a57d3929SIgor Russkikh } 50a57d3929SIgor Russkikh 5144e00dd8SIgor Russkikh static int aq_fw2x_deinit(struct aq_hw_s *self) 5244e00dd8SIgor Russkikh { 5344e00dd8SIgor Russkikh int err = aq_fw2x_set_link_speed(self, 0); 5444e00dd8SIgor Russkikh 5544e00dd8SIgor Russkikh if (!err) 5644e00dd8SIgor Russkikh err = aq_fw2x_set_state(self, MPI_DEINIT); 5744e00dd8SIgor Russkikh 5844e00dd8SIgor Russkikh return err; 5944e00dd8SIgor Russkikh } 6044e00dd8SIgor Russkikh 61a57d3929SIgor Russkikh static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) 62a57d3929SIgor Russkikh { 63a57d3929SIgor Russkikh enum hw_atl_fw2x_rate rate = 0; 64a57d3929SIgor Russkikh 65a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_10G) 66a57d3929SIgor Russkikh rate |= FW2X_RATE_10G; 67a57d3929SIgor Russkikh 68a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5G) 69a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 70a57d3929SIgor Russkikh 71a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5GSR) 72a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 73a57d3929SIgor Russkikh 74a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_2GS) 75a57d3929SIgor Russkikh rate |= FW2X_RATE_2G5; 76a57d3929SIgor Russkikh 77a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_1G) 78a57d3929SIgor Russkikh rate |= FW2X_RATE_1G; 79a57d3929SIgor Russkikh 80a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_100M) 81a57d3929SIgor Russkikh rate |= FW2X_RATE_100M; 82a57d3929SIgor Russkikh 83a57d3929SIgor Russkikh return rate; 84a57d3929SIgor Russkikh } 85a57d3929SIgor Russkikh 86a57d3929SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) 87a57d3929SIgor Russkikh { 88a57d3929SIgor Russkikh u32 val = link_speed_mask_2fw2x_ratemask(speed); 89a57d3929SIgor Russkikh 90a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val); 91a57d3929SIgor Russkikh 92a57d3929SIgor Russkikh return 0; 93a57d3929SIgor Russkikh } 94a57d3929SIgor Russkikh 95288551deSIgor Russkikh static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state) 96288551deSIgor Russkikh { 97288551deSIgor Russkikh if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) 98288551deSIgor Russkikh *mpi_state |= BIT(CAPS_HI_PAUSE); 99288551deSIgor Russkikh else 100288551deSIgor Russkikh *mpi_state &= ~BIT(CAPS_HI_PAUSE); 101288551deSIgor Russkikh 102288551deSIgor Russkikh if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX) 103288551deSIgor Russkikh *mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE); 104288551deSIgor Russkikh else 105288551deSIgor Russkikh *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); 106288551deSIgor Russkikh } 107288551deSIgor Russkikh 108a57d3929SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 109a57d3929SIgor Russkikh enum hal_atl_utils_fw_state_e state) 110a57d3929SIgor Russkikh { 11144e00dd8SIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 11244e00dd8SIgor Russkikh 11344e00dd8SIgor Russkikh switch (state) { 11444e00dd8SIgor Russkikh case MPI_INIT: 11544e00dd8SIgor Russkikh mpi_state &= ~BIT(CAPS_HI_LINK_DROP); 116288551deSIgor Russkikh aq_fw2x_set_mpi_flow_control(self, &mpi_state); 11744e00dd8SIgor Russkikh break; 11844e00dd8SIgor Russkikh case MPI_DEINIT: 11944e00dd8SIgor Russkikh mpi_state |= BIT(CAPS_HI_LINK_DROP); 12044e00dd8SIgor Russkikh break; 12144e00dd8SIgor Russkikh case MPI_RESET: 12244e00dd8SIgor Russkikh case MPI_POWER: 12344e00dd8SIgor Russkikh /* No actions */ 12444e00dd8SIgor Russkikh break; 12544e00dd8SIgor Russkikh } 12644e00dd8SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 127a57d3929SIgor Russkikh return 0; 128a57d3929SIgor Russkikh } 129a57d3929SIgor Russkikh 130a57d3929SIgor Russkikh static int aq_fw2x_update_link_status(struct aq_hw_s *self) 131a57d3929SIgor Russkikh { 132a57d3929SIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); 133a57d3929SIgor Russkikh u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | 134a57d3929SIgor Russkikh FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G); 135a57d3929SIgor Russkikh struct aq_hw_link_status_s *link_status = &self->aq_link_status; 136a57d3929SIgor Russkikh 137a57d3929SIgor Russkikh if (speed) { 138a57d3929SIgor Russkikh if (speed & FW2X_RATE_10G) 139a57d3929SIgor Russkikh link_status->mbps = 10000; 140a57d3929SIgor Russkikh else if (speed & FW2X_RATE_5G) 141a57d3929SIgor Russkikh link_status->mbps = 5000; 142a57d3929SIgor Russkikh else if (speed & FW2X_RATE_2G5) 143a57d3929SIgor Russkikh link_status->mbps = 2500; 144a57d3929SIgor Russkikh else if (speed & FW2X_RATE_1G) 145a57d3929SIgor Russkikh link_status->mbps = 1000; 146a57d3929SIgor Russkikh else if (speed & FW2X_RATE_100M) 147a57d3929SIgor Russkikh link_status->mbps = 100; 148a57d3929SIgor Russkikh else 149a57d3929SIgor Russkikh link_status->mbps = 10000; 150a57d3929SIgor Russkikh } else { 151a57d3929SIgor Russkikh link_status->mbps = 0; 152a57d3929SIgor Russkikh } 153a57d3929SIgor Russkikh 154a57d3929SIgor Russkikh return 0; 155a57d3929SIgor Russkikh } 156a57d3929SIgor Russkikh 15776a45194SColin Ian King static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) 158a57d3929SIgor Russkikh { 159a57d3929SIgor Russkikh int err = 0; 160a57d3929SIgor Russkikh u32 h = 0U; 161a57d3929SIgor Russkikh u32 l = 0U; 162a57d3929SIgor Russkikh u32 mac_addr[2] = { 0 }; 163a57d3929SIgor Russkikh u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR); 164a57d3929SIgor Russkikh 165a57d3929SIgor Russkikh if (efuse_addr != 0) { 166a57d3929SIgor Russkikh err = hw_atl_utils_fw_downld_dwords(self, 167a57d3929SIgor Russkikh efuse_addr + (40U * 4U), 168a57d3929SIgor Russkikh mac_addr, 169a57d3929SIgor Russkikh ARRAY_SIZE(mac_addr)); 170a57d3929SIgor Russkikh if (err) 171a57d3929SIgor Russkikh return err; 172a57d3929SIgor Russkikh mac_addr[0] = __swab32(mac_addr[0]); 173a57d3929SIgor Russkikh mac_addr[1] = __swab32(mac_addr[1]); 174a57d3929SIgor Russkikh } 175a57d3929SIgor Russkikh 176a57d3929SIgor Russkikh ether_addr_copy(mac, (u8 *)mac_addr); 177a57d3929SIgor Russkikh 178a57d3929SIgor Russkikh if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { 179a57d3929SIgor Russkikh unsigned int rnd = 0; 180a57d3929SIgor Russkikh 181a57d3929SIgor Russkikh get_random_bytes(&rnd, sizeof(unsigned int)); 182a57d3929SIgor Russkikh 183a57d3929SIgor Russkikh l = 0xE3000000U 184a57d3929SIgor Russkikh | (0xFFFFU & rnd) 185a57d3929SIgor Russkikh | (0x00 << 16); 186a57d3929SIgor Russkikh h = 0x8001300EU; 187a57d3929SIgor Russkikh 188a57d3929SIgor Russkikh mac[5] = (u8)(0xFFU & l); 189a57d3929SIgor Russkikh l >>= 8; 190a57d3929SIgor Russkikh mac[4] = (u8)(0xFFU & l); 191a57d3929SIgor Russkikh l >>= 8; 192a57d3929SIgor Russkikh mac[3] = (u8)(0xFFU & l); 193a57d3929SIgor Russkikh l >>= 8; 194a57d3929SIgor Russkikh mac[2] = (u8)(0xFFU & l); 195a57d3929SIgor Russkikh mac[1] = (u8)(0xFFU & h); 196a57d3929SIgor Russkikh h >>= 8; 197a57d3929SIgor Russkikh mac[0] = (u8)(0xFFU & h); 198a57d3929SIgor Russkikh } 199a57d3929SIgor Russkikh return err; 200a57d3929SIgor Russkikh } 201a57d3929SIgor Russkikh 202a57d3929SIgor Russkikh static int aq_fw2x_update_stats(struct aq_hw_s *self) 203a57d3929SIgor Russkikh { 204a57d3929SIgor Russkikh int err = 0; 205a57d3929SIgor Russkikh u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 206a57d3929SIgor Russkikh u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS); 207a57d3929SIgor Russkikh 208a57d3929SIgor Russkikh /* Toggle statistics bit for FW to update */ 209a57d3929SIgor Russkikh mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS); 210a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 211a57d3929SIgor Russkikh 212a57d3929SIgor Russkikh /* Wait FW to report back */ 213a57d3929SIgor Russkikh AQ_HW_WAIT_FOR(orig_stats_val != 214a57d3929SIgor Russkikh (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) & 215a57d3929SIgor Russkikh BIT(CAPS_HI_STATISTICS)), 216a57d3929SIgor Russkikh 1U, 10000U); 217a57d3929SIgor Russkikh if (err) 218a57d3929SIgor Russkikh return err; 219a57d3929SIgor Russkikh 220a57d3929SIgor Russkikh return hw_atl_utils_update_stats(self); 221a57d3929SIgor Russkikh } 222a57d3929SIgor Russkikh 223b8d68b62SAnton Mikaev static int aq_fw2x_renegotiate(struct aq_hw_s *self) 224b8d68b62SAnton Mikaev { 225b8d68b62SAnton Mikaev u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 226b8d68b62SAnton Mikaev 227b8d68b62SAnton Mikaev mpi_opts |= BIT(CTRL_FORCE_RECONNECT); 228b8d68b62SAnton Mikaev 229b8d68b62SAnton Mikaev aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 230b8d68b62SAnton Mikaev 231b8d68b62SAnton Mikaev return 0; 232b8d68b62SAnton Mikaev } 233b8d68b62SAnton Mikaev 234288551deSIgor Russkikh static int aq_fw2x_set_flow_control(struct aq_hw_s *self) 235288551deSIgor Russkikh { 236288551deSIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 237288551deSIgor Russkikh 238288551deSIgor Russkikh aq_fw2x_set_mpi_flow_control(self, &mpi_state); 239288551deSIgor Russkikh 240288551deSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 241288551deSIgor Russkikh 242288551deSIgor Russkikh return 0; 243288551deSIgor Russkikh } 244288551deSIgor Russkikh 245a57d3929SIgor Russkikh const struct aq_fw_ops aq_fw_2x_ops = { 246a57d3929SIgor Russkikh .init = aq_fw2x_init, 24744e00dd8SIgor Russkikh .deinit = aq_fw2x_deinit, 248a57d3929SIgor Russkikh .reset = NULL, 249b8d68b62SAnton Mikaev .renegotiate = aq_fw2x_renegotiate, 250a57d3929SIgor Russkikh .get_mac_permanent = aq_fw2x_get_mac_permanent, 251a57d3929SIgor Russkikh .set_link_speed = aq_fw2x_set_link_speed, 252a57d3929SIgor Russkikh .set_state = aq_fw2x_set_state, 253a57d3929SIgor Russkikh .update_link_status = aq_fw2x_update_link_status, 254a57d3929SIgor Russkikh .update_stats = aq_fw2x_update_stats, 255288551deSIgor Russkikh .set_flow_control = aq_fw2x_set_flow_control, 256a57d3929SIgor Russkikh }; 257