Skip to content

Commit c8c82eb

Browse files
caildavem330
authored andcommitted
net: aquantia: Introduce global AQC hardware reset sequence
The detailed reset sequence ensures all HW components are in aligned state before NIC startup. It also supports cards with signed firmware (RBL) and checks if their FW is valid. Signed-off-by: Igor Russkikh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a57d392 commit c8c82eb

File tree

3 files changed

+183
-29
lines changed

3 files changed

+183
-29
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_hw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ struct aq_stats_s {
100100

101101
struct aq_hw_s {
102102
atomic_t flags;
103+
u8 rbl_enabled:1;
103104
struct aq_nic_cfg_s *aq_nic_cfg;
104105
const struct aq_fw_ops *aq_fw_ops;
105106
void __iomem *mmio;

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,32 +87,14 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self)
8787
{
8888
int err = 0;
8989

90-
hw_atl_glb_glb_reg_res_dis_set(self, 1U);
91-
hw_atl_pci_pci_reg_res_dis_set(self, 0U);
92-
hw_atl_rx_rx_reg_res_dis_set(self, 0U);
93-
hw_atl_tx_tx_reg_res_dis_set(self, 0U);
94-
95-
HW_ATL_FLUSH();
96-
hw_atl_glb_soft_res_set(self, 1);
97-
98-
/* check 10 times by 1ms */
99-
AQ_HW_WAIT_FOR(hw_atl_glb_soft_res_get(self) == 0, 1000U, 10U);
100-
if (err < 0)
101-
goto err_exit;
102-
103-
hw_atl_itr_irq_reg_res_dis_set(self, 0U);
104-
hw_atl_itr_res_irq_set(self, 1U);
105-
106-
/* check 10 times by 1ms */
107-
AQ_HW_WAIT_FOR(hw_atl_itr_res_irq_get(self) == 0, 1000U, 10U);
108-
if (err < 0)
109-
goto err_exit;
90+
err = hw_atl_utils_soft_reset(self);
91+
if (err)
92+
return err;
11093

11194
self->aq_fw_ops->set_state(self, MPI_RESET);
11295

11396
err = aq_hw_err_from_flags(self);
11497

115-
err_exit:
11698
return err;
11799
}
118100

drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c

Lines changed: 179 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,39 +31,210 @@
3131
#define HW_ATL_MPI_SPEED_MSK 0xFFFF0000U
3232
#define HW_ATL_MPI_SPEED_SHIFT 16U
3333

34+
#define HW_ATL_MPI_DAISY_CHAIN_STATUS 0x704
35+
#define HW_ATL_MPI_BOOT_EXIT_CODE 0x388
36+
37+
#define HW_ATL_MAC_PHY_CONTROL 0x4000
38+
#define HW_ATL_MAC_PHY_MPI_RESET_BIT 0x1D
39+
3440
#define HW_ATL_FW_VER_1X 0x01050006U
3541
#define HW_ATL_FW_VER_2X 0x02000000U
3642
#define HW_ATL_FW_VER_3X 0x03000000U
3743

44+
#define FORCE_FLASHLESS 0
45+
3846
static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
3947

4048
int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
4149
{
4250
int err = 0;
4351

52+
err = hw_atl_utils_soft_reset(self);
53+
if (err)
54+
return err;
55+
4456
hw_atl_utils_hw_chip_features_init(self,
4557
&self->chip_features);
4658

4759
hw_atl_utils_get_fw_version(self, &self->fw_ver_actual);
4860

49-
if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual) == 0)
61+
if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
62+
self->fw_ver_actual) == 0) {
5063
*fw_ops = &aq_fw_1x_ops;
51-
else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
52-
self->fw_ver_actual) == 0)
64+
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X,
65+
self->fw_ver_actual) == 0) {
5366
*fw_ops = &aq_fw_2x_ops;
54-
else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
55-
self->fw_ver_actual) == 0)
67+
} else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X,
68+
self->fw_ver_actual) == 0) {
5669
*fw_ops = &aq_fw_2x_ops;
57-
else {
70+
} else {
5871
aq_pr_err("Bad FW version detected: %x\n",
59-
self->fw_ver_actual);
72+
self->fw_ver_actual);
6073
return -EOPNOTSUPP;
6174
}
6275
self->aq_fw_ops = *fw_ops;
6376
err = self->aq_fw_ops->init(self);
6477
return err;
6578
}
6679

