cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hw_atl_utils_fw2x.c (19197B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Atlantic Network Driver
      3 *
      4 * Copyright (C) 2014-2019 aQuantia Corporation
      5 * Copyright (C) 2019-2020 Marvell International Ltd.
      6 */
      7
      8/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
      9 * Atlantic hardware abstraction layer.
     10 */
     11
     12#include "../aq_hw.h"
     13#include "../aq_hw_utils.h"
     14#include "../aq_pci_func.h"
     15#include "../aq_ring.h"
     16#include "../aq_vec.h"
     17#include "../aq_nic.h"
     18#include "hw_atl_utils.h"
     19#include "hw_atl_llh.h"
     20
     21#define HW_ATL_FW2X_MPI_LED_ADDR         0x31c
     22#define HW_ATL_FW2X_MPI_RPC_ADDR         0x334
     23
     24#define HW_ATL_FW2X_MPI_MBOX_ADDR        0x360
     25#define HW_ATL_FW2X_MPI_EFUSE_ADDR       0x364
     26#define HW_ATL_FW2X_MPI_CONTROL_ADDR     0x368
     27#define HW_ATL_FW2X_MPI_CONTROL2_ADDR    0x36C
     28#define HW_ATL_FW2X_MPI_STATE_ADDR       0x370
     29#define HW_ATL_FW2X_MPI_STATE2_ADDR      0x374
     30
     31#define HW_ATL_FW3X_EXT_CONTROL_ADDR     0x378
     32#define HW_ATL_FW3X_EXT_STATE_ADDR       0x37c
     33
     34#define HW_ATL_FW3X_PTP_ADJ_LSW_ADDR	 0x50a0
     35#define HW_ATL_FW3X_PTP_ADJ_MSW_ADDR	 0x50a4
     36
     37#define HW_ATL_FW2X_CAP_PAUSE            BIT(CAPS_HI_PAUSE)
     38#define HW_ATL_FW2X_CAP_ASYM_PAUSE       BIT(CAPS_HI_ASYMMETRIC_PAUSE)
     39#define HW_ATL_FW2X_CAP_SLEEP_PROXY      BIT(CAPS_HI_SLEEP_PROXY)
     40#define HW_ATL_FW2X_CAP_WOL              BIT(CAPS_HI_WOL)
     41
     42#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK     BIT(CTRL_WAKE_ON_LINK)
     43#define HW_ATL_FW2X_CTRL_SLEEP_PROXY      BIT(CTRL_SLEEP_PROXY)
     44#define HW_ATL_FW2X_CTRL_WOL              BIT(CTRL_WOL)
     45#define HW_ATL_FW2X_CTRL_LINK_DROP        BIT(CTRL_LINK_DROP)
     46#define HW_ATL_FW2X_CTRL_PAUSE            BIT(CTRL_PAUSE)
     47#define HW_ATL_FW2X_CTRL_TEMPERATURE      BIT(CTRL_TEMPERATURE)
     48#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
     49#define HW_ATL_FW2X_CTRL_INT_LOOPBACK     BIT(CTRL_INT_LOOPBACK)
     50#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK     BIT(CTRL_EXT_LOOPBACK)
     51#define HW_ATL_FW2X_CTRL_DOWNSHIFT        BIT(CTRL_DOWNSHIFT)
     52#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT  BIT(CTRL_FORCE_RECONNECT)
     53
     54#define HW_ATL_FW2X_CAP_EEE_1G_MASK      BIT(CAPS_HI_1000BASET_FD_EEE)
     55#define HW_ATL_FW2X_CAP_EEE_2G5_MASK     BIT(CAPS_HI_2P5GBASET_FD_EEE)
     56#define HW_ATL_FW2X_CAP_EEE_5G_MASK      BIT(CAPS_HI_5GBASET_FD_EEE)
     57#define HW_ATL_FW2X_CAP_EEE_10G_MASK     BIT(CAPS_HI_10GBASET_FD_EEE)
     58
     59#define HW_ATL_FW2X_CAP_MACSEC           BIT(CAPS_LO_MACSEC)
     60
     61#define HAL_ATLANTIC_WOL_FILTERS_COUNT   8
     62#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL  0x0E
     63
     64#define HW_ATL_FW_VER_LED                0x03010026U
     65#define HW_ATL_FW_VER_MEDIA_CONTROL      0x0301005aU
     66
     67struct __packed fw2x_msg_wol_pattern {
     68	u8 mask[16];
     69	u32 crc;
     70};
     71
     72struct __packed fw2x_msg_wol {
     73	u32 msg_id;
     74	u8 hw_addr[ETH_ALEN];
     75	u8 magic_packet_enabled;
     76	u8 filter_count;
     77	struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
     78	u8 link_up_enabled;
     79	u8 link_down_enabled;
     80	u16 reserved;
     81	u32 link_up_timeout;
     82	u32 link_down_timeout;
     83};
     84
     85static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
     86static int aq_fw2x_set_state(struct aq_hw_s *self,
     87			     enum hal_atl_utils_fw_state_e state);
     88
     89static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
     90static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
     91static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
     92static u32 aq_fw2x_state_get(struct aq_hw_s *self);
     93static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
     94
     95static int aq_fw2x_init(struct aq_hw_s *self)
     96{
     97	int err = 0;
     98
     99	/* check 10 times by 1ms */
    100	err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
    101					self, self->mbox_addr,
    102					self->mbox_addr != 0U,
    103					1000U, 10000U);
    104
    105	err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
    106					self, self->rpc_addr,
    107					self->rpc_addr != 0U,
    108					1000U, 100000U);
    109
    110	err = aq_fw2x_settings_get(self, &self->settings_addr);
    111
    112	return err;
    113}
    114
    115static int aq_fw2x_deinit(struct aq_hw_s *self)
    116{
    117	int err = aq_fw2x_set_link_speed(self, 0);
    118
    119	if (!err)
    120		err = aq_fw2x_set_state(self, MPI_DEINIT);
    121
    122	return err;
    123}
    124
    125static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
    126{
    127	enum hw_atl_fw2x_rate rate = 0;
    128
    129	if (speed & AQ_NIC_RATE_10G)
    130		rate |= FW2X_RATE_10G;
    131
    132	if (speed & AQ_NIC_RATE_5G)
    133		rate |= FW2X_RATE_5G;
    134
    135	if (speed & AQ_NIC_RATE_2G5)
    136		rate |= FW2X_RATE_2G5;
    137
    138	if (speed & AQ_NIC_RATE_1G)
    139		rate |= FW2X_RATE_1G;
    140
    141	if (speed & AQ_NIC_RATE_100M)
    142		rate |= FW2X_RATE_100M;
    143
    144	return rate;
    145}
    146
    147static u32 fw2x_to_eee_mask(u32 speed)
    148{
    149	u32 rate = 0;
    150
    151	if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
    152		rate |= AQ_NIC_RATE_EEE_10G;
    153	if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
    154		rate |= AQ_NIC_RATE_EEE_5G;
    155	if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
    156		rate |= AQ_NIC_RATE_EEE_2G5;
    157	if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
    158		rate |= AQ_NIC_RATE_EEE_1G;
    159
    160	return rate;
    161}
    162
    163static u32 eee_mask_to_fw2x(u32 speed)
    164{
    165	u32 rate = 0;
    166
    167	if (speed & AQ_NIC_RATE_EEE_10G)
    168		rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
    169	if (speed & AQ_NIC_RATE_EEE_5G)
    170		rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
    171	if (speed & AQ_NIC_RATE_EEE_2G5)
    172		rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
    173	if (speed & AQ_NIC_RATE_EEE_1G)
    174		rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
    175
    176	return rate;
    177}
    178
    179static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
    180{
    181	u32 val = link_speed_mask_2fw2x_ratemask(speed);
    182
    183	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
    184
    185	return 0;
    186}
    187
    188static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
    189					  u32 *mpi_state, u32 fc)
    190{
    191	*mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
    192			HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
    193
    194	switch (fc) {
    195	/* There is not explicit mode of RX only pause frames,
    196	 * thus, we join this mode with FC full.
    197	 * FC full is either Rx, either Tx, or both.
    198	 */
    199	case AQ_NIC_FC_FULL:
    200	case AQ_NIC_FC_RX:
    201		*mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
    202			      HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
    203		break;
    204	case AQ_NIC_FC_TX:
    205		*mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
    206		break;
    207	}
    208}
    209
    210static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
    211				      u32 eee_speeds)
    212{
    213	*mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
    214		       HW_ATL_FW2X_CAP_EEE_2G5_MASK |
    215		       HW_ATL_FW2X_CAP_EEE_5G_MASK |
    216		       HW_ATL_FW2X_CAP_EEE_10G_MASK);
    217
    218	*mpi_opts |= eee_mask_to_fw2x(eee_speeds);
    219}
    220
    221static int aq_fw2x_set_state(struct aq_hw_s *self,
    222			     enum hal_atl_utils_fw_state_e state)
    223{
    224	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    225	struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
    226
    227	switch (state) {
    228	case MPI_INIT:
    229		mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
    230		aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
    231		aq_fw2x_upd_flow_control_bits(self, &mpi_state,
    232					      self->aq_nic_cfg->fc.req);
    233		break;
    234	case MPI_DEINIT:
    235		mpi_state |= BIT(CAPS_HI_LINK_DROP);
    236		break;
    237	case MPI_RESET:
    238	case MPI_POWER:
    239		/* No actions */
    240		break;
    241	}
    242	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
    243
    244	return 0;
    245}
    246
    247static int aq_fw2x_update_link_status(struct aq_hw_s *self)
    248{
    249	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
    250	u32 mpi_state;
    251	u32 speed;
    252
    253	mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
    254	speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
    255			     FW2X_RATE_2G5 | FW2X_RATE_5G |
    256			     FW2X_RATE_10G);
    257
    258	if (speed) {
    259		if (speed & FW2X_RATE_10G)
    260			link_status->mbps = 10000;
    261		else if (speed & FW2X_RATE_5G)
    262			link_status->mbps = 5000;
    263		else if (speed & FW2X_RATE_2G5)
    264			link_status->mbps = 2500;
    265		else if (speed & FW2X_RATE_1G)
    266			link_status->mbps = 1000;
    267		else if (speed & FW2X_RATE_100M)
    268			link_status->mbps = 100;
    269		else
    270			link_status->mbps = 10000;
    271	} else {
    272		link_status->mbps = 0;
    273	}
    274	link_status->full_duplex = true;
    275
    276	return 0;
    277}
    278
    279static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
    280{
    281	u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
    282	u32 mac_addr[2] = { 0 };
    283	int err = 0;
    284
    285	if (efuse_addr != 0) {
    286		err = hw_atl_utils_fw_downld_dwords(self,
    287						    efuse_addr + (40U * 4U),
    288						    mac_addr,
    289						    ARRAY_SIZE(mac_addr));
    290		if (err)
    291			return err;
    292		mac_addr[0] = __swab32(mac_addr[0]);
    293		mac_addr[1] = __swab32(mac_addr[1]);
    294	}
    295
    296	ether_addr_copy(mac, (u8 *)mac_addr);
    297
    298	return err;
    299}
    300
    301static int aq_fw2x_update_stats(struct aq_hw_s *self)
    302{
    303	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    304	u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
    305	u32 stats_val;
    306	int err = 0;
    307
    308	/* Toggle statistics bit for FW to update */
    309	mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
    310	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    311
    312	/* Wait FW to report back */
    313	err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
    314					self, stats_val,
    315					orig_stats_val != (stats_val &
    316					BIT(CAPS_HI_STATISTICS)),
    317					1U, 10000U);
    318	if (err)
    319		return err;
    320
    321	return hw_atl_utils_update_stats(self);
    322}
    323
    324static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
    325{
    326	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    327	u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
    328	u32 phy_temp_offset;
    329	u32 temp_res;
    330	int err = 0;
    331	u32 val;
    332
    333	phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
    334						     info.phy_temperature);
    335
    336	/* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
    337	mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
    338	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    339	/* Wait FW to report back */
    340	err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
    341					temp_val !=
    342					(val & HW_ATL_FW2X_CTRL_TEMPERATURE),
    343					1U, 10000U);
    344	err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
    345					    &temp_res, 1);
    346
    347	if (err)
    348		return err;
    349
    350	/* Convert PHY temperature from 1/256 degree Celsius
    351	 * to 1/1000 degree Celsius.
    352	 */
    353	*temp = (int16_t)(temp_res & 0xFFFF) * 1000 / 256;
    354
    355	return 0;
    356}
    357
    358static int aq_fw2x_set_wol(struct aq_hw_s *self, const u8 *mac)
    359{
    360	struct hw_atl_utils_fw_rpc *rpc = NULL;
    361	struct offload_info *info = NULL;
    362	u32 wol_bits = 0;
    363	u32 rpc_size;
    364	int err = 0;
    365	u32 val;
    366
    367	if (self->aq_nic_cfg->wol & WAKE_PHY) {
    368		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
    369				HW_ATL_FW2X_CTRL_LINK_DROP);
    370		readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
    371					  (val &
    372					   HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
    373					  1000, 100000);
    374		wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
    375	}
    376
    377	if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
    378		wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
    379			    HW_ATL_FW2X_CTRL_WOL;
    380
    381		err = hw_atl_utils_fw_rpc_wait(self, &rpc);
    382		if (err < 0)
    383			goto err_exit;
    384
    385		rpc_size = sizeof(*info) +
    386			   offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
    387		memset(rpc, 0, rpc_size);
    388		info = &rpc->fw2x_offloads;
    389		memcpy(info->mac_addr, mac, ETH_ALEN);
    390		info->len = sizeof(*info);
    391
    392		err = hw_atl_utils_fw_rpc_call(self, rpc_size);
    393		if (err < 0)
    394			goto err_exit;
    395	}
    396
    397	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
    398
    399err_exit:
    400	return err;
    401}
    402
    403static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
    404			     const u8 *mac)
    405{
    406	int err = 0;
    407
    408	if (self->aq_nic_cfg->wol)
    409		err = aq_fw2x_set_wol(self, mac);
    410
    411	return err;
    412}
    413
    414static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
    415				   const struct hw_fw_request_iface *fw_req,
    416				   size_t size)
    417{
    418	u32 ctrl2, orig_ctrl2;
    419	u32 dword_cnt;
    420	int err = 0;
    421	u32 val;
    422
    423	/* Write data to drvIface Mailbox */
    424	dword_cnt = size / sizeof(u32);
    425	if (size % sizeof(u32))
    426		dword_cnt++;
    427	err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
    428	if (err < 0)
    429		goto err_exit;
    430
    431	/* Toggle statistics bit for FW to update */
    432	ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    433	orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
    434	ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
    435	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
    436
    437	/* Wait FW to report back */
    438	err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
    439					orig_ctrl2 != (val &
    440						       BIT(CAPS_HI_FW_REQUEST)),
    441					1U, 10000U);
    442
    443err_exit:
    444	return err;
    445}
    446
    447static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
    448{
    449	u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
    450	u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
    451						   BIT(CAPS_EX_PTP_GPIO_EN);
    452
    453	if (enable)
    454		ptp_opts |= all_ptp_features;
    455	else
    456		ptp_opts &= ~all_ptp_features;
    457
    458	aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
    459}
    460
    461static void aq_fw3x_adjust_ptp(struct aq_hw_s *self, uint64_t adj)
    462{
    463	aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_LSW_ADDR,
    464			(adj >>  0) & 0xffffffff);
    465	aq_hw_write_reg(self, HW_ATL_FW3X_PTP_ADJ_MSW_ADDR,
    466			(adj >> 32) & 0xffffffff);
    467}
    468
    469static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
    470{
    471	if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
    472		return -EOPNOTSUPP;
    473
    474	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
    475
    476	return 0;
    477}
    478
    479static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
    480{
    481	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    482
    483	aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
    484
    485	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    486
    487	return 0;
    488}
    489
    490static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
    491				u32 *supported_rates)
    492{
    493	u32 mpi_state;
    494	u32 caps_hi;
    495	int err = 0;
    496	u32 offset;
    497
    498	offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
    499					    info.caps_hi);
    500
    501	err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
    502
    503	if (err)
    504		return err;
    505
    506	*supported_rates = fw2x_to_eee_mask(caps_hi);
    507
    508	mpi_state = aq_fw2x_state2_get(self);
    509	*rate = fw2x_to_eee_mask(mpi_state);
    510
    511	return err;
    512}
    513
    514static int aq_fw2x_renegotiate(struct aq_hw_s *self)
    515{
    516	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    517
    518	mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
    519
    520	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    521
    522	return 0;
    523}
    524
    525static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
    526{
    527	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    528
    529	aq_fw2x_upd_flow_control_bits(self, &mpi_state,
    530				      self->aq_nic_cfg->fc.req);
    531
    532	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
    533
    534	return 0;
    535}
    536
    537static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
    538{
    539	u32 mpi_state = aq_fw2x_state2_get(self);
    540	*fcmode = 0;
    541
    542	if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
    543		*fcmode |= AQ_NIC_FC_RX;
    544
    545	if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
    546		*fcmode |= AQ_NIC_FC_TX;
    547
    548	return 0;
    549}
    550
    551static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
    552{
    553	u32 mpi_opts;
    554
    555	switch (mode) {
    556	case AQ_HW_LOOPBACK_PHYINT_SYS:
    557		mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    558		if (enable)
    559			mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
    560		else
    561			mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
    562		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    563		break;
    564	case AQ_HW_LOOPBACK_PHYEXT_SYS:
    565		mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    566		if (enable)
    567			mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
    568		else
    569			mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
    570		aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    571		break;
    572	default:
    573		return -EINVAL;
    574	}
    575
    576	return 0;
    577}
    578
    579static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
    580{
    581	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
    582}
    583
    584static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
    585{
    586	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
    587}
    588
    589static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
    590{
    591	int err = 0;
    592	u32 offset;
    593
    594	offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
    595					    info.setting_address);
    596
    597	err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
    598
    599	return err;
    600}
    601
    602static u32 aq_fw2x_state_get(struct aq_hw_s *self)
    603{
    604	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
    605}
    606
    607static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
    608{
    609	return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
    610}
    611
    612static int aq_fw2x_set_downshift(struct aq_hw_s *self, u32 counter)
    613{
    614	int err = 0;
    615	u32 mpi_opts;
    616	u32 offset;
    617
    618	offset = offsetof(struct hw_atl_utils_settings, downshift_retry_count);
    619	err = hw_atl_write_fwsettings_dwords(self, offset, &counter, 1);
    620	if (err)
    621		return err;
    622
    623	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
    624	if (counter)
    625		mpi_opts |= HW_ATL_FW2X_CTRL_DOWNSHIFT;
    626	else
    627		mpi_opts &= ~HW_ATL_FW2X_CTRL_DOWNSHIFT;
    628	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
    629
    630	return err;
    631}
    632
    633static int aq_fw2x_set_media_detect(struct aq_hw_s *self, bool on)
    634{
    635	u32 enable;
    636	u32 offset;
    637
    638	if (self->fw_ver_actual < HW_ATL_FW_VER_MEDIA_CONTROL)
    639		return -EOPNOTSUPP;
    640
    641	offset = offsetof(struct hw_atl_utils_settings, media_detect);
    642	enable = on;
    643
    644	return hw_atl_write_fwsettings_dwords(self, offset, &enable, 1);
    645}
    646
    647static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self)
    648{
    649	int err = 0;
    650	u32 offset;
    651	u32 val;
    652
    653	offset = self->mbox_addr +
    654		 offsetof(struct hw_atl_utils_mbox, info.caps_lo);
    655
    656	err = hw_atl_utils_fw_downld_dwords(self, offset, &val, 1);
    657
    658	if (err)
    659		return 0;
    660
    661	return val;
    662}
    663
    664static int aq_fw2x_send_macsec_req(struct aq_hw_s *hw,
    665				   struct macsec_msg_fw_request *req,
    666				   struct macsec_msg_fw_response *response)
    667{
    668	u32 low_status, low_req = 0;
    669	u32 dword_cnt;
    670	u32 caps_lo;
    671	u32 offset;
    672	int err;
    673
    674	if (!req || !response)
    675		return -EINVAL;
    676
    677	caps_lo = aq_fw2x_get_link_capabilities(hw);
    678	if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
    679		return -EOPNOTSUPP;
    680
    681	/* Write macsec request to cfg memory */
    682	dword_cnt = (sizeof(*req) + sizeof(u32) - 1) / sizeof(u32);
    683	err = hw_atl_write_fwcfg_dwords(hw, (void *)req, dword_cnt);
    684	if (err < 0)
    685		return err;
    686
    687	/* Toggle 0x368.CAPS_LO_MACSEC bit */
    688	low_req = aq_hw_read_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR);
    689	low_req ^= HW_ATL_FW2X_CAP_MACSEC;
    690	aq_hw_write_reg(hw, HW_ATL_FW2X_MPI_CONTROL_ADDR, low_req);
    691
    692	/* Wait FW to report back */
    693	err = readx_poll_timeout_atomic(aq_fw2x_state_get, hw, low_status,
    694		low_req != (low_status & BIT(CAPS_LO_MACSEC)), 1U, 10000U);
    695	if (err)
    696		return -EIO;
    697
    698	/* Read status of write operation */
    699	offset = hw->rpc_addr + sizeof(u32);
    700	err = hw_atl_utils_fw_downld_dwords(hw, offset, (u32 *)(void *)response,
    701					    sizeof(*response) / sizeof(u32));
    702
    703	return err;
    704}
    705
    706const struct aq_fw_ops aq_fw_2x_ops = {
    707	.init               = aq_fw2x_init,
    708	.deinit             = aq_fw2x_deinit,
    709	.reset              = NULL,
    710	.renegotiate        = aq_fw2x_renegotiate,
    711	.get_mac_permanent  = aq_fw2x_get_mac_permanent,
    712	.set_link_speed     = aq_fw2x_set_link_speed,
    713	.set_state          = aq_fw2x_set_state,
    714	.update_link_status = aq_fw2x_update_link_status,
    715	.update_stats       = aq_fw2x_update_stats,
    716	.get_mac_temp       = NULL,
    717	.get_phy_temp       = aq_fw2x_get_phy_temp,
    718	.set_power          = aq_fw2x_set_power,
    719	.set_eee_rate       = aq_fw2x_set_eee_rate,
    720	.get_eee_rate       = aq_fw2x_get_eee_rate,
    721	.set_flow_control   = aq_fw2x_set_flow_control,
    722	.get_flow_control   = aq_fw2x_get_flow_control,
    723	.send_fw_request    = aq_fw2x_send_fw_request,
    724	.enable_ptp         = aq_fw3x_enable_ptp,
    725	.led_control        = aq_fw2x_led_control,
    726	.set_phyloopback    = aq_fw2x_set_phyloopback,
    727	.set_downshift      = aq_fw2x_set_downshift,
    728	.set_media_detect   = aq_fw2x_set_media_detect,
    729	.adjust_ptp         = aq_fw3x_adjust_ptp,
    730	.get_link_capabilities = aq_fw2x_get_link_capabilities,
    731	.send_macsec_req    = aq_fw2x_send_macsec_req,
    732};