.. | .. |
---|
1 | | -/* |
---|
2 | | - * aQuantia Corporation Network Driver |
---|
3 | | - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
| 2 | +/* Atlantic Network Driver |
---|
4 | 3 | * |
---|
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. |
---|
| 4 | + * Copyright (C) 2014-2019 aQuantia Corporation |
---|
| 5 | + * Copyright (C) 2019-2020 Marvell International Ltd. |
---|
8 | 6 | */ |
---|
9 | 7 | |
---|
10 | 8 | /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for |
---|
.. | .. |
---|
16 | 14 | #include "../aq_pci_func.h" |
---|
17 | 15 | #include "../aq_ring.h" |
---|
18 | 16 | #include "../aq_vec.h" |
---|
| 17 | +#include "../aq_nic.h" |
---|
19 | 18 | #include "hw_atl_utils.h" |
---|
20 | 19 | #include "hw_atl_llh.h" |
---|
21 | 20 | |
---|
22 | | -#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 |
---|
23 | | -#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 |
---|
24 | | -#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 |
---|
| 21 | +#define HW_ATL_FW2X_MPI_LED_ADDR 0x31c |
---|
| 22 | +#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 |
---|
25 | 23 | |
---|
26 | | -#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 |
---|
27 | | -#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C |
---|
| 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 |
---|
28 | 30 | |
---|
29 | | -#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 |
---|
30 | | -#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 |
---|
| 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 | + |
---|
| 67 | +struct __packed fw2x_msg_wol_pattern { |
---|
| 68 | + u8 mask[16]; |
---|
| 69 | + u32 crc; |
---|
| 70 | +}; |
---|
| 71 | + |
---|
| 72 | +struct __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 | +}; |
---|
31 | 84 | |
---|
32 | 85 | static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed); |
---|
33 | 86 | static int aq_fw2x_set_state(struct aq_hw_s *self, |
---|
34 | 87 | enum hal_atl_utils_fw_state_e state); |
---|
| 88 | + |
---|
| 89 | +static u32 aq_fw2x_mbox_get(struct aq_hw_s *self); |
---|
| 90 | +static u32 aq_fw2x_rpc_get(struct aq_hw_s *self); |
---|
| 91 | +static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr); |
---|
| 92 | +static u32 aq_fw2x_state_get(struct aq_hw_s *self); |
---|
| 93 | +static u32 aq_fw2x_state2_get(struct aq_hw_s *self); |
---|
35 | 94 | |
---|
36 | 95 | static int aq_fw2x_init(struct aq_hw_s *self) |
---|
37 | 96 | { |
---|
38 | 97 | int err = 0; |
---|
39 | 98 | |
---|
40 | 99 | /* check 10 times by 1ms */ |
---|
41 | | - AQ_HW_WAIT_FOR(0U != (self->mbox_addr = |
---|
42 | | - aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)), |
---|
43 | | - 1000U, 10U); |
---|
44 | | - AQ_HW_WAIT_FOR(0U != (self->rpc_addr = |
---|
45 | | - aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)), |
---|
46 | | - 1000U, 100U); |
---|
| 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); |
---|
47 | 111 | |
---|
48 | 112 | return err; |
---|
49 | 113 | } |
---|
.. | .. |
---|
68 | 132 | if (speed & AQ_NIC_RATE_5G) |
---|
69 | 133 | rate |= FW2X_RATE_5G; |
---|
70 | 134 | |
---|
71 | | - if (speed & AQ_NIC_RATE_5GSR) |
---|
72 | | - rate |= FW2X_RATE_5G; |
---|
73 | | - |
---|
74 | | - if (speed & AQ_NIC_RATE_2GS) |
---|
| 135 | + if (speed & AQ_NIC_RATE_2G5) |
---|
75 | 136 | rate |= FW2X_RATE_2G5; |
---|
76 | 137 | |
---|
77 | 138 | if (speed & AQ_NIC_RATE_1G) |
---|
.. | .. |
---|
79 | 140 | |
---|
80 | 141 | if (speed & AQ_NIC_RATE_100M) |
---|
81 | 142 | rate |= FW2X_RATE_100M; |
---|
| 143 | + |
---|
| 144 | + return rate; |
---|
| 145 | +} |
---|
| 146 | + |
---|
| 147 | +static 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 | + |
---|
| 163 | +static 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; |
---|
82 | 175 | |
---|
83 | 176 | return rate; |
---|
84 | 177 | } |
---|
.. | .. |
---|
92 | 185 | return 0; |
---|
93 | 186 | } |
---|
94 | 187 | |
---|
95 | | -static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state) |
---|
| 188 | +static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self, |
---|
| 189 | + u32 *mpi_state, u32 fc) |
---|
96 | 190 | { |
---|
97 | | - if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) |
---|
98 | | - *mpi_state |= BIT(CAPS_HI_PAUSE); |
---|
99 | | - else |
---|
100 | | - *mpi_state &= ~BIT(CAPS_HI_PAUSE); |
---|
| 191 | + *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE | |
---|
| 192 | + HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE); |
---|
101 | 193 | |
---|
102 | | - if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX) |
---|
103 | | - *mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE); |
---|
104 | | - else |
---|
105 | | - *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); |
---|
| 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 | + |
---|
| 210 | +static 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); |
---|
106 | 219 | } |
---|
107 | 220 | |
---|
108 | 221 | static int aq_fw2x_set_state(struct aq_hw_s *self, |
---|
109 | 222 | enum hal_atl_utils_fw_state_e state) |
---|
110 | 223 | { |
---|
111 | 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; |
---|
112 | 226 | |
---|
113 | 227 | switch (state) { |
---|
114 | 228 | case MPI_INIT: |
---|
115 | 229 | mpi_state &= ~BIT(CAPS_HI_LINK_DROP); |
---|
116 | | - aq_fw2x_set_mpi_flow_control(self, &mpi_state); |
---|
| 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); |
---|
117 | 233 | break; |
---|
118 | 234 | case MPI_DEINIT: |
---|
119 | 235 | mpi_state |= BIT(CAPS_HI_LINK_DROP); |
---|
.. | .. |
---|
124 | 240 | break; |
---|
125 | 241 | } |
---|
126 | 242 | aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); |
---|
| 243 | + |
---|
127 | 244 | return 0; |
---|
128 | 245 | } |
---|
129 | 246 | |
---|
130 | 247 | static int aq_fw2x_update_link_status(struct aq_hw_s *self) |
---|
131 | 248 | { |
---|
132 | | - u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); |
---|
133 | | - u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | |
---|
134 | | - FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G); |
---|
135 | 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); |
---|
136 | 257 | |
---|
137 | 258 | if (speed) { |
---|
138 | 259 | if (speed & FW2X_RATE_10G) |
---|
.. | .. |
---|
150 | 271 | } else { |
---|
151 | 272 | link_status->mbps = 0; |
---|
152 | 273 | } |
---|
| 274 | + link_status->full_duplex = true; |
---|
153 | 275 | |
---|
154 | 276 | return 0; |
---|
155 | 277 | } |
---|
156 | 278 | |
---|
157 | 279 | static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) |
---|
158 | 280 | { |
---|
159 | | - int err = 0; |
---|
160 | | - u32 h = 0U; |
---|
161 | | - u32 l = 0U; |
---|
162 | | - u32 mac_addr[2] = { 0 }; |
---|
163 | 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; |
---|
164 | 284 | |
---|
165 | 285 | if (efuse_addr != 0) { |
---|
166 | 286 | err = hw_atl_utils_fw_downld_dwords(self, |
---|
.. | .. |
---|
175 | 295 | |
---|
176 | 296 | ether_addr_copy(mac, (u8 *)mac_addr); |
---|
177 | 297 | |
---|
178 | | - if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) { |
---|
179 | | - unsigned int rnd = 0; |
---|
180 | | - |
---|
181 | | - get_random_bytes(&rnd, sizeof(unsigned int)); |
---|
182 | | - |
---|
183 | | - l = 0xE3000000U |
---|
184 | | - | (0xFFFFU & rnd) |
---|
185 | | - | (0x00 << 16); |
---|
186 | | - h = 0x8001300EU; |
---|
187 | | - |
---|
188 | | - mac[5] = (u8)(0xFFU & l); |
---|
189 | | - l >>= 8; |
---|
190 | | - mac[4] = (u8)(0xFFU & l); |
---|
191 | | - l >>= 8; |
---|
192 | | - mac[3] = (u8)(0xFFU & l); |
---|
193 | | - l >>= 8; |
---|
194 | | - mac[2] = (u8)(0xFFU & l); |
---|
195 | | - mac[1] = (u8)(0xFFU & h); |
---|
196 | | - h >>= 8; |
---|
197 | | - mac[0] = (u8)(0xFFU & h); |
---|
198 | | - } |
---|
199 | 298 | return err; |
---|
200 | 299 | } |
---|
201 | 300 | |
---|
202 | 301 | static int aq_fw2x_update_stats(struct aq_hw_s *self) |
---|
203 | 302 | { |
---|
204 | | - int err = 0; |
---|
205 | 303 | u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); |
---|
206 | 304 | u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS); |
---|
| 305 | + u32 stats_val; |
---|
| 306 | + int err = 0; |
---|
207 | 307 | |
---|
208 | 308 | /* Toggle statistics bit for FW to update */ |
---|
209 | 309 | mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS); |
---|
210 | 310 | aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); |
---|
211 | 311 | |
---|
212 | 312 | /* Wait FW to report back */ |
---|
213 | | - AQ_HW_WAIT_FOR(orig_stats_val != |
---|
214 | | - (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) & |
---|
215 | | - BIT(CAPS_HI_STATISTICS)), |
---|
216 | | - 1U, 10000U); |
---|
| 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); |
---|
217 | 318 | if (err) |
---|
218 | 319 | return err; |
---|
219 | 320 | |
---|
220 | 321 | return hw_atl_utils_update_stats(self); |
---|
| 322 | +} |
---|
| 323 | + |
---|
| 324 | +static 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 | + |
---|
| 358 | +static int aq_fw2x_set_wol(struct aq_hw_s *self, 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 | + |
---|
| 399 | +err_exit: |
---|
| 400 | + return err; |
---|
| 401 | +} |
---|
| 402 | + |
---|
| 403 | +static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, |
---|
| 404 | + 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 | + |
---|
| 414 | +static 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 | + |
---|
| 443 | +err_exit: |
---|
| 444 | + return err; |
---|
| 445 | +} |
---|
| 446 | + |
---|
| 447 | +static 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 | + |
---|
| 461 | +static 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 | + |
---|
| 469 | +static 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 | + |
---|
| 479 | +static 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 | + |
---|
| 490 | +static 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; |
---|
221 | 512 | } |
---|
222 | 513 | |
---|
223 | 514 | static int aq_fw2x_renegotiate(struct aq_hw_s *self) |
---|
.. | .. |
---|
235 | 526 | { |
---|
236 | 527 | u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); |
---|
237 | 528 | |
---|
238 | | - aq_fw2x_set_mpi_flow_control(self, &mpi_state); |
---|
| 529 | + aq_fw2x_upd_flow_control_bits(self, &mpi_state, |
---|
| 530 | + self->aq_nic_cfg->fc.req); |
---|
239 | 531 | |
---|
240 | 532 | aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); |
---|
241 | 533 | |
---|
242 | 534 | return 0; |
---|
243 | 535 | } |
---|
244 | 536 | |
---|
| 537 | +static 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 | + |
---|
| 551 | +static 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 | + |
---|
| 579 | +static 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 | + |
---|
| 584 | +static 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 | + |
---|
| 589 | +static 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 | + |
---|
| 602 | +static 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 | + |
---|
| 607 | +static 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 | + |
---|
| 612 | +static 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 | + |
---|
| 633 | +static 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 | + |
---|
| 647 | +static 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 | + |
---|
| 664 | +static 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 | + |
---|
245 | 706 | const struct aq_fw_ops aq_fw_2x_ops = { |
---|
246 | | - .init = aq_fw2x_init, |
---|
247 | | - .deinit = aq_fw2x_deinit, |
---|
248 | | - .reset = NULL, |
---|
249 | | - .renegotiate = aq_fw2x_renegotiate, |
---|
250 | | - .get_mac_permanent = aq_fw2x_get_mac_permanent, |
---|
251 | | - .set_link_speed = aq_fw2x_set_link_speed, |
---|
252 | | - .set_state = aq_fw2x_set_state, |
---|
| 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, |
---|
253 | 714 | .update_link_status = aq_fw2x_update_link_status, |
---|
254 | | - .update_stats = aq_fw2x_update_stats, |
---|
| 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, |
---|
255 | 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, |
---|
256 | 732 | }; |
---|