175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a57d3929SIgor Russkikh /* 3a57d3929SIgor Russkikh * aQuantia Corporation Network Driver 4910479a9SEgor Pomozov * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved 5a57d3929SIgor Russkikh */ 6a57d3929SIgor Russkikh 7a57d3929SIgor Russkikh /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for 8a57d3929SIgor Russkikh * Atlantic hardware abstraction layer. 9a57d3929SIgor Russkikh */ 10a57d3929SIgor Russkikh 11a57d3929SIgor Russkikh #include "../aq_hw.h" 12a57d3929SIgor Russkikh #include "../aq_hw_utils.h" 13a57d3929SIgor Russkikh #include "../aq_pci_func.h" 14a57d3929SIgor Russkikh #include "../aq_ring.h" 15a57d3929SIgor Russkikh #include "../aq_vec.h" 160e1a0ddeSYana Esina #include "../aq_nic.h" 17a57d3929SIgor Russkikh #include "hw_atl_utils.h" 18a57d3929SIgor Russkikh #include "hw_atl_llh.h" 19a57d3929SIgor Russkikh 20d1287ce4SNikita Danilov #define HW_ATL_FW2X_MPI_LED_ADDR 0x31c 213ee5c887SYana Esina #define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 22a57d3929SIgor Russkikh 236a7f2277SNikita Danilov #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 246a7f2277SNikita Danilov #define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 25a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 26a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C 27a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 28a57d3929SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 29a57d3929SIgor Russkikh 30910479a9SEgor Pomozov #define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378 31910479a9SEgor Pomozov #define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c 32910479a9SEgor Pomozov 33f08a464cSEgor Pomozov #define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR 0x50a0 34f08a464cSEgor Pomozov #define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR 0x50a4 35f08a464cSEgor Pomozov 3635e8e8b4SIgor Russkikh #define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE) 3735e8e8b4SIgor Russkikh #define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE) 380e1a0ddeSYana Esina #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) 390e1a0ddeSYana Esina #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) 400e1a0ddeSYana Esina 41837c6378SNikita Danilov #define HW_ATL_FW2X_CTRL_WAKE_ON_LINK BIT(CTRL_WAKE_ON_LINK) 420e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY) 430e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL) 440e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP) 450e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE) 468f894011SYana Esina #define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE) 470e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) 48ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK) 49ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK) 50ea4b4d7fSIgor Russkikh #define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT) 510e1a0ddeSYana Esina #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) 520e1a0ddeSYana Esina 5392ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE) 5492ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE) 5592ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE) 5692ab6407SYana Esina #define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE) 5792ab6407SYana Esina 5862c1c2e6SDmitry Bogdanov #define HW_ATL_FW2X_CAP_MACSEC BIT(CAPS_LO_MACSEC) 5962c1c2e6SDmitry Bogdanov 600e1a0ddeSYana Esina #define HAL_ATLANTIC_WOL_FILTERS_COUNT 8 610e1a0ddeSYana Esina #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E 620e1a0ddeSYana Esina 63d1287ce4SNikita Danilov #define HW_ATL_FW_VER_LED 0x03010026U 64ea4b4d7fSIgor Russkikh #define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU 65d1287ce4SNikita Danilov 660e1a0ddeSYana Esina struct __packed fw2x_msg_wol_pattern { 670e1a0ddeSYana Esina u8 mask[16]; 680e1a0ddeSYana Esina u32 crc; 690e1a0ddeSYana Esina }; 700e1a0ddeSYana Esina 710e1a0ddeSYana Esina struct __packed fw2x_msg_wol { 720e1a0ddeSYana Esina u32 msg_id; 730e1a0ddeSYana Esina u8 hw_addr[ETH_ALEN]; 740e1a0ddeSYana Esina u8 magic_packet_enabled; 750e1a0ddeSYana Esina u8 filter_count; 760e1a0ddeSYana Esina struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT]; 770e1a0ddeSYana Esina u8 link_up_enabled; 780e1a0ddeSYana Esina u8 link_down_enabled; 790e1a0ddeSYana Esina u16 reserved; 800e1a0ddeSYana Esina u32 link_up_timeout; 810e1a0ddeSYana Esina u32 link_down_timeout; 820e1a0ddeSYana Esina }; 830e1a0ddeSYana Esina 8444e00dd8SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); 8544e00dd8SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 8644e00dd8SIgor Russkikh enum hal_atl_utils_fw_state_e state); 8744e00dd8SIgor Russkikh 886a7f2277SNikita Danilov static u32 aq_fw2x_mbox_get(struct aq_hw_s *self); 896a7f2277SNikita Danilov static u32 aq_fw2x_rpc_get(struct aq_hw_s *self); 90dc12f75aSNikita Danilov static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr); 9162c1c2e6SDmitry Bogdanov static u32 aq_fw2x_state_get(struct aq_hw_s *self); 926a7f2277SNikita Danilov static u32 aq_fw2x_state2_get(struct aq_hw_s *self); 936a7f2277SNikita Danilov 94a57d3929SIgor Russkikh static int aq_fw2x_init(struct aq_hw_s *self) 95a57d3929SIgor Russkikh { 96a57d3929SIgor Russkikh int err = 0; 97a57d3929SIgor Russkikh 98a57d3929SIgor Russkikh /* check 10 times by 1ms */ 996a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_mbox_get, 1006a7f2277SNikita Danilov self, self->mbox_addr, 1016a7f2277SNikita Danilov self->mbox_addr != 0U, 1026a7f2277SNikita Danilov 1000U, 10000U); 1036a7f2277SNikita Danilov 1046a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_rpc_get, 1056a7f2277SNikita Danilov self, self->rpc_addr, 1066a7f2277SNikita Danilov self->rpc_addr != 0U, 1076a7f2277SNikita Danilov 1000U, 100000U); 1083ee5c887SYana Esina 109dc12f75aSNikita Danilov err = aq_fw2x_settings_get(self, &self->settings_addr); 110dc12f75aSNikita Danilov 111a57d3929SIgor Russkikh return err; 112a57d3929SIgor Russkikh } 113a57d3929SIgor Russkikh 11444e00dd8SIgor Russkikh static int aq_fw2x_deinit(struct aq_hw_s *self) 11544e00dd8SIgor Russkikh { 11644e00dd8SIgor Russkikh int err = aq_fw2x_set_link_speed(self, 0); 11744e00dd8SIgor Russkikh 11844e00dd8SIgor Russkikh if (!err) 11944e00dd8SIgor Russkikh err = aq_fw2x_set_state(self, MPI_DEINIT); 12044e00dd8SIgor Russkikh 12144e00dd8SIgor Russkikh return err; 12244e00dd8SIgor Russkikh } 12344e00dd8SIgor Russkikh 124a57d3929SIgor Russkikh static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed) 125a57d3929SIgor Russkikh { 126a57d3929SIgor Russkikh enum hw_atl_fw2x_rate rate = 0; 127a57d3929SIgor Russkikh 128a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_10G) 129a57d3929SIgor Russkikh rate |= FW2X_RATE_10G; 130a57d3929SIgor Russkikh 131a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5G) 132a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 133a57d3929SIgor Russkikh 134a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_5GSR) 135a57d3929SIgor Russkikh rate |= FW2X_RATE_5G; 136a57d3929SIgor Russkikh 137a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_2GS) 138a57d3929SIgor Russkikh rate |= FW2X_RATE_2G5; 139a57d3929SIgor Russkikh 140a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_1G) 141a57d3929SIgor Russkikh rate |= FW2X_RATE_1G; 142a57d3929SIgor Russkikh 143a57d3929SIgor Russkikh if (speed & AQ_NIC_RATE_100M) 144a57d3929SIgor Russkikh rate |= FW2X_RATE_100M; 145a57d3929SIgor Russkikh 146a57d3929SIgor Russkikh return rate; 147a57d3929SIgor Russkikh } 148a57d3929SIgor Russkikh 14992ab6407SYana Esina static u32 fw2x_to_eee_mask(u32 speed) 15092ab6407SYana Esina { 15192ab6407SYana Esina u32 rate = 0; 15292ab6407SYana Esina 15392ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK) 15492ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_10G; 15592ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK) 15692ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_5G; 15792ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK) 15892ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_2GS; 15992ab6407SYana Esina if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK) 16092ab6407SYana Esina rate |= AQ_NIC_RATE_EEE_1G; 16192ab6407SYana Esina 16292ab6407SYana Esina return rate; 16392ab6407SYana Esina } 16492ab6407SYana Esina 16592ab6407SYana Esina static u32 eee_mask_to_fw2x(u32 speed) 16692ab6407SYana Esina { 16792ab6407SYana Esina u32 rate = 0; 16892ab6407SYana Esina 16992ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_10G) 17092ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK; 17192ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_5G) 17292ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK; 17392ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_2GS) 17492ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK; 17592ab6407SYana Esina if (speed & AQ_NIC_RATE_EEE_1G) 17692ab6407SYana Esina rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK; 17792ab6407SYana Esina 17892ab6407SYana Esina return rate; 17992ab6407SYana Esina } 18092ab6407SYana Esina 181a57d3929SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) 182a57d3929SIgor Russkikh { 183a57d3929SIgor Russkikh u32 val = link_speed_mask_2fw2x_ratemask(speed); 184a57d3929SIgor Russkikh 185a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val); 186a57d3929SIgor Russkikh 187a57d3929SIgor Russkikh return 0; 188a57d3929SIgor Russkikh } 189a57d3929SIgor Russkikh 1908009bb19SNikita Danilov static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self, 1918009bb19SNikita Danilov u32 *mpi_state, u32 fc) 192288551deSIgor Russkikh { 1938009bb19SNikita Danilov *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE | 1948009bb19SNikita Danilov HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE); 195288551deSIgor Russkikh 1968009bb19SNikita Danilov switch (fc) { 1978009bb19SNikita Danilov /* There is not explicit mode of RX only pause frames, 1988009bb19SNikita Danilov * thus, we join this mode with FC full. 1998009bb19SNikita Danilov * FC full is either Rx, either Tx, or both. 2008009bb19SNikita Danilov */ 2018009bb19SNikita Danilov case AQ_NIC_FC_FULL: 2028009bb19SNikita Danilov case AQ_NIC_FC_RX: 2038009bb19SNikita Danilov *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE | 2048009bb19SNikita Danilov HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; 2058009bb19SNikita Danilov break; 2068009bb19SNikita Danilov case AQ_NIC_FC_TX: 2078009bb19SNikita Danilov *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; 2088009bb19SNikita Danilov break; 2098009bb19SNikita Danilov } 210288551deSIgor Russkikh } 211288551deSIgor Russkikh 21292ab6407SYana Esina static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts, 21392ab6407SYana Esina u32 eee_speeds) 21492ab6407SYana Esina { 21592ab6407SYana Esina *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK | 21692ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_2G5_MASK | 21792ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_5G_MASK | 21892ab6407SYana Esina HW_ATL_FW2X_CAP_EEE_10G_MASK); 21992ab6407SYana Esina 22092ab6407SYana Esina *mpi_opts |= eee_mask_to_fw2x(eee_speeds); 22192ab6407SYana Esina } 22292ab6407SYana Esina 223a57d3929SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self, 224a57d3929SIgor Russkikh enum hal_atl_utils_fw_state_e state) 225a57d3929SIgor Russkikh { 22644e00dd8SIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 22792ab6407SYana Esina struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; 22844e00dd8SIgor Russkikh 22944e00dd8SIgor Russkikh switch (state) { 23044e00dd8SIgor Russkikh case MPI_INIT: 23144e00dd8SIgor Russkikh mpi_state &= ~BIT(CAPS_HI_LINK_DROP); 23292ab6407SYana Esina aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds); 2338009bb19SNikita Danilov aq_fw2x_upd_flow_control_bits(self, &mpi_state, 2348009bb19SNikita Danilov self->aq_nic_cfg->fc.req); 23544e00dd8SIgor Russkikh break; 23644e00dd8SIgor Russkikh case MPI_DEINIT: 23744e00dd8SIgor Russkikh mpi_state |= BIT(CAPS_HI_LINK_DROP); 23844e00dd8SIgor Russkikh break; 23944e00dd8SIgor Russkikh case MPI_RESET: 24044e00dd8SIgor Russkikh case MPI_POWER: 24144e00dd8SIgor Russkikh /* No actions */ 24244e00dd8SIgor Russkikh break; 24344e00dd8SIgor Russkikh } 24444e00dd8SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 2457b0c342fSNikita Danilov 246a57d3929SIgor Russkikh return 0; 247a57d3929SIgor Russkikh } 248a57d3929SIgor Russkikh 249a57d3929SIgor Russkikh static int aq_fw2x_update_link_status(struct aq_hw_s *self) 250a57d3929SIgor Russkikh { 251a57d3929SIgor Russkikh struct aq_hw_link_status_s *link_status = &self->aq_link_status; 2527b0c342fSNikita Danilov u32 mpi_state; 2537b0c342fSNikita Danilov u32 speed; 2547b0c342fSNikita Danilov 2557b0c342fSNikita Danilov mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); 2567b0c342fSNikita Danilov speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | 2577b0c342fSNikita Danilov FW2X_RATE_2G5 | FW2X_RATE_5G | 2587b0c342fSNikita Danilov FW2X_RATE_10G); 259a57d3929SIgor Russkikh 260a57d3929SIgor Russkikh if (speed) { 261a57d3929SIgor Russkikh if (speed & FW2X_RATE_10G) 262a57d3929SIgor Russkikh link_status->mbps = 10000; 263a57d3929SIgor Russkikh else if (speed & FW2X_RATE_5G) 264a57d3929SIgor Russkikh link_status->mbps = 5000; 265a57d3929SIgor Russkikh else if (speed & FW2X_RATE_2G5) 266a57d3929SIgor Russkikh link_status->mbps = 2500; 267a57d3929SIgor Russkikh else if (speed & FW2X_RATE_1G) 268a57d3929SIgor Russkikh link_status->mbps = 1000; 269a57d3929SIgor Russkikh else if (speed & FW2X_RATE_100M) 270a57d3929SIgor Russkikh link_status->mbps = 100; 271a57d3929SIgor Russkikh else 272a57d3929SIgor Russkikh link_status->mbps = 10000; 273a57d3929SIgor Russkikh } else { 274a57d3929SIgor Russkikh link_status->mbps = 0; 275a57d3929SIgor Russkikh } 276a57d3929SIgor Russkikh 277a57d3929SIgor Russkikh return 0; 278a57d3929SIgor Russkikh } 279a57d3929SIgor Russkikh 28076a45194SColin Ian King static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) 281a57d3929SIgor Russkikh { 2827b0c342fSNikita Danilov u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR); 2837b0c342fSNikita Danilov u32 mac_addr[2] = { 0 }; 284a57d3929SIgor Russkikh int err = 0; 285a57d3929SIgor Russkikh u32 h = 0U; 286a57d3929SIgor Russkikh u32 l = 0U; 287a57d3929SIgor Russkikh 288a57d3929SIgor Russkikh if (efuse_addr != 0) { 289a57d3929SIgor Russkikh err = hw_atl_utils_fw_downld_dwords(self, 290a57d3929SIgor Russkikh efuse_addr + (40U * 4U), 291a57d3929SIgor Russkikh mac_addr, 292a57d3929SIgor Russkikh ARRAY_SIZE(mac_addr)); 293a57d3929SIgor Russkikh if (err) 294a57d3929SIgor Russkikh return err; 295a57d3929SIgor Russkikh mac_addr[0] = __swab32(mac_addr[0]); 296a57d3929SIgor Russkikh mac_addr[1] = __swab32(mac_addr[1]); 297a57d3929SIgor Russkikh } 298a57d3929SIgor Russkikh 299a57d3929SIgor Russkikh ether_addr_copy(mac, (u8 *)mac_addr); 300a57d3929SIgor Russkikh 301a57d3929SIgor Russkikh if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { 302a57d3929SIgor Russkikh unsigned int rnd = 0; 303a57d3929SIgor Russkikh 304a57d3929SIgor Russkikh get_random_bytes(&rnd, sizeof(unsigned int)); 305a57d3929SIgor Russkikh 306e9157848SNikita Danilov l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16); 307a57d3929SIgor Russkikh h = 0x8001300EU; 308a57d3929SIgor Russkikh 309a57d3929SIgor Russkikh mac[5] = (u8)(0xFFU & l); 310a57d3929SIgor Russkikh l >>= 8; 311a57d3929SIgor Russkikh mac[4] = (u8)(0xFFU & l); 312a57d3929SIgor Russkikh l >>= 8; 313a57d3929SIgor Russkikh mac[3] = (u8)(0xFFU & l); 314a57d3929SIgor Russkikh l >>= 8; 315a57d3929SIgor Russkikh mac[2] = (u8)(0xFFU & l); 316a57d3929SIgor Russkikh mac[1] = (u8)(0xFFU & h); 317a57d3929SIgor Russkikh h >>= 8; 318a57d3929SIgor Russkikh mac[0] = (u8)(0xFFU & h); 319a57d3929SIgor Russkikh } 3207b0c342fSNikita Danilov 321a57d3929SIgor Russkikh return err; 322a57d3929SIgor Russkikh } 323a57d3929SIgor Russkikh 3240ba4ad32SYueHaibing static int aq_fw2x_update_stats(struct aq_hw_s *self) 325a57d3929SIgor Russkikh { 326a57d3929SIgor Russkikh u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 327a57d3929SIgor Russkikh u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS); 3286a7f2277SNikita Danilov u32 stats_val; 3297b0c342fSNikita Danilov int err = 0; 330a57d3929SIgor Russkikh 331a57d3929SIgor Russkikh /* Toggle statistics bit for FW to update */ 332a57d3929SIgor Russkikh mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS); 333a57d3929SIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 334a57d3929SIgor Russkikh 335a57d3929SIgor Russkikh /* Wait FW to report back */ 3366a7f2277SNikita Danilov err = readx_poll_timeout_atomic(aq_fw2x_state2_get, 3376a7f2277SNikita Danilov self, stats_val, 3386a7f2277SNikita Danilov orig_stats_val != (stats_val & 339a57d3929SIgor Russkikh BIT(CAPS_HI_STATISTICS)), 340a57d3929SIgor Russkikh 1U, 10000U); 341a57d3929SIgor Russkikh if (err) 342a57d3929SIgor Russkikh return err; 343a57d3929SIgor Russkikh 344a57d3929SIgor Russkikh return hw_atl_utils_update_stats(self); 345a57d3929SIgor Russkikh } 346a57d3929SIgor Russkikh 3478f894011SYana Esina static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp) 3488f894011SYana Esina { 3498f894011SYana Esina u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 3508f894011SYana Esina u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE; 3518f894011SYana Esina u32 phy_temp_offset; 3528f894011SYana Esina u32 temp_res; 3538f894011SYana Esina int err = 0; 3548f894011SYana Esina u32 val; 3558f894011SYana Esina 3567b0c342fSNikita Danilov phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 3577b0c342fSNikita Danilov info.phy_temperature); 3587b0c342fSNikita Danilov 3598f894011SYana Esina /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */ 3608f894011SYana Esina mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE; 3618f894011SYana Esina aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 3628f894011SYana Esina /* Wait FW to report back */ 3638f894011SYana Esina err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 3648f894011SYana Esina temp_val != 3658f894011SYana Esina (val & HW_ATL_FW2X_CTRL_TEMPERATURE), 3668f894011SYana Esina 1U, 10000U); 3678f894011SYana Esina err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset, 3688f894011SYana Esina &temp_res, 1); 3698f894011SYana Esina 3708f894011SYana Esina if (err) 3718f894011SYana Esina return err; 3728f894011SYana Esina 3738f894011SYana Esina /* Convert PHY temperature from 1/256 degree Celsius 3748f894011SYana Esina * to 1/1000 degree Celsius. 3758f894011SYana Esina */ 37606b0d7feSIgor Russkikh *temp = (temp_res & 0xFFFF) * 1000 / 256; 3778f894011SYana Esina 3788f894011SYana Esina return 0; 3798f894011SYana Esina } 3808f894011SYana Esina 381837c6378SNikita Danilov static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac) 382a0da96c0SYana Esina { 3838f60f762SNikita Danilov struct hw_atl_utils_fw_rpc *rpc = NULL; 384837c6378SNikita Danilov struct offload_info *info = NULL; 385837c6378SNikita Danilov u32 wol_bits = 0; 386837c6378SNikita Danilov u32 rpc_size; 387a0da96c0SYana Esina int err = 0; 3886a7f2277SNikita Danilov u32 val; 389a0da96c0SYana Esina 390837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_PHY) { 391837c6378SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, 392837c6378SNikita Danilov HW_ATL_FW2X_CTRL_LINK_DROP); 393837c6378SNikita Danilov readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 394837c6378SNikita Danilov (val & 395837c6378SNikita Danilov HW_ATL_FW2X_CTRL_LINK_DROP) != 0, 396837c6378SNikita Danilov 1000, 100000); 397837c6378SNikita Danilov wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK; 398837c6378SNikita Danilov } 399837c6378SNikita Danilov 400837c6378SNikita Danilov if (self->aq_nic_cfg->wol & WAKE_MAGIC) { 401837c6378SNikita Danilov wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY | 402837c6378SNikita Danilov HW_ATL_FW2X_CTRL_WOL; 403a0da96c0SYana Esina 404a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_wait(self, &rpc); 405a0da96c0SYana Esina if (err < 0) 406a0da96c0SYana Esina goto err_exit; 407a0da96c0SYana Esina 408837c6378SNikita Danilov rpc_size = sizeof(*info) + 409837c6378SNikita Danilov offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads); 410a0da96c0SYana Esina memset(rpc, 0, rpc_size); 411837c6378SNikita Danilov info = &rpc->fw2x_offloads; 412837c6378SNikita Danilov memcpy(info->mac_addr, mac, ETH_ALEN); 413837c6378SNikita Danilov info->len = sizeof(*info); 414a0da96c0SYana Esina 415a0da96c0SYana Esina err = hw_atl_utils_fw_rpc_call(self, rpc_size); 416a0da96c0SYana Esina if (err < 0) 417a0da96c0SYana Esina goto err_exit; 418a0da96c0SYana Esina } 419a0da96c0SYana Esina 420837c6378SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits); 421a0da96c0SYana Esina 422a0da96c0SYana Esina err_exit: 423a0da96c0SYana Esina return err; 424a0da96c0SYana Esina } 425a0da96c0SYana Esina 426a0da96c0SYana Esina static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, 427a0da96c0SYana Esina u8 *mac) 428a0da96c0SYana Esina { 429a0da96c0SYana Esina int err = 0; 430a0da96c0SYana Esina 431837c6378SNikita Danilov if (self->aq_nic_cfg->wol) 432837c6378SNikita Danilov err = aq_fw2x_set_wol(self, mac); 433a0da96c0SYana Esina 434a0da96c0SYana Esina return err; 435a0da96c0SYana Esina } 436a0da96c0SYana Esina 437910479a9SEgor Pomozov static int aq_fw2x_send_fw_request(struct aq_hw_s *self, 438910479a9SEgor Pomozov const struct hw_fw_request_iface *fw_req, 439910479a9SEgor Pomozov size_t size) 440910479a9SEgor Pomozov { 441910479a9SEgor Pomozov u32 ctrl2, orig_ctrl2; 442910479a9SEgor Pomozov u32 dword_cnt; 443910479a9SEgor Pomozov int err = 0; 444910479a9SEgor Pomozov u32 val; 445910479a9SEgor Pomozov 446910479a9SEgor Pomozov /* Write data to drvIface Mailbox */ 447910479a9SEgor Pomozov dword_cnt = size / sizeof(u32); 448910479a9SEgor Pomozov if (size % sizeof(u32)) 449910479a9SEgor Pomozov dword_cnt++; 450dc12f75aSNikita Danilov err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt); 451910479a9SEgor Pomozov if (err < 0) 452910479a9SEgor Pomozov goto err_exit; 453910479a9SEgor Pomozov 454910479a9SEgor Pomozov /* Toggle statistics bit for FW to update */ 455910479a9SEgor Pomozov ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 456910479a9SEgor Pomozov orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST); 457910479a9SEgor Pomozov ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST); 458910479a9SEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2); 459910479a9SEgor Pomozov 460910479a9SEgor Pomozov /* Wait FW to report back */ 461910479a9SEgor Pomozov err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, 462910479a9SEgor Pomozov orig_ctrl2 != (val & 463910479a9SEgor Pomozov BIT(CAPS_HI_FW_REQUEST)), 464910479a9SEgor Pomozov 1U, 10000U); 465910479a9SEgor Pomozov 466910479a9SEgor Pomozov err_exit: 467910479a9SEgor Pomozov return err; 468910479a9SEgor Pomozov } 469910479a9SEgor Pomozov 470910479a9SEgor Pomozov static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable) 471910479a9SEgor Pomozov { 472910479a9SEgor Pomozov u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR); 473910479a9SEgor Pomozov u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) | 474910479a9SEgor Pomozov BIT(CAPS_EX_PTP_GPIO_EN); 475910479a9SEgor Pomozov 476910479a9SEgor Pomozov if (enable) 477910479a9SEgor Pomozov ptp_opts |= all_ptp_features; 478910479a9SEgor Pomozov else 479910479a9SEgor Pomozov ptp_opts &= ~all_ptp_features; 480910479a9SEgor Pomozov 481910479a9SEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts); 482910479a9SEgor Pomozov } 483910479a9SEgor Pomozov 484f08a464cSEgor Pomozov static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj) 485f08a464cSEgor Pomozov { 486f08a464cSEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR, 487f08a464cSEgor Pomozov (adj >> 0) & 0xffffffff); 488f08a464cSEgor Pomozov aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR, 489f08a464cSEgor Pomozov (adj >> 32) & 0xffffffff); 490f08a464cSEgor Pomozov } 491f08a464cSEgor Pomozov 492d1287ce4SNikita Danilov static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode) 493d1287ce4SNikita Danilov { 494d1287ce4SNikita Danilov if (self->fw_ver_actual < HW_ATL_FW_VER_LED) 495d1287ce4SNikita Danilov return -EOPNOTSUPP; 496d1287ce4SNikita Danilov 497d1287ce4SNikita Danilov aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode); 498d1287ce4SNikita Danilov 499d1287ce4SNikita Danilov return 0; 500d1287ce4SNikita Danilov } 501d1287ce4SNikita Danilov 50292ab6407SYana Esina static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) 50392ab6407SYana Esina { 50492ab6407SYana Esina u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 50592ab6407SYana Esina 50692ab6407SYana Esina aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed); 50792ab6407SYana Esina 50892ab6407SYana Esina aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 50992ab6407SYana Esina 51092ab6407SYana Esina return 0; 51192ab6407SYana Esina } 51292ab6407SYana Esina 51392ab6407SYana Esina static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate, 51492ab6407SYana Esina u32 *supported_rates) 51592ab6407SYana Esina { 51692ab6407SYana Esina u32 mpi_state; 51792ab6407SYana Esina u32 caps_hi; 51892ab6407SYana Esina int err = 0; 5197b0c342fSNikita Danilov u32 offset; 52092ab6407SYana Esina 5217b0c342fSNikita Danilov offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 5227b0c342fSNikita Danilov info.caps_hi); 5237b0c342fSNikita Danilov 5247b0c342fSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1); 52592ab6407SYana Esina 52692ab6407SYana Esina if (err) 52792ab6407SYana Esina return err; 52892ab6407SYana Esina 52992ab6407SYana Esina *supported_rates = fw2x_to_eee_mask(caps_hi); 53092ab6407SYana Esina 5310b926d46SNikita Danilov mpi_state = aq_fw2x_state2_get(self); 53292ab6407SYana Esina *rate = fw2x_to_eee_mask(mpi_state); 53392ab6407SYana Esina 53492ab6407SYana Esina return err; 53592ab6407SYana Esina } 53692ab6407SYana Esina 537b8d68b62SAnton Mikaev static int aq_fw2x_renegotiate(struct aq_hw_s *self) 538b8d68b62SAnton Mikaev { 539b8d68b62SAnton Mikaev u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 540b8d68b62SAnton Mikaev 541b8d68b62SAnton Mikaev mpi_opts |= BIT(CTRL_FORCE_RECONNECT); 542b8d68b62SAnton Mikaev 543b8d68b62SAnton Mikaev aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 544b8d68b62SAnton Mikaev 545b8d68b62SAnton Mikaev return 0; 546b8d68b62SAnton Mikaev } 547b8d68b62SAnton Mikaev 548288551deSIgor Russkikh static int aq_fw2x_set_flow_control(struct aq_hw_s *self) 549288551deSIgor Russkikh { 550288551deSIgor Russkikh u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 551288551deSIgor Russkikh 5528009bb19SNikita Danilov aq_fw2x_upd_flow_control_bits(self, &mpi_state, 5538009bb19SNikita Danilov self->aq_nic_cfg->fc.req); 554288551deSIgor Russkikh 555288551deSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); 556288551deSIgor Russkikh 557288551deSIgor Russkikh return 0; 558288551deSIgor Russkikh } 559288551deSIgor Russkikh 56035e8e8b4SIgor Russkikh static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode) 56135e8e8b4SIgor Russkikh { 5620b926d46SNikita Danilov u32 mpi_state = aq_fw2x_state2_get(self); 5638009bb19SNikita Danilov *fcmode = 0; 56435e8e8b4SIgor Russkikh 56535e8e8b4SIgor Russkikh if (mpi_state & HW_ATL_FW2X_CAP_PAUSE) 5668009bb19SNikita Danilov *fcmode |= AQ_NIC_FC_RX; 5678009bb19SNikita Danilov 56835e8e8b4SIgor Russkikh if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) 5698009bb19SNikita Danilov *fcmode |= AQ_NIC_FC_TX; 57035e8e8b4SIgor Russkikh 57135e8e8b4SIgor Russkikh return 0; 57235e8e8b4SIgor Russkikh } 57335e8e8b4SIgor Russkikh 574ea4b4d7fSIgor Russkikh static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable) 575ea4b4d7fSIgor Russkikh { 576ea4b4d7fSIgor Russkikh u32 mpi_opts; 577ea4b4d7fSIgor Russkikh 578ea4b4d7fSIgor Russkikh switch (mode) { 579ea4b4d7fSIgor Russkikh case AQ_HW_LOOPBACK_PHYINT_SYS: 580ea4b4d7fSIgor Russkikh mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 581ea4b4d7fSIgor Russkikh if (enable) 582ea4b4d7fSIgor Russkikh mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK; 583ea4b4d7fSIgor Russkikh else 584ea4b4d7fSIgor Russkikh mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK; 585ea4b4d7fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 586ea4b4d7fSIgor Russkikh break; 587ea4b4d7fSIgor Russkikh case AQ_HW_LOOPBACK_PHYEXT_SYS: 588ea4b4d7fSIgor Russkikh mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 589ea4b4d7fSIgor Russkikh if (enable) 590ea4b4d7fSIgor Russkikh mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK; 591ea4b4d7fSIgor Russkikh else 592ea4b4d7fSIgor Russkikh mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK; 593ea4b4d7fSIgor Russkikh aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 594ea4b4d7fSIgor Russkikh break; 595ea4b4d7fSIgor Russkikh default: 596ea4b4d7fSIgor Russkikh return -EINVAL; 597ea4b4d7fSIgor Russkikh } 5987b0c342fSNikita Danilov 599ea4b4d7fSIgor Russkikh return 0; 600ea4b4d7fSIgor Russkikh } 601ea4b4d7fSIgor Russkikh 6026a7f2277SNikita Danilov static u32 aq_fw2x_mbox_get(struct aq_hw_s *self) 6036a7f2277SNikita Danilov { 6046a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR); 6056a7f2277SNikita Danilov } 6066a7f2277SNikita Danilov 6076a7f2277SNikita Danilov static u32 aq_fw2x_rpc_get(struct aq_hw_s *self) 6086a7f2277SNikita Danilov { 6096a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR); 6106a7f2277SNikita Danilov } 6116a7f2277SNikita Danilov 612dc12f75aSNikita Danilov static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr) 613dc12f75aSNikita Danilov { 614dc12f75aSNikita Danilov int err = 0; 615dc12f75aSNikita Danilov u32 offset; 616dc12f75aSNikita Danilov 617dc12f75aSNikita Danilov offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, 618dc12f75aSNikita Danilov info.setting_address); 619dc12f75aSNikita Danilov 620dc12f75aSNikita Danilov err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1); 621dc12f75aSNikita Danilov 622dc12f75aSNikita Danilov return err; 623dc12f75aSNikita Danilov } 624dc12f75aSNikita Danilov 62562c1c2e6SDmitry Bogdanov static u32 aq_fw2x_state_get(struct aq_hw_s *self) 62662c1c2e6SDmitry Bogdanov { 62762c1c2e6SDmitry Bogdanov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); 62862c1c2e6SDmitry Bogdanov } 62962c1c2e6SDmitry Bogdanov 6306a7f2277SNikita Danilov static u32 aq_fw2x_state2_get(struct aq_hw_s *self) 6316a7f2277SNikita Danilov { 6326a7f2277SNikita Danilov return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); 6336a7f2277SNikita Danilov } 6346a7f2277SNikita Danilov 63562c1c2e6SDmitry Bogdanov static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self) 63662c1c2e6SDmitry Bogdanov { 63762c1c2e6SDmitry Bogdanov int err = 0; 63862c1c2e6SDmitry Bogdanov u32 offset; 63962c1c2e6SDmitry Bogdanov u32 val; 64062c1c2e6SDmitry Bogdanov 64162c1c2e6SDmitry Bogdanov offset = self->mbox_addr + 64262c1c2e6SDmitry Bogdanov offsetof(struct hw_atl_utils_mbox, info.caps_lo); 64362c1c2e6SDmitry Bogdanov 64462c1c2e6SDmitry Bogdanov err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1); 64562c1c2e6SDmitry Bogdanov 64662c1c2e6SDmitry Bogdanov if (err) 64762c1c2e6SDmitry Bogdanov return 0; 64862c1c2e6SDmitry Bogdanov 64962c1c2e6SDmitry Bogdanov return val; 65062c1c2e6SDmitry Bogdanov } 65162c1c2e6SDmitry Bogdanov 65262c1c2e6SDmitry Bogdanov static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw, 65362c1c2e6SDmitry Bogdanov struct macsec_msg_fw_request *req, 65462c1c2e6SDmitry Bogdanov struct macsec_msg_fw_response *response) 65562c1c2e6SDmitry Bogdanov { 65662c1c2e6SDmitry Bogdanov u32 low_status, low_req = 0; 65762c1c2e6SDmitry Bogdanov u32 dword_cnt; 65862c1c2e6SDmitry Bogdanov u32 caps_lo; 65962c1c2e6SDmitry Bogdanov u32 offset; 66062c1c2e6SDmitry Bogdanov int err; 66162c1c2e6SDmitry Bogdanov 66262c1c2e6SDmitry Bogdanov if (!req || !response) 66362c1c2e6SDmitry Bogdanov return -EINVAL; 66462c1c2e6SDmitry Bogdanov 66562c1c2e6SDmitry Bogdanov caps_lo = aq_fw2x_get_link_capabilities(hw); 66662c1c2e6SDmitry Bogdanov if (!(caps_lo & BIT(CAPS_LO_MACSEC))) 66762c1c2e6SDmitry Bogdanov return -EOPNOTSUPP; 66862c1c2e6SDmitry Bogdanov 66962c1c2e6SDmitry Bogdanov /* Write macsec request to cfg memory */ 67062c1c2e6SDmitry Bogdanov dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32); 67162c1c2e6SDmitry Bogdanov err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt); 67262c1c2e6SDmitry Bogdanov if (err < 0) 67362c1c2e6SDmitry Bogdanov return err; 67462c1c2e6SDmitry Bogdanov 67562c1c2e6SDmitry Bogdanov /* Toggle 0x368.CAPS_LO_MACSEC bit */ 67662c1c2e6SDmitry Bogdanov low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR); 67762c1c2e6SDmitry Bogdanov low_req ^= HW_ATL_FW2X_CAP_MACSEC; 67862c1c2e6SDmitry Bogdanov aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req); 67962c1c2e6SDmitry Bogdanov 68062c1c2e6SDmitry Bogdanov /* Wait FW to report back */ 68162c1c2e6SDmitry Bogdanov err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status, 68262c1c2e6SDmitry Bogdanov low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U); 68362c1c2e6SDmitry Bogdanov if (err) 68462c1c2e6SDmitry Bogdanov return -EIO; 68562c1c2e6SDmitry Bogdanov 68662c1c2e6SDmitry Bogdanov /* Read status of write operation */ 68762c1c2e6SDmitry Bogdanov offset = hw->rpc_addr + sizeof(u32); 68862c1c2e6SDmitry Bogdanov err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response, 68962c1c2e6SDmitry Bogdanov sizeof(*response) / sizeof(u32)); 69062c1c2e6SDmitry Bogdanov 69162c1c2e6SDmitry Bogdanov return err; 69262c1c2e6SDmitry Bogdanov } 69362c1c2e6SDmitry Bogdanov 694a57d3929SIgor Russkikh const struct aq_fw_ops aq_fw_2x_ops = { 695a57d3929SIgor Russkikh .init = aq_fw2x_init, 69644e00dd8SIgor Russkikh .deinit = aq_fw2x_deinit, 697a57d3929SIgor Russkikh .reset = NULL, 698b8d68b62SAnton Mikaev .renegotiate = aq_fw2x_renegotiate, 699a57d3929SIgor Russkikh .get_mac_permanent = aq_fw2x_get_mac_permanent, 700a57d3929SIgor Russkikh .set_link_speed = aq_fw2x_set_link_speed, 701a57d3929SIgor Russkikh .set_state = aq_fw2x_set_state, 702a57d3929SIgor Russkikh .update_link_status = aq_fw2x_update_link_status, 703a57d3929SIgor Russkikh .update_stats = aq_fw2x_update_stats, 7048f894011SYana Esina .get_phy_temp = aq_fw2x_get_phy_temp, 705a0da96c0SYana Esina .set_power = aq_fw2x_set_power, 70692ab6407SYana Esina .set_eee_rate = aq_fw2x_set_eee_rate, 70792ab6407SYana Esina .get_eee_rate = aq_fw2x_get_eee_rate, 708288551deSIgor Russkikh .set_flow_control = aq_fw2x_set_flow_control, 709910479a9SEgor Pomozov .get_flow_control = aq_fw2x_get_flow_control, 710910479a9SEgor Pomozov .send_fw_request = aq_fw2x_send_fw_request, 711910479a9SEgor Pomozov .enable_ptp = aq_fw3x_enable_ptp, 712d1287ce4SNikita Danilov .led_control = aq_fw2x_led_control, 713ea4b4d7fSIgor Russkikh .set_phyloopback = aq_fw2x_set_phyloopback, 714f08a464cSEgor Pomozov .adjust_ptp = aq_fw3x_adjust_ptp, 71562c1c2e6SDmitry Bogdanov .get_link_capabilities = aq_fw2x_get_link_capabilities, 71662c1c2e6SDmitry Bogdanov .send_macsec_req = aq_fw2x_send_macsec_req, 717a57d3929SIgor Russkikh }; 718