xref: /dpdk/drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c (revision e77506397fc8005c5129e22e9e2d15d5876790fd)
186d36773SIgor Russkikh // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
286d36773SIgor Russkikh /* Copyright (C) 2014-2017 aQuantia Corporation. */
386d36773SIgor Russkikh 
486d36773SIgor Russkikh /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
586d36773SIgor Russkikh  * Atlantic hardware abstraction layer.
686d36773SIgor Russkikh  */
786d36773SIgor Russkikh 
886d36773SIgor Russkikh #include <rte_ether.h>
9e9924638SPavel Belous #include <pthread.h>
1086d36773SIgor Russkikh #include "../atl_hw_regs.h"
1186d36773SIgor Russkikh 
1286d36773SIgor Russkikh #include "../atl_types.h"
1386d36773SIgor Russkikh #include "hw_atl_utils.h"
1486d36773SIgor Russkikh #include "hw_atl_llh.h"
1586d36773SIgor Russkikh 
1686d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_EFUSE_ADDR	0x364
1786d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_MBOX_ADDR	0x360
1886d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_RPC_ADDR	0x334
1986d36773SIgor Russkikh 
2086d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL_ADDR	0x368
2186d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_CONTROL2_ADDR	0x36C
2286d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_LED_ADDR	0x31c
2386d36773SIgor Russkikh 
2486d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE_ADDR	0x370
2586d36773SIgor Russkikh #define HW_ATL_FW2X_MPI_STATE2_ADDR	0x374
2686d36773SIgor Russkikh 
2786d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
2886d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
2986d36773SIgor Russkikh 
3086d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_EEE_1G_MASK   BIT(CAPS_HI_1000BASET_FD_EEE)
3186d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_EEE_2G5_MASK  BIT(CAPS_HI_2P5GBASET_FD_EEE)
3286d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_EEE_5G_MASK   BIT(CAPS_HI_5GBASET_FD_EEE)
3386d36773SIgor Russkikh #define HW_ATL_FW2X_CAP_EEE_10G_MASK  BIT(CAPS_HI_10GBASET_FD_EEE)
3486d36773SIgor Russkikh 
3586d36773SIgor Russkikh #define HAL_ATLANTIC_WOL_FILTERS_COUNT     8
3686d36773SIgor Russkikh #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL    0x0E
3786d36773SIgor Russkikh 
3886d36773SIgor Russkikh #define HW_ATL_FW_FEATURE_LED 0x03010026
3986d36773SIgor Russkikh 
40*e7750639SAndre Muezerie struct __rte_packed_begin fw2x_msg_wol_pattern {
4186d36773SIgor Russkikh 	u8 mask[16];
4286d36773SIgor Russkikh 	u32 crc;
43*e7750639SAndre Muezerie } __rte_packed_end;
4486d36773SIgor Russkikh 
45*e7750639SAndre Muezerie struct __rte_packed_begin fw2x_msg_wol {
4686d36773SIgor Russkikh 	u32 msg_id;
4786d36773SIgor Russkikh 	u8 hw_addr[6];
4886d36773SIgor Russkikh 	u8 magic_packet_enabled;
4986d36773SIgor Russkikh 	u8 filter_count;
5086d36773SIgor Russkikh 	struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
5186d36773SIgor Russkikh 	u8 link_up_enabled;
5286d36773SIgor Russkikh 	u8 link_down_enabled;
5386d36773SIgor Russkikh 	u16 reserved;
5486d36773SIgor Russkikh 	u32 link_up_timeout;
5586d36773SIgor Russkikh 	u32 link_down_timeout;
56*e7750639SAndre Muezerie } __rte_packed_end;
5786d36773SIgor Russkikh 
5886d36773SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
5986d36773SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self,
6086d36773SIgor Russkikh 			     enum hal_atl_utils_fw_state_e state);
6186d36773SIgor Russkikh 
6286d36773SIgor Russkikh static int aq_fw2x_init(struct aq_hw_s *self)
6386d36773SIgor Russkikh {
6486d36773SIgor Russkikh 	int err = 0;
652f40244bSPavel Belous 	struct hw_aq_atl_utils_mbox mbox;
6686d36773SIgor Russkikh 
6786d36773SIgor Russkikh 	/* check 10 times by 1ms */
6886d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
6986d36773SIgor Russkikh 		       aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
7086d36773SIgor Russkikh 		       1000U, 10U);
7186d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
7286d36773SIgor Russkikh 		       aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
7386d36773SIgor Russkikh 		       1000U, 100U);
742f40244bSPavel Belous 
752f40244bSPavel Belous 	/* Read caps */
762f40244bSPavel Belous 	hw_atl_utils_mpi_read_stats(self, &mbox);
772f40244bSPavel Belous 
782f40244bSPavel Belous 	self->caps_lo = mbox.info.caps_lo;
792f40244bSPavel Belous 
8086d36773SIgor Russkikh 	return err;
8186d36773SIgor Russkikh }
8286d36773SIgor Russkikh 
8386d36773SIgor Russkikh static int aq_fw2x_deinit(struct aq_hw_s *self)
8486d36773SIgor Russkikh {
8586d36773SIgor Russkikh 	int err = aq_fw2x_set_link_speed(self, 0);
8686d36773SIgor Russkikh 
8786d36773SIgor Russkikh 	if (!err)
8886d36773SIgor Russkikh 		err = aq_fw2x_set_state(self, MPI_DEINIT);
8986d36773SIgor Russkikh 
9086d36773SIgor Russkikh 	return err;
9186d36773SIgor Russkikh }
9286d36773SIgor Russkikh 
9386d36773SIgor Russkikh static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
9486d36773SIgor Russkikh {
9586d36773SIgor Russkikh 	enum hw_atl_fw2x_rate rate = 0;
9686d36773SIgor Russkikh 
9786d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_10G)
9886d36773SIgor Russkikh 		rate |= FW2X_RATE_10G;
9986d36773SIgor Russkikh 
10086d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_5G)
10186d36773SIgor Russkikh 		rate |= FW2X_RATE_5G;
10286d36773SIgor Russkikh 
10386d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_5G5R)
10486d36773SIgor Russkikh 		rate |= FW2X_RATE_5G;
10586d36773SIgor Russkikh 
10686d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_2G5)
10786d36773SIgor Russkikh 		rate |= FW2X_RATE_2G5;
10886d36773SIgor Russkikh 
10986d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_1G)
11086d36773SIgor Russkikh 		rate |= FW2X_RATE_1G;
11186d36773SIgor Russkikh 
11286d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_100M)
11386d36773SIgor Russkikh 		rate |= FW2X_RATE_100M;
11486d36773SIgor Russkikh 
11586d36773SIgor Russkikh 	return rate;
11686d36773SIgor Russkikh }
11786d36773SIgor Russkikh 
11886d36773SIgor Russkikh static u32 fw2x_to_eee_mask(u32 speed)
11986d36773SIgor Russkikh {
12086d36773SIgor Russkikh 	u32 rate = 0;
12186d36773SIgor Russkikh 
12286d36773SIgor Russkikh 	if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
12386d36773SIgor Russkikh 		rate |= AQ_NIC_RATE_EEE_10G;
12486d36773SIgor Russkikh 
12586d36773SIgor Russkikh 	if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
12686d36773SIgor Russkikh 		rate |= AQ_NIC_RATE_EEE_5G;
12786d36773SIgor Russkikh 
12886d36773SIgor Russkikh 	if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
12986d36773SIgor Russkikh 		rate |= AQ_NIC_RATE_EEE_2G5;
13086d36773SIgor Russkikh 
13186d36773SIgor Russkikh 	if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
13286d36773SIgor Russkikh 		rate |= AQ_NIC_RATE_EEE_1G;
13386d36773SIgor Russkikh 
13486d36773SIgor Russkikh 	return rate;
13586d36773SIgor Russkikh }
13686d36773SIgor Russkikh 
13786d36773SIgor Russkikh static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
13886d36773SIgor Russkikh {
139f73061d5SPavel Belous 	u32 rate_mask = link_speed_mask_2fw2x_ratemask(speed);
140f73061d5SPavel Belous 	u32 reg_val = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
141f73061d5SPavel Belous 	u32 val = rate_mask | ((BIT(CAPS_LO_SMBUS_READ) |
142f73061d5SPavel Belous 				BIT(CAPS_LO_SMBUS_WRITE) |
143f73061d5SPavel Belous 				BIT(CAPS_LO_MACSEC)) & reg_val);
14486d36773SIgor Russkikh 
14586d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
14686d36773SIgor Russkikh 
14786d36773SIgor Russkikh 	return 0;
14886d36773SIgor Russkikh }
14986d36773SIgor Russkikh 
15086d36773SIgor Russkikh static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
15186d36773SIgor Russkikh {
15286d36773SIgor Russkikh 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
15386d36773SIgor Russkikh 		*mpi_state |= BIT(CAPS_HI_PAUSE);
15486d36773SIgor Russkikh 	else
15586d36773SIgor Russkikh 		*mpi_state &= ~BIT(CAPS_HI_PAUSE);
15686d36773SIgor Russkikh 
15786d36773SIgor Russkikh 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
15886d36773SIgor Russkikh 		*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
15986d36773SIgor Russkikh 	else
16086d36773SIgor Russkikh 		*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
16186d36773SIgor Russkikh }
16286d36773SIgor Russkikh 
16386d36773SIgor Russkikh static int aq_fw2x_set_state(struct aq_hw_s *self,
16486d36773SIgor Russkikh 			     enum hal_atl_utils_fw_state_e state)
16586d36773SIgor Russkikh {
16686d36773SIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
16786d36773SIgor Russkikh 
16886d36773SIgor Russkikh 	switch (state) {
16986d36773SIgor Russkikh 	case MPI_INIT:
17086d36773SIgor Russkikh 		mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
17186d36773SIgor Russkikh 		aq_fw2x_set_mpi_flow_control(self, &mpi_state);
17286d36773SIgor Russkikh 		break;
17386d36773SIgor Russkikh 	case MPI_DEINIT:
17486d36773SIgor Russkikh 		mpi_state |= BIT(CAPS_HI_LINK_DROP);
17586d36773SIgor Russkikh 		break;
17686d36773SIgor Russkikh 	case MPI_RESET:
17786d36773SIgor Russkikh 	case MPI_POWER:
17886d36773SIgor Russkikh 		/* No actions */
17986d36773SIgor Russkikh 		break;
18086d36773SIgor Russkikh 	}
18186d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
18286d36773SIgor Russkikh 	return 0;
18386d36773SIgor Russkikh }
18486d36773SIgor Russkikh 
18586d36773SIgor Russkikh static int aq_fw2x_update_link_status(struct aq_hw_s *self)
18686d36773SIgor Russkikh {
18786d36773SIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
18886d36773SIgor Russkikh 	u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
18986d36773SIgor Russkikh 				FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
19086d36773SIgor Russkikh 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
19186d36773SIgor Russkikh 
19286d36773SIgor Russkikh 	if (speed) {
19386d36773SIgor Russkikh 		if (speed & FW2X_RATE_10G)
19486d36773SIgor Russkikh 			link_status->mbps = 10000;
19586d36773SIgor Russkikh 		else if (speed & FW2X_RATE_5G)
19686d36773SIgor Russkikh 			link_status->mbps = 5000;
19786d36773SIgor Russkikh 		else if (speed & FW2X_RATE_2G5)
19886d36773SIgor Russkikh 			link_status->mbps = 2500;
19986d36773SIgor Russkikh 		else if (speed & FW2X_RATE_1G)
20086d36773SIgor Russkikh 			link_status->mbps = 1000;
20186d36773SIgor Russkikh 		else if (speed & FW2X_RATE_100M)
20286d36773SIgor Russkikh 			link_status->mbps = 100;
20386d36773SIgor Russkikh 		else
20486d36773SIgor Russkikh 			link_status->mbps = 10000;
20586d36773SIgor Russkikh 	} else {
20686d36773SIgor Russkikh 		link_status->mbps = 0;
20786d36773SIgor Russkikh 	}
20886d36773SIgor Russkikh 
20986d36773SIgor Russkikh 	return 0;
21086d36773SIgor Russkikh }
21186d36773SIgor Russkikh 
21286d36773SIgor Russkikh static
21386d36773SIgor Russkikh int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
21486d36773SIgor Russkikh {
21586d36773SIgor Russkikh 	int err = 0;
21686d36773SIgor Russkikh 	u32 h = 0U;
21786d36773SIgor Russkikh 	u32 l = 0U;
21886d36773SIgor Russkikh 	u32 mac_addr[2] = { 0 };
21986d36773SIgor Russkikh 	u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
22086d36773SIgor Russkikh 
221e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
222e9924638SPavel Belous 
22386d36773SIgor Russkikh 	if (efuse_addr != 0) {
22486d36773SIgor Russkikh 		err = hw_atl_utils_fw_downld_dwords(self,
22586d36773SIgor Russkikh 						    efuse_addr + (40U * 4U),
22686d36773SIgor Russkikh 						    mac_addr,
22786d36773SIgor Russkikh 						    ARRAY_SIZE(mac_addr));
22886d36773SIgor Russkikh 		if (err)
229e9924638SPavel Belous 			goto exit;
23086d36773SIgor Russkikh 		mac_addr[0] = rte_constant_bswap32(mac_addr[0]);
23186d36773SIgor Russkikh 		mac_addr[1] = rte_constant_bswap32(mac_addr[1]);
23286d36773SIgor Russkikh 	}
23386d36773SIgor Russkikh 
234538da7a1SOlivier Matz 	rte_ether_addr_copy((struct rte_ether_addr *)mac_addr,
2356d13ea8eSOlivier Matz 			(struct rte_ether_addr *)mac);
23686d36773SIgor Russkikh 
23786d36773SIgor Russkikh 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
23886d36773SIgor Russkikh 		unsigned int rnd = (uint32_t)rte_rand();
23986d36773SIgor Russkikh 
24086d36773SIgor Russkikh 		//get_random_bytes(&rnd, sizeof(unsigned int));
24186d36773SIgor Russkikh 
24286d36773SIgor Russkikh 		l = 0xE3000000U
24386d36773SIgor Russkikh 			| (0xFFFFU & rnd)
24486d36773SIgor Russkikh 			| (0x00 << 16);
24586d36773SIgor Russkikh 		h = 0x8001300EU;
24686d36773SIgor Russkikh 
24786d36773SIgor Russkikh 		mac[5] = (u8)(0xFFU & l);
24886d36773SIgor Russkikh 		l >>= 8;
24986d36773SIgor Russkikh 		mac[4] = (u8)(0xFFU & l);
25086d36773SIgor Russkikh 		l >>= 8;
25186d36773SIgor Russkikh 		mac[3] = (u8)(0xFFU & l);
25286d36773SIgor Russkikh 		l >>= 8;
25386d36773SIgor Russkikh 		mac[2] = (u8)(0xFFU & l);
25486d36773SIgor Russkikh 		mac[1] = (u8)(0xFFU & h);
25586d36773SIgor Russkikh 		h >>= 8;
25686d36773SIgor Russkikh 		mac[0] = (u8)(0xFFU & h);
25786d36773SIgor Russkikh 	}
258e9924638SPavel Belous 
259e9924638SPavel Belous exit:
260e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
261e9924638SPavel Belous 
26286d36773SIgor Russkikh 	return err;
26386d36773SIgor Russkikh }
26486d36773SIgor Russkikh 
26586d36773SIgor Russkikh static int aq_fw2x_update_stats(struct aq_hw_s *self)
26686d36773SIgor Russkikh {
26786d36773SIgor Russkikh 	int err = 0;
26886d36773SIgor Russkikh 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
26986d36773SIgor Russkikh 	u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
27086d36773SIgor Russkikh 
271e9924638SPavel Belous 
272e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
273e9924638SPavel Belous 
27486d36773SIgor Russkikh 	/* Toggle statistics bit for FW to update */
27586d36773SIgor Russkikh 	mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
27686d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
27786d36773SIgor Russkikh 
27886d36773SIgor Russkikh 	/* Wait FW to report back */
27986d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(orig_stats_val !=
28086d36773SIgor Russkikh 		       (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
28186d36773SIgor Russkikh 				       BIT(CAPS_HI_STATISTICS)),
28286d36773SIgor Russkikh 		       1U, 10000U);
28386d36773SIgor Russkikh 	if (err)
284e9924638SPavel Belous 		goto exit;
285e9924638SPavel Belous 
286e9924638SPavel Belous 	err = hw_atl_utils_update_stats(self);
287e9924638SPavel Belous 
288e9924638SPavel Belous exit:
289e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
290e9924638SPavel Belous 
29186d36773SIgor Russkikh 	return err;
29286d36773SIgor Russkikh 
29386d36773SIgor Russkikh }
29486d36773SIgor Russkikh 
29586d36773SIgor Russkikh static int aq_fw2x_get_temp(struct aq_hw_s *self, int *temp)
29686d36773SIgor Russkikh {
29786d36773SIgor Russkikh 	int err = 0;
29886d36773SIgor Russkikh 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
29986d36773SIgor Russkikh 	u32 temp_val = mpi_opts & BIT(CAPS_HI_TEMPERATURE);
30086d36773SIgor Russkikh 	u32 temp_res;
30186d36773SIgor Russkikh 
302e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
303e9924638SPavel Belous 
30486d36773SIgor Russkikh 	/* Toggle statistics bit for FW to 0x36C.18 (CAPS_HI_TEMPERATURE) */
30586d36773SIgor Russkikh 	mpi_opts = mpi_opts ^ BIT(CAPS_HI_TEMPERATURE);
30686d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
30786d36773SIgor Russkikh 
30886d36773SIgor Russkikh 	/* Wait FW to report back */
30986d36773SIgor Russkikh 	AQ_HW_WAIT_FOR(temp_val !=
31086d36773SIgor Russkikh 			(aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
31186d36773SIgor Russkikh 					BIT(CAPS_HI_TEMPERATURE)), 1U, 10000U);
31286d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self,
31386d36773SIgor Russkikh 				self->mbox_addr +
31486d36773SIgor Russkikh 				offsetof(struct hw_aq_atl_utils_mbox, info) +
31586d36773SIgor Russkikh 				offsetof(struct hw_aq_info, phy_temperature),
31686d36773SIgor Russkikh 				&temp_res,
31786d36773SIgor Russkikh 				sizeof(temp_res) / sizeof(u32));
31886d36773SIgor Russkikh 
319e9924638SPavel Belous 
320e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
321e9924638SPavel Belous 
32286d36773SIgor Russkikh 	if (err)
32386d36773SIgor Russkikh 		return err;
32486d36773SIgor Russkikh 
32586d36773SIgor Russkikh 	*temp = temp_res  * 100 / 256;
32686d36773SIgor Russkikh 	return 0;
32786d36773SIgor Russkikh }
32886d36773SIgor Russkikh 
32986d36773SIgor Russkikh static int aq_fw2x_get_cable_len(struct aq_hw_s *self, int *cable_len)
33086d36773SIgor Russkikh {
33186d36773SIgor Russkikh 	int err = 0;
33286d36773SIgor Russkikh 	u32 cable_len_res;
33386d36773SIgor Russkikh 
33486d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self,
33586d36773SIgor Russkikh 				self->mbox_addr +
33686d36773SIgor Russkikh 				offsetof(struct hw_aq_atl_utils_mbox, info) +
33786d36773SIgor Russkikh 				offsetof(struct hw_aq_info, phy_temperature),
33886d36773SIgor Russkikh 				&cable_len_res,
33986d36773SIgor Russkikh 				sizeof(cable_len_res) / sizeof(u32));
34086d36773SIgor Russkikh 
34186d36773SIgor Russkikh 	if (err)
34286d36773SIgor Russkikh 		return err;
34386d36773SIgor Russkikh 
34486d36773SIgor Russkikh 	*cable_len = (cable_len_res >> 16) & 0xFF;
34586d36773SIgor Russkikh 	return 0;
34686d36773SIgor Russkikh }
34786d36773SIgor Russkikh 
34886d36773SIgor Russkikh #ifndef ETH_ALEN
34986d36773SIgor Russkikh #define ETH_ALEN 6
35086d36773SIgor Russkikh #endif
35186d36773SIgor Russkikh 
35286d36773SIgor Russkikh static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
35386d36773SIgor Russkikh {
35486d36773SIgor Russkikh 	int err = 0;
35586d36773SIgor Russkikh 	struct hw_aq_atl_utils_fw_rpc *rpc = NULL;
35686d36773SIgor Russkikh 	struct offload_info *cfg = NULL;
35786d36773SIgor Russkikh 	unsigned int rpc_size = 0U;
35886d36773SIgor Russkikh 	u32 mpi_opts;
35986d36773SIgor Russkikh 
36086d36773SIgor Russkikh 	rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg);
36186d36773SIgor Russkikh 
36286d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_wait(self, &rpc);
36386d36773SIgor Russkikh 	if (err < 0)
36486d36773SIgor Russkikh 		goto err_exit;
36586d36773SIgor Russkikh 
36686d36773SIgor Russkikh 	memset(rpc, 0, rpc_size);
36786d36773SIgor Russkikh 	cfg = (struct offload_info *)(&rpc->msg_id + 1);
36886d36773SIgor Russkikh 
36986d36773SIgor Russkikh 	memcpy(cfg->mac_addr, mac, ETH_ALEN);
37086d36773SIgor Russkikh 	cfg->len = sizeof(*cfg);
37186d36773SIgor Russkikh 
37286d36773SIgor Russkikh 	/* Clear bit 0x36C.23 */
37386d36773SIgor Russkikh 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
37486d36773SIgor Russkikh 	mpi_opts &= ~HW_ATL_FW2X_CAP_SLEEP_PROXY;
37586d36773SIgor Russkikh 
37686d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
37786d36773SIgor Russkikh 
37886d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_call(self, rpc_size);
37986d36773SIgor Russkikh 	if (err < 0)
38086d36773SIgor Russkikh 		goto err_exit;
38186d36773SIgor Russkikh 
38286d36773SIgor Russkikh 	/* Set bit 0x36C.23 */
38386d36773SIgor Russkikh 	mpi_opts |= HW_ATL_FW2X_CAP_SLEEP_PROXY;
38486d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
38586d36773SIgor Russkikh 
38686d36773SIgor Russkikh 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
38786d36773SIgor Russkikh 			HW_ATL_FW2X_CAP_SLEEP_PROXY), 1U, 10000U);
38886d36773SIgor Russkikh err_exit:
38986d36773SIgor Russkikh 	return err;
39086d36773SIgor Russkikh }
39186d36773SIgor Russkikh 
39286d36773SIgor Russkikh static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac)
39386d36773SIgor Russkikh {
39486d36773SIgor Russkikh 	int err = 0;
39586d36773SIgor Russkikh 	struct fw2x_msg_wol *msg = NULL;
39686d36773SIgor Russkikh 	u32 mpi_opts;
39786d36773SIgor Russkikh 
39886d36773SIgor Russkikh 	struct hw_aq_atl_utils_fw_rpc *rpc = NULL;
39986d36773SIgor Russkikh 
40086d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_wait(self, &rpc);
40186d36773SIgor Russkikh 	if (err < 0)
40286d36773SIgor Russkikh 		goto err_exit;
40386d36773SIgor Russkikh 
40486d36773SIgor Russkikh 	msg = (struct fw2x_msg_wol *)rpc;
40586d36773SIgor Russkikh 
40686d36773SIgor Russkikh 	msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL;
40786d36773SIgor Russkikh 	msg->magic_packet_enabled = true;
40886d36773SIgor Russkikh 	memcpy(msg->hw_addr, mac, ETH_ALEN);
40986d36773SIgor Russkikh 
41086d36773SIgor Russkikh 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
41186d36773SIgor Russkikh 	mpi_opts &= ~(HW_ATL_FW2X_CAP_SLEEP_PROXY | HW_ATL_FW2X_CAP_WOL);
41286d36773SIgor Russkikh 
41386d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
41486d36773SIgor Russkikh 
41586d36773SIgor Russkikh 	err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg));
41686d36773SIgor Russkikh 	if (err < 0)
41786d36773SIgor Russkikh 		goto err_exit;
41886d36773SIgor Russkikh 
41986d36773SIgor Russkikh 	/* Set bit 0x36C.24 */
42086d36773SIgor Russkikh 	mpi_opts |= HW_ATL_FW2X_CAP_WOL;
42186d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
42286d36773SIgor Russkikh 
42386d36773SIgor Russkikh 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
42486d36773SIgor Russkikh 			HW_ATL_FW2X_CAP_WOL), 1U, 10000U);
42586d36773SIgor Russkikh err_exit:
42686d36773SIgor Russkikh 	return err;
42786d36773SIgor Russkikh }
42886d36773SIgor Russkikh 
42986d36773SIgor Russkikh static int aq_fw2x_set_power(struct aq_hw_s *self,
43086d36773SIgor Russkikh 			     unsigned int power_state __rte_unused,
43186d36773SIgor Russkikh 			     u8 *mac)
43286d36773SIgor Russkikh {
43386d36773SIgor Russkikh 	int err = 0;
43486d36773SIgor Russkikh 
43586d36773SIgor Russkikh 	if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
43686d36773SIgor Russkikh 		err = aq_fw2x_set_sleep_proxy(self, mac);
43786d36773SIgor Russkikh 		if (err < 0)
43886d36773SIgor Russkikh 			goto err_exit;
43986d36773SIgor Russkikh 		err = aq_fw2x_set_wol_params(self, mac);
44086d36773SIgor Russkikh 		if (err < 0)
44186d36773SIgor Russkikh 			goto err_exit;
44286d36773SIgor Russkikh 	}
44386d36773SIgor Russkikh err_exit:
44486d36773SIgor Russkikh 	return err;
44586d36773SIgor Russkikh }
44686d36773SIgor Russkikh 
44786d36773SIgor Russkikh static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
44886d36773SIgor Russkikh {
44986d36773SIgor Russkikh 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
45086d36773SIgor Russkikh 	mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
45186d36773SIgor Russkikh 		HW_ATL_FW2X_CAP_EEE_2G5_MASK | HW_ATL_FW2X_CAP_EEE_5G_MASK |
45286d36773SIgor Russkikh 		HW_ATL_FW2X_CAP_EEE_10G_MASK);
45386d36773SIgor Russkikh 
45486d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_EEE_10G)
45586d36773SIgor Russkikh 		mpi_opts |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
45686d36773SIgor Russkikh 
45786d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_EEE_5G)
45886d36773SIgor Russkikh 		mpi_opts |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
45986d36773SIgor Russkikh 
46086d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_EEE_2G5)
46186d36773SIgor Russkikh 		mpi_opts |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
46286d36773SIgor Russkikh 
46386d36773SIgor Russkikh 	if (speed & AQ_NIC_RATE_EEE_1G)
46486d36773SIgor Russkikh 		mpi_opts |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
46586d36773SIgor Russkikh 
46686d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
46786d36773SIgor Russkikh 
46886d36773SIgor Russkikh 	return 0;
46986d36773SIgor Russkikh }
47086d36773SIgor Russkikh 
47186d36773SIgor Russkikh static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
47286d36773SIgor Russkikh 					u32 *supported_rates)
47386d36773SIgor Russkikh {
47486d36773SIgor Russkikh 	int err = 0;
47586d36773SIgor Russkikh 	u32 caps_hi;
47686d36773SIgor Russkikh 	u32 mpi_state;
47786d36773SIgor Russkikh 
47886d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self,
47986d36773SIgor Russkikh 				self->mbox_addr +
48086d36773SIgor Russkikh 				offsetof(struct hw_aq_atl_utils_mbox, info) +
48186d36773SIgor Russkikh 				offsetof(struct hw_aq_info, caps_hi),
48286d36773SIgor Russkikh 				&caps_hi,
48386d36773SIgor Russkikh 				sizeof(caps_hi) / sizeof(u32));
48486d36773SIgor Russkikh 
48586d36773SIgor Russkikh 	if (err)
48686d36773SIgor Russkikh 		return err;
48786d36773SIgor Russkikh 
48886d36773SIgor Russkikh 	*supported_rates = fw2x_to_eee_mask(caps_hi);
48986d36773SIgor Russkikh 
49086d36773SIgor Russkikh 	mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
49186d36773SIgor Russkikh 	*rate = fw2x_to_eee_mask(mpi_state);
49286d36773SIgor Russkikh 
49386d36773SIgor Russkikh 	return err;
49486d36773SIgor Russkikh }
49586d36773SIgor Russkikh 
496921eb6b8SPavel Belous static int aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fc)
497921eb6b8SPavel Belous {
498921eb6b8SPavel Belous 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
49986d36773SIgor Russkikh 
500921eb6b8SPavel Belous 	*fc = ((mpi_state & BIT(CAPS_HI_PAUSE)) ? AQ_NIC_FC_RX : 0) |
501921eb6b8SPavel Belous 	      ((mpi_state & BIT(CAPS_HI_ASYMMETRIC_PAUSE)) ? AQ_NIC_FC_TX : 0);
502921eb6b8SPavel Belous 
503921eb6b8SPavel Belous 	return 0;
504921eb6b8SPavel Belous }
50586d36773SIgor Russkikh 
50686d36773SIgor Russkikh static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
50786d36773SIgor Russkikh {
50886d36773SIgor Russkikh 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
50986d36773SIgor Russkikh 
51086d36773SIgor Russkikh 	aq_fw2x_set_mpi_flow_control(self, &mpi_state);
51186d36773SIgor Russkikh 
51286d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
51386d36773SIgor Russkikh 
51486d36773SIgor Russkikh 	return 0;
51586d36773SIgor Russkikh }
51686d36773SIgor Russkikh 
51786d36773SIgor Russkikh static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
51886d36773SIgor Russkikh {
51986d36773SIgor Russkikh 	if (self->fw_ver_actual < HW_ATL_FW_FEATURE_LED)
52086d36773SIgor Russkikh 		return -EOPNOTSUPP;
52186d36773SIgor Russkikh 
52286d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
52386d36773SIgor Russkikh 	return 0;
52486d36773SIgor Russkikh }
52586d36773SIgor Russkikh 
526f73061d5SPavel Belous static int aq_fw2x_get_eeprom(struct aq_hw_s *self, int dev_addr,
527f73061d5SPavel Belous 			      u32 *data, u32 len, u32 offset)
52886d36773SIgor Russkikh {
52905d5b1d6SPavel Belous 	u32 bytes_remains = len % sizeof(u32);
53005d5b1d6SPavel Belous 	u32 num_dwords = len / sizeof(u32);
53105d5b1d6SPavel Belous 	struct smbus_request request;
53286d36773SIgor Russkikh 	u32 result = 0;
53305d5b1d6SPavel Belous 	u32 mpi_opts;
53405d5b1d6SPavel Belous 	int err = 0;
53586d36773SIgor Russkikh 
5363d19de22SPavel Belous 	if ((self->caps_lo & BIT(CAPS_LO_SMBUS_READ)) == 0)
53786d36773SIgor Russkikh 		return -EOPNOTSUPP;
53886d36773SIgor Russkikh 
539e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
540e9924638SPavel Belous 
54105d5b1d6SPavel Belous 	request.msg_id = 0;
542f73061d5SPavel Belous 	request.device_id = dev_addr;
543f73061d5SPavel Belous 	request.address = offset;
54486d36773SIgor Russkikh 	request.length = len;
54586d36773SIgor Russkikh 
54686d36773SIgor Russkikh 	/* Write SMBUS request to cfg memory */
54786d36773SIgor Russkikh 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
54886d36773SIgor Russkikh 				(u32 *)(void *)&request,
549e09a7beeSPavel Belous 				sizeof(request) / sizeof(u32));
55086d36773SIgor Russkikh 
55186d36773SIgor Russkikh 	if (err < 0)
552e9924638SPavel Belous 		goto exit;
55386d36773SIgor Russkikh 
554f73061d5SPavel Belous 	/* Toggle 0x368.CAPS_LO_SMBUS_READ bit */
55586d36773SIgor Russkikh 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
556f73061d5SPavel Belous 	mpi_opts ^= BIT(CAPS_LO_SMBUS_READ);
55786d36773SIgor Russkikh 
55886d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
55986d36773SIgor Russkikh 
56086d36773SIgor Russkikh 	/* Wait until REQUEST_BIT matched in 0x370 */
56186d36773SIgor Russkikh 
56286d36773SIgor Russkikh 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
563f73061d5SPavel Belous 		BIT(CAPS_LO_SMBUS_READ)) == (mpi_opts & BIT(CAPS_LO_SMBUS_READ)),
56486d36773SIgor Russkikh 		10U, 10000U);
56586d36773SIgor Russkikh 
56686d36773SIgor Russkikh 	if (err < 0)
567e9924638SPavel Belous 		goto exit;
56886d36773SIgor Russkikh 
56986d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
57086d36773SIgor Russkikh 			&result,
571e09a7beeSPavel Belous 			sizeof(result) / sizeof(u32));
57286d36773SIgor Russkikh 
57386d36773SIgor Russkikh 	if (err < 0)
574e9924638SPavel Belous 		goto exit;
57586d36773SIgor Russkikh 
576e9924638SPavel Belous 	if (result) {
577e9924638SPavel Belous 		err = -EIO;
578e9924638SPavel Belous 		goto exit;
579e9924638SPavel Belous 	}
580d940a707SPavel Belous 
581d940a707SPavel Belous 	if (num_dwords) {
58286d36773SIgor Russkikh 		err = hw_atl_utils_fw_downld_dwords(self,
58386d36773SIgor Russkikh 			self->rpc_addr + sizeof(u32) * 2,
58486d36773SIgor Russkikh 			data,
585d940a707SPavel Belous 			num_dwords);
58686d36773SIgor Russkikh 
58786d36773SIgor Russkikh 		if (err < 0)
588e9924638SPavel Belous 			goto exit;
58986d36773SIgor Russkikh 	}
59086d36773SIgor Russkikh 
591d940a707SPavel Belous 	if (bytes_remains) {
592d940a707SPavel Belous 		u32 val = 0;
593d940a707SPavel Belous 
594d940a707SPavel Belous 		err = hw_atl_utils_fw_downld_dwords(self,
59505d5b1d6SPavel Belous 			self->rpc_addr + (sizeof(u32) * 2) +
59605d5b1d6SPavel Belous 			(num_dwords * sizeof(u32)),
597d940a707SPavel Belous 			&val,
59805d5b1d6SPavel Belous 			1);
599d940a707SPavel Belous 
600d940a707SPavel Belous 		if (err < 0)
601e9924638SPavel Belous 			goto exit;
602d940a707SPavel Belous 
603d940a707SPavel Belous 		rte_memcpy((u8 *)data + len - bytes_remains,
604d940a707SPavel Belous 				&val, bytes_remains);
605d940a707SPavel Belous 	}
606d940a707SPavel Belous 
607e9924638SPavel Belous exit:
608e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
609e9924638SPavel Belous 
610e9924638SPavel Belous 	return err;
61186d36773SIgor Russkikh }
61286d36773SIgor Russkikh 
61386d36773SIgor Russkikh 
614f73061d5SPavel Belous static int aq_fw2x_set_eeprom(struct aq_hw_s *self, int dev_addr,
61505d5b1d6SPavel Belous 			      u32 *data, u32 len, u32 offset)
61686d36773SIgor Russkikh {
61705d5b1d6SPavel Belous 	struct smbus_request request;
61886d36773SIgor Russkikh 	u32 mpi_opts, result = 0;
61986d36773SIgor Russkikh 	int err = 0;
62086d36773SIgor Russkikh 
6213d19de22SPavel Belous 	if ((self->caps_lo & BIT(CAPS_LO_SMBUS_WRITE)) == 0)
62286d36773SIgor Russkikh 		return -EOPNOTSUPP;
62386d36773SIgor Russkikh 
62405d5b1d6SPavel Belous 	request.msg_id = 0;
625f73061d5SPavel Belous 	request.device_id = dev_addr;
62605d5b1d6SPavel Belous 	request.address = offset;
62786d36773SIgor Russkikh 	request.length = len;
62886d36773SIgor Russkikh 
629e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
630e9924638SPavel Belous 
63186d36773SIgor Russkikh 	/* Write SMBUS request to cfg memory */
63286d36773SIgor Russkikh 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
63386d36773SIgor Russkikh 				(u32 *)(void *)&request,
634e09a7beeSPavel Belous 				sizeof(request) / sizeof(u32));
63586d36773SIgor Russkikh 
63686d36773SIgor Russkikh 	if (err < 0)
637e9924638SPavel Belous 		goto exit;
63886d36773SIgor Russkikh 
63986d36773SIgor Russkikh 	/* Write SMBUS data to cfg memory */
64005d5b1d6SPavel Belous 	u32 num_dwords = len / sizeof(u32);
64105d5b1d6SPavel Belous 	u32 bytes_remains = len % sizeof(u32);
64205d5b1d6SPavel Belous 
64305d5b1d6SPavel Belous 	if (num_dwords) {
64486d36773SIgor Russkikh 		err = hw_atl_utils_fw_upload_dwords(self,
64586d36773SIgor Russkikh 			self->rpc_addr + sizeof(request),
64686d36773SIgor Russkikh 			(u32 *)(void *)data,
64705d5b1d6SPavel Belous 			num_dwords);
64886d36773SIgor Russkikh 
64986d36773SIgor Russkikh 		if (err < 0)
650e9924638SPavel Belous 			goto exit;
65105d5b1d6SPavel Belous 	}
65205d5b1d6SPavel Belous 
65305d5b1d6SPavel Belous 	if (bytes_remains) {
65405d5b1d6SPavel Belous 		u32 val = 0;
65505d5b1d6SPavel Belous 
65605d5b1d6SPavel Belous 		rte_memcpy(&val, (u8 *)data + (sizeof(u32) * num_dwords),
65705d5b1d6SPavel Belous 			   bytes_remains);
65805d5b1d6SPavel Belous 
65905d5b1d6SPavel Belous 		err = hw_atl_utils_fw_upload_dwords(self,
66005d5b1d6SPavel Belous 			self->rpc_addr + sizeof(request) +
66105d5b1d6SPavel Belous 			(num_dwords * sizeof(u32)),
66205d5b1d6SPavel Belous 			&val,
66305d5b1d6SPavel Belous 			1);
66405d5b1d6SPavel Belous 
66505d5b1d6SPavel Belous 		if (err < 0)
666e9924638SPavel Belous 			goto exit;
66705d5b1d6SPavel Belous 	}
66886d36773SIgor Russkikh 
669f73061d5SPavel Belous 	/* Toggle 0x368.CAPS_LO_SMBUS_WRITE bit */
67086d36773SIgor Russkikh 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
671f73061d5SPavel Belous 	mpi_opts ^= BIT(CAPS_LO_SMBUS_WRITE);
67286d36773SIgor Russkikh 
67386d36773SIgor Russkikh 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
67486d36773SIgor Russkikh 
67586d36773SIgor Russkikh 	/* Wait until REQUEST_BIT matched in 0x370 */
67686d36773SIgor Russkikh 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
677f73061d5SPavel Belous 		BIT(CAPS_LO_SMBUS_WRITE)) == (mpi_opts & BIT(CAPS_LO_SMBUS_WRITE)),
67886d36773SIgor Russkikh 		10U, 10000U);
67986d36773SIgor Russkikh 
68086d36773SIgor Russkikh 	if (err < 0)
681e9924638SPavel Belous 		goto exit;
68286d36773SIgor Russkikh 
68386d36773SIgor Russkikh 	/* Read status of write operation */
68486d36773SIgor Russkikh 	err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
68586d36773SIgor Russkikh 				&result,
686e09a7beeSPavel Belous 				sizeof(result) / sizeof(u32));
68786d36773SIgor Russkikh 
68886d36773SIgor Russkikh 	if (err < 0)
689e9924638SPavel Belous 		goto exit;
690e9924638SPavel Belous 
691e9924638SPavel Belous 	if (result) {
692e9924638SPavel Belous 		err = -EIO;
693e9924638SPavel Belous 		goto exit;
694e9924638SPavel Belous 	}
695e9924638SPavel Belous 
696e9924638SPavel Belous exit:
697e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
698e9924638SPavel Belous 
69986d36773SIgor Russkikh 	return err;
70086d36773SIgor Russkikh }
70186d36773SIgor Russkikh 
7022f40244bSPavel Belous static int aq_fw2x_send_macsec_request(struct aq_hw_s *self,
7032f40244bSPavel Belous 				struct macsec_msg_fw_request *req,
7042f40244bSPavel Belous 				struct macsec_msg_fw_response *response)
7052f40244bSPavel Belous {
7062f40244bSPavel Belous 	int err = 0;
7072f40244bSPavel Belous 	u32 mpi_opts = 0;
7082f40244bSPavel Belous 
709e949eaa5SIgor Russkikh 	if (!req || !response)
7102f40244bSPavel Belous 		return 0;
7112f40244bSPavel Belous 
7122f40244bSPavel Belous 	if ((self->caps_lo & BIT(CAPS_LO_MACSEC)) == 0)
7132f40244bSPavel Belous 		return -EOPNOTSUPP;
7142f40244bSPavel Belous 
715e9924638SPavel Belous 	pthread_mutex_lock(&self->mbox_mutex);
716e9924638SPavel Belous 
7172f40244bSPavel Belous 	/* Write macsec request to cfg memory */
7182f40244bSPavel Belous 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
7192f40244bSPavel Belous 		(u32 *)(void *)req,
7202f40244bSPavel Belous 		RTE_ALIGN(sizeof(*req) / sizeof(u32), sizeof(u32)));
7212f40244bSPavel Belous 
7222f40244bSPavel Belous 	if (err < 0)
723e9924638SPavel Belous 		goto exit;
7242f40244bSPavel Belous 
7252f40244bSPavel Belous 	/* Toggle 0x368.CAPS_LO_MACSEC bit */
7262f40244bSPavel Belous 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
7272f40244bSPavel Belous 	mpi_opts ^= BIT(CAPS_LO_MACSEC);
7282f40244bSPavel Belous 
7292f40244bSPavel Belous 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
7302f40244bSPavel Belous 
7312f40244bSPavel Belous 	/* Wait until REQUEST_BIT matched in 0x370 */
7322f40244bSPavel Belous 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
7332f40244bSPavel Belous 		BIT(CAPS_LO_MACSEC)) == (mpi_opts & BIT(CAPS_LO_MACSEC)),
7342f40244bSPavel Belous 		1000U, 10000U);
7352f40244bSPavel Belous 
7362f40244bSPavel Belous 	if (err < 0)
737e9924638SPavel Belous 		goto exit;
7382f40244bSPavel Belous 
7392f40244bSPavel Belous 	/* Read status of write operation */
7402f40244bSPavel Belous 	err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
7412f40244bSPavel Belous 		(u32 *)(void *)response,
7422f40244bSPavel Belous 		RTE_ALIGN(sizeof(*response) / sizeof(u32), sizeof(u32)));
7432f40244bSPavel Belous 
744e9924638SPavel Belous exit:
745e9924638SPavel Belous 	pthread_mutex_unlock(&self->mbox_mutex);
746e9924638SPavel Belous 
7472f40244bSPavel Belous 	return err;
7482f40244bSPavel Belous }
7492f40244bSPavel Belous 
75086d36773SIgor Russkikh const struct aq_fw_ops aq_fw_2x_ops = {
75186d36773SIgor Russkikh 	.init = aq_fw2x_init,
75286d36773SIgor Russkikh 	.deinit = aq_fw2x_deinit,
75386d36773SIgor Russkikh 	.reset = NULL,
75486d36773SIgor Russkikh 	.get_mac_permanent = aq_fw2x_get_mac_permanent,
75586d36773SIgor Russkikh 	.set_link_speed = aq_fw2x_set_link_speed,
75686d36773SIgor Russkikh 	.set_state = aq_fw2x_set_state,
75786d36773SIgor Russkikh 	.update_link_status = aq_fw2x_update_link_status,
75886d36773SIgor Russkikh 	.update_stats = aq_fw2x_update_stats,
75986d36773SIgor Russkikh 	.set_power = aq_fw2x_set_power,
76086d36773SIgor Russkikh 	.get_temp = aq_fw2x_get_temp,
76186d36773SIgor Russkikh 	.get_cable_len = aq_fw2x_get_cable_len,
76286d36773SIgor Russkikh 	.set_eee_rate = aq_fw2x_set_eee_rate,
76386d36773SIgor Russkikh 	.get_eee_rate = aq_fw2x_get_eee_rate,
764921eb6b8SPavel Belous 	.get_flow_control = aq_fw2x_get_flow_control,
76586d36773SIgor Russkikh 	.set_flow_control = aq_fw2x_set_flow_control,
76686d36773SIgor Russkikh 	.led_control = aq_fw2x_led_control,
76786d36773SIgor Russkikh 	.get_eeprom = aq_fw2x_get_eeprom,
76886d36773SIgor Russkikh 	.set_eeprom = aq_fw2x_set_eeprom,
7692f40244bSPavel Belous 	.send_macsec_req = aq_fw2x_send_macsec_request,
77086d36773SIgor Russkikh };
771