80+
static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
81+
{
82+
int k = 0;
83+
u32 gsr;
84+
85+
aq_hw_write_reg(self, 0x404, 0x40e1);
86+
AQ_HW_SLEEP(50);
87+
88+
/* Cleanup SPI */
89+
aq_hw_write_reg(self, 0x534, 0xA0);
90+
aq_hw_write_reg(self, 0x100, 0x9F);
91+
aq_hw_write_reg(self, 0x100, 0x809F);
92+
93+
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
94+
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
95+
96+
/* Kickstart MAC */
97+
aq_hw_write_reg(self, 0x404, 0x80e0);
98+
aq_hw_write_reg(self, 0x32a8, 0x0);
99+
aq_hw_write_reg(self, 0x520, 0x1);
100+
AQ_HW_SLEEP(10);
101+
aq_hw_write_reg(self, 0x404, 0x180e0);
102+
103+
for (k = 0; k < 1000; k++) {
104+
u32 flb_status = aq_hw_read_reg(self,
105+
HW_ATL_MPI_DAISY_CHAIN_STATUS);
106+
107+
flb_status = flb_status & 0x10;
108+
if (flb_status)
109+
break;
110+
AQ_HW_SLEEP(10);
111+
}
112+
if (k == 1000) {
113+
aq_pr_err("MAC kickstart failed\n");
114+
return -EIO;
115+
}
116+
117+
/* FW reset */
118+
aq_hw_write_reg(self, 0x404, 0x80e0);
119+
AQ_HW_SLEEP(50);
120+
aq_hw_write_reg(self, 0x3a0, 0x1);
121+
122+
/* Kickstart PHY - skipped */
123+
124+
/* Global software reset*/
125+
hw_atl_rx_rx_reg_res_dis_set(self, 0U);
126+
hw_atl_tx_tx_reg_res_dis_set(self, 0U);
127+
aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
128+
BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
129+
HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
130+
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
131+
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
132+
133+
for (k = 0; k < 1000; k++) {
134+
u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
135+
136+
if (fw_state)
137+
break;
138+
AQ_HW_SLEEP(10);
139+
}
140+
if (k == 1000) {
141+
aq_pr_err("FW kickstart failed\n");
142+
return -EIO;
143+
}
144+
145+
return 0;
146+
}
147+
148+
static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
149+
{
150+
u32 gsr, rbl_status;
151+
int k;
152+
153+
aq_hw_write_reg(self, 0x404, 0x40e1);
154+
aq_hw_write_reg(self, 0x3a0, 0x1);
155+
aq_hw_write_reg(self, 0x32a8, 0x0);
156+
157+
/* Alter RBL status */
158+
aq_hw_write_reg(self, 0x388, 0xDEAD);
159+
160+
/* Global software reset*/
161+
hw_atl_rx_rx_reg_res_dis_set(self, 0U);
162+
hw_atl_tx_tx_reg_res_dis_set(self, 0U);
163+
aq_hw_write_reg_bit(self, HW_ATL_MAC_PHY_CONTROL,
164+
BIT(HW_ATL_MAC_PHY_MPI_RESET_BIT),
165+
HW_ATL_MAC_PHY_MPI_RESET_BIT, 0x0);
166+
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
167+
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR,
168+
(gsr & 0xFFFFBFFF) | 0x8000);
169+
170+
if (FORCE_FLASHLESS)
171+
aq_hw_write_reg(self, 0x534, 0x0);
172+
173+
aq_hw_write_reg(self, 0x404, 0x40e0);
174+
175+
/* Wait for RBL boot */
176+
for (k = 0; k < 1000; k++) {
177+
rbl_status = aq_hw_read_reg(self, 0x388) & 0xFFFF;
178+
if (rbl_status && rbl_status != 0xDEAD)
179+
break;
180+
AQ_HW_SLEEP(10);
181+
}
182+
if (!rbl_status || rbl_status == 0xDEAD) {
183+
aq_pr_err("RBL Restart failed");
184+
return -EIO;
185+
}
186+
187+
/* Restore NVR */
188+
if (FORCE_FLASHLESS)
189+
aq_hw_write_reg(self, 0x534, 0xA0);
190+
191+
if (rbl_status == 0xF1A7) {
192+
aq_pr_err("No FW detected. Dynamic FW load not implemented\n");
193+
return -ENOTSUPP;
194+
}
195+
196+
for (k = 0; k < 1000; k++) {
197+
u32 fw_state = aq_hw_read_reg(self, HW_ATL_MPI_FW_VERSION);
198+
199+
if (fw_state)
200+
break;
201+
AQ_HW_SLEEP(10);
202+
}
203+
if (k == 1000) {
204+
aq_pr_err("FW kickstart failed\n");
205+
return -EIO;
206+
}
207+
208+
return 0;
209+
}
210+
211+
int hw_atl_utils_soft_reset(struct aq_hw_s *self)
212+
{
213+
int k;
214+
u32 boot_exit_code = 0;
215+
216+
for (k = 0; k < 1000; ++k) {
217+
u32 flb_status = aq_hw_read_reg(self,
218+
HW_ATL_MPI_DAISY_CHAIN_STATUS);
219+
boot_exit_code = aq_hw_read_reg(self,
220+
HW_ATL_MPI_BOOT_EXIT_CODE);
221+
if (flb_status != 0x06000000 || boot_exit_code != 0)
222+
break;
223+
}
224+
225+
if (k == 1000) {
226+
aq_pr_err("Neither RBL nor FLB firmware started\n");
227+
return -EOPNOTSUPP;
228+
}
229+
230+
self->rbl_enabled = (boot_exit_code != 0);
231+
232+
if (self->rbl_enabled)
233+
return hw_atl_utils_soft_reset_rbl(self);
234+
else
235+
return hw_atl_utils_soft_reset_flb(self);
236+
}
237+
67238
int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
68239
u32 *p, u32 cnt)
69240
{
@@ -598,7 +769,7 @@ int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
598769

599770
for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
600771
regs_buff[i] = aq_hw_read_reg(self,
601-
hw_atl_utils_hw_mac_regs[i]);
772+
hw_atl_utils_hw_mac_regs[i]);
602773
return 0;
603774
}
604775

0 commit comments

Comments
 (0)