1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  */
9 
10 /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
11  * Atlantic hardware abstraction layer.
12  */
13 
14 #include "../aq_hw.h"
15 #include "../aq_hw_utils.h"
16 #include "../aq_pci_func.h"
17 #include "../aq_ring.h"
18 #include "../aq_vec.h"
19 #include "hw_atl_utils.h"
20 #include "hw_atl_llh.h"
21 
22 #define HW_ATL_FW2X_MPI_EFUSE_ADDR	0x364
23 #define HW_ATL_FW2X_MPI_MBOX_ADDR	0x360
24 
25 #define HW_ATL_FW2X_MPI_CONTROL_ADDR	0x368
26 #define HW_ATL_FW2X_MPI_CONTROL2_ADDR	0x36C
27 
28 #define HW_ATL_FW2X_MPI_STATE_ADDR	0x370
29 #define HW_ATL_FW2X_MPI_STATE2_ADDR	0x374
30 
31 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
32 static int aq_fw2x_set_state(struct aq_hw_s *self,
33 			     enum hal_atl_utils_fw_state_e state);
34 
aq_fw2x_init(struct aq_hw_s * self)35 static int aq_fw2x_init(struct aq_hw_s *self)
36 {
37 	int err = 0;
38 
39 	/* check 10 times by 1ms */
40 	AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
41 			aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
42 		       1000U, 10U);
43 	return err;
44 }
45 
aq_fw2x_deinit(struct aq_hw_s * self)46 static int aq_fw2x_deinit(struct aq_hw_s *self)
47 {
48 	int err = aq_fw2x_set_link_speed(self, 0);
49 
50 	if (!err)
51 		err = aq_fw2x_set_state(self, MPI_DEINIT);
52 
53 	return err;
54 }
55 
link_speed_mask_2fw2x_ratemask(u32 speed)56 static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
57 {
58 	enum hw_atl_fw2x_rate rate = 0;
59 
60 	if (speed & AQ_NIC_RATE_10G)
61 		rate |= FW2X_RATE_10G;
62 
63 	if (speed & AQ_NIC_RATE_5G)
64 		rate |= FW2X_RATE_5G;
65 
66 	if (speed & AQ_NIC_RATE_5GSR)
67 		rate |= FW2X_RATE_5G;
68 
69 	if (speed & AQ_NIC_RATE_2GS)
70 		rate |= FW2X_RATE_2G5;
71 
72 	if (speed & AQ_NIC_RATE_1G)
73 		rate |= FW2X_RATE_1G;
74 
75 	if (speed & AQ_NIC_RATE_100M)
76 		rate |= FW2X_RATE_100M;
77 
78 	return rate;
79 }
80 
aq_fw2x_set_link_speed(struct aq_hw_s * self,u32 speed)81 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
82 {
83 	u32 val = link_speed_mask_2fw2x_ratemask(speed);
84 
85 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
86 
87 	return 0;
88 }
89 
aq_fw2x_set_mpi_flow_control(struct aq_hw_s * self,u32 * mpi_state)90 static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
91 {
92 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
93 		*mpi_state |= BIT(CAPS_HI_PAUSE);
94 	else
95 		*mpi_state &= ~BIT(CAPS_HI_PAUSE);
96 
97 	if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
98 		*mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
99 	else
100 		*mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
101 }
102 
aq_fw2x_set_state(struct aq_hw_s * self,enum hal_atl_utils_fw_state_e state)103 static int aq_fw2x_set_state(struct aq_hw_s *self,
104 			     enum hal_atl_utils_fw_state_e state)
105 {
106 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
107 
108 	switch (state) {
109 	case MPI_INIT:
110 		mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
111 		aq_fw2x_set_mpi_flow_control(self, &mpi_state);
112 		break;
113 	case MPI_DEINIT:
114 		mpi_state |= BIT(CAPS_HI_LINK_DROP);
115 		break;
116 	case MPI_RESET:
117 	case MPI_POWER:
118 		/* No actions */
119 		break;
120 	}
121 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
122 	return 0;
123 }
124 
aq_fw2x_update_link_status(struct aq_hw_s * self)125 static int aq_fw2x_update_link_status(struct aq_hw_s *self)
126 {
127 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
128 	u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
129 				FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
130 	struct aq_hw_link_status_s *link_status = &self->aq_link_status;
131 
132 	if (speed) {
133 		if (speed & FW2X_RATE_10G)
134 			link_status->mbps = 10000;
135 		else if (speed & FW2X_RATE_5G)
136 			link_status->mbps = 5000;
137 		else if (speed & FW2X_RATE_2G5)
138 			link_status->mbps = 2500;
139 		else if (speed & FW2X_RATE_1G)
140 			link_status->mbps = 1000;
141 		else if (speed & FW2X_RATE_100M)
142 			link_status->mbps = 100;
143 		else
144 			link_status->mbps = 10000;
145 	} else {
146 		link_status->mbps = 0;
147 	}
148 
149 	return 0;
150 }
151 
aq_fw2x_get_mac_permanent(struct aq_hw_s * self,u8 * mac)152 static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
153 {
154 	int err = 0;
155 	u32 h = 0U;
156 	u32 l = 0U;
157 	u32 mac_addr[2] = { 0 };
158 	u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
159 
160 	if (efuse_addr != 0) {
161 		err = hw_atl_utils_fw_downld_dwords(self,
162 						    efuse_addr + (40U * 4U),
163 						    mac_addr,
164 						    ARRAY_SIZE(mac_addr));
165 		if (err)
166 			return err;
167 		mac_addr[0] = __swab32(mac_addr[0]);
168 		mac_addr[1] = __swab32(mac_addr[1]);
169 	}
170 
171 	ether_addr_copy(mac, (u8 *)mac_addr);
172 
173 	if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
174 		unsigned int rnd = 0;
175 
176 		get_random_bytes(&rnd, sizeof(unsigned int));
177 
178 		l = 0xE3000000U
179 			| (0xFFFFU & rnd)
180 			| (0x00 << 16);
181 		h = 0x8001300EU;
182 
183 		mac[5] = (u8)(0xFFU & l);
184 		l >>= 8;
185 		mac[4] = (u8)(0xFFU & l);
186 		l >>= 8;
187 		mac[3] = (u8)(0xFFU & l);
188 		l >>= 8;
189 		mac[2] = (u8)(0xFFU & l);
190 		mac[1] = (u8)(0xFFU & h);
191 		h >>= 8;
192 		mac[0] = (u8)(0xFFU & h);
193 	}
194 	return err;
195 }
196 
aq_fw2x_update_stats(struct aq_hw_s * self)197 static int aq_fw2x_update_stats(struct aq_hw_s *self)
198 {
199 	int err = 0;
200 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
201 	u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
202 
203 	/* Toggle statistics bit for FW to update */
204 	mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
205 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
206 
207 	/* Wait FW to report back */
208 	AQ_HW_WAIT_FOR(orig_stats_val !=
209 		       (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
210 				       BIT(CAPS_HI_STATISTICS)),
211 		       1U, 10000U);
212 	if (err)
213 		return err;
214 
215 	return hw_atl_utils_update_stats(self);
216 }
217 
aq_fw2x_renegotiate(struct aq_hw_s * self)218 static int aq_fw2x_renegotiate(struct aq_hw_s *self)
219 {
220 	u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
221 
222 	mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
223 
224 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
225 
226 	return 0;
227 }
228 
aq_fw2x_set_flow_control(struct aq_hw_s * self)229 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
230 {
231 	u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
232 
233 	aq_fw2x_set_mpi_flow_control(self, &mpi_state);
234 
235 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
236 
237 	return 0;
238 }
239 
240 const struct aq_fw_ops aq_fw_2x_ops = {
241 	.init = aq_fw2x_init,
242 	.deinit = aq_fw2x_deinit,
243 	.reset = NULL,
244 	.renegotiate = aq_fw2x_renegotiate,
245 	.get_mac_permanent = aq_fw2x_get_mac_permanent,
246 	.set_link_speed = aq_fw2x_set_link_speed,
247 	.set_state = aq_fw2x_set_state,
248 	.update_link_status = aq_fw2x_update_link_status,
249 	.update_stats = aq_fw2x_update_stats,
250 	.set_flow_control   = aq_fw2x_set_flow_control,
251 };
252