1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * QLogic qlcnic NIC Driver |
4 | * Copyright (c) 2009-2013 QLogic Corporation |
5 | */ |
6 | |
7 | #include <linux/slab.h> |
8 | #include <net/ip.h> |
9 | #include <linux/bitops.h> |
10 | |
11 | #include "qlcnic.h" |
12 | #include "qlcnic_hdr.h" |
13 | |
14 | #define MASK(n) ((1ULL<<(n))-1) |
15 | #define OCM_WIN_P3P(addr) (addr & 0xffc0000) |
16 | |
17 | #define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) |
18 | |
19 | #define CRB_BLK(off) ((off >> 20) & 0x3f) |
20 | #define CRB_SUBBLK(off) ((off >> 16) & 0xf) |
21 | #define CRB_WINDOW_2M (0x130060) |
22 | #define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000)) |
23 | #define CRB_INDIRECT_2M (0x1e0000UL) |
24 | |
25 | struct qlcnic_ms_reg_ctrl { |
26 | u32 ocm_window; |
27 | u32 control; |
28 | u32 hi; |
29 | u32 low; |
30 | u32 rd[4]; |
31 | u32 wd[4]; |
32 | u64 off; |
33 | }; |
34 | |
35 | #ifndef readq |
36 | static inline u64 readq(void __iomem *addr) |
37 | { |
38 | return readl(addr) | (((u64) readl(addr + 4)) << 32LL); |
39 | } |
40 | #endif |
41 | |
42 | #ifndef writeq |
43 | static inline void writeq(u64 val, void __iomem *addr) |
44 | { |
45 | writel(((u32) (val)), (addr)); |
46 | writel(((u32) (val >> 32)), (addr + 4)); |
47 | } |
48 | #endif |
49 | |
50 | static struct crb_128M_2M_block_map |
51 | crb_128M_2M_map[64] __cacheline_aligned_in_smp = { |
52 | {{{0, 0, 0, 0} } }, /* 0: PCI */ |
53 | {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ |
54 | {1, 0x0110000, 0x0120000, 0x130000}, |
55 | {1, 0x0120000, 0x0122000, 0x124000}, |
56 | {1, 0x0130000, 0x0132000, 0x126000}, |
57 | {1, 0x0140000, 0x0142000, 0x128000}, |
58 | {1, 0x0150000, 0x0152000, 0x12a000}, |
59 | {1, 0x0160000, 0x0170000, 0x110000}, |
60 | {1, 0x0170000, 0x0172000, 0x12e000}, |
61 | {0, 0x0000000, 0x0000000, 0x000000}, |
62 | {0, 0x0000000, 0x0000000, 0x000000}, |
63 | {0, 0x0000000, 0x0000000, 0x000000}, |
64 | {0, 0x0000000, 0x0000000, 0x000000}, |
65 | {0, 0x0000000, 0x0000000, 0x000000}, |
66 | {0, 0x0000000, 0x0000000, 0x000000}, |
67 | {1, 0x01e0000, 0x01e0800, 0x122000}, |
68 | {0, 0x0000000, 0x0000000, 0x000000} } }, |
69 | {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */ |
70 | {{{0, 0, 0, 0} } }, /* 3: */ |
71 | {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */ |
72 | {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */ |
73 | {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */ |
74 | {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */ |
75 | {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */ |
76 | {0, 0x0000000, 0x0000000, 0x000000}, |
77 | {0, 0x0000000, 0x0000000, 0x000000}, |
78 | {0, 0x0000000, 0x0000000, 0x000000}, |
79 | {0, 0x0000000, 0x0000000, 0x000000}, |
80 | {0, 0x0000000, 0x0000000, 0x000000}, |
81 | {0, 0x0000000, 0x0000000, 0x000000}, |
82 | {0, 0x0000000, 0x0000000, 0x000000}, |
83 | {0, 0x0000000, 0x0000000, 0x000000}, |
84 | {0, 0x0000000, 0x0000000, 0x000000}, |
85 | {0, 0x0000000, 0x0000000, 0x000000}, |
86 | {0, 0x0000000, 0x0000000, 0x000000}, |
87 | {0, 0x0000000, 0x0000000, 0x000000}, |
88 | {0, 0x0000000, 0x0000000, 0x000000}, |
89 | {0, 0x0000000, 0x0000000, 0x000000}, |
90 | {1, 0x08f0000, 0x08f2000, 0x172000} } }, |
91 | {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/ |
92 | {0, 0x0000000, 0x0000000, 0x000000}, |
93 | {0, 0x0000000, 0x0000000, 0x000000}, |
94 | {0, 0x0000000, 0x0000000, 0x000000}, |
95 | {0, 0x0000000, 0x0000000, 0x000000}, |
96 | {0, 0x0000000, 0x0000000, 0x000000}, |
97 | {0, 0x0000000, 0x0000000, 0x000000}, |
98 | {0, 0x0000000, 0x0000000, 0x000000}, |
99 | {0, 0x0000000, 0x0000000, 0x000000}, |
100 | {0, 0x0000000, 0x0000000, 0x000000}, |
101 | {0, 0x0000000, 0x0000000, 0x000000}, |
102 | {0, 0x0000000, 0x0000000, 0x000000}, |
103 | {0, 0x0000000, 0x0000000, 0x000000}, |
104 | {0, 0x0000000, 0x0000000, 0x000000}, |
105 | {0, 0x0000000, 0x0000000, 0x000000}, |
106 | {1, 0x09f0000, 0x09f2000, 0x176000} } }, |
107 | {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/ |
108 | {0, 0x0000000, 0x0000000, 0x000000}, |
109 | {0, 0x0000000, 0x0000000, 0x000000}, |
110 | {0, 0x0000000, 0x0000000, 0x000000}, |
111 | {0, 0x0000000, 0x0000000, 0x000000}, |
112 | {0, 0x0000000, 0x0000000, 0x000000}, |
113 | {0, 0x0000000, 0x0000000, 0x000000}, |
114 | {0, 0x0000000, 0x0000000, 0x000000}, |
115 | {0, 0x0000000, 0x0000000, 0x000000}, |
116 | {0, 0x0000000, 0x0000000, 0x000000}, |
117 | {0, 0x0000000, 0x0000000, 0x000000}, |
118 | {0, 0x0000000, 0x0000000, 0x000000}, |
119 | {0, 0x0000000, 0x0000000, 0x000000}, |
120 | {0, 0x0000000, 0x0000000, 0x000000}, |
121 | {0, 0x0000000, 0x0000000, 0x000000}, |
122 | {1, 0x0af0000, 0x0af2000, 0x17a000} } }, |
123 | {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/ |
124 | {0, 0x0000000, 0x0000000, 0x000000}, |
125 | {0, 0x0000000, 0x0000000, 0x000000}, |
126 | {0, 0x0000000, 0x0000000, 0x000000}, |
127 | {0, 0x0000000, 0x0000000, 0x000000}, |
128 | {0, 0x0000000, 0x0000000, 0x000000}, |
129 | {0, 0x0000000, 0x0000000, 0x000000}, |
130 | {0, 0x0000000, 0x0000000, 0x000000}, |
131 | {0, 0x0000000, 0x0000000, 0x000000}, |
132 | {0, 0x0000000, 0x0000000, 0x000000}, |
133 | {0, 0x0000000, 0x0000000, 0x000000}, |
134 | {0, 0x0000000, 0x0000000, 0x000000}, |
135 | {0, 0x0000000, 0x0000000, 0x000000}, |
136 | {0, 0x0000000, 0x0000000, 0x000000}, |
137 | {0, 0x0000000, 0x0000000, 0x000000}, |
138 | {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, |
139 | {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */ |
140 | {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */ |
141 | {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */ |
142 | {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */ |
143 | {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */ |
144 | {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */ |
145 | {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */ |
146 | {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */ |
147 | {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */ |
148 | {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */ |
149 | {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */ |
150 | {{{0, 0, 0, 0} } }, /* 23: */ |
151 | {{{0, 0, 0, 0} } }, /* 24: */ |
152 | {{{0, 0, 0, 0} } }, /* 25: */ |
153 | {{{0, 0, 0, 0} } }, /* 26: */ |
154 | {{{0, 0, 0, 0} } }, /* 27: */ |
155 | {{{0, 0, 0, 0} } }, /* 28: */ |
156 | {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */ |
157 | {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */ |
158 | {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */ |
159 | {{{0} } }, /* 32: PCI */ |
160 | {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */ |
161 | {1, 0x2110000, 0x2120000, 0x130000}, |
162 | {1, 0x2120000, 0x2122000, 0x124000}, |
163 | {1, 0x2130000, 0x2132000, 0x126000}, |
164 | {1, 0x2140000, 0x2142000, 0x128000}, |
165 | {1, 0x2150000, 0x2152000, 0x12a000}, |
166 | {1, 0x2160000, 0x2170000, 0x110000}, |
167 | {1, 0x2170000, 0x2172000, 0x12e000}, |
168 | {0, 0x0000000, 0x0000000, 0x000000}, |
169 | {0, 0x0000000, 0x0000000, 0x000000}, |
170 | {0, 0x0000000, 0x0000000, 0x000000}, |
171 | {0, 0x0000000, 0x0000000, 0x000000}, |
172 | {0, 0x0000000, 0x0000000, 0x000000}, |
173 | {0, 0x0000000, 0x0000000, 0x000000}, |
174 | {0, 0x0000000, 0x0000000, 0x000000}, |
175 | {0, 0x0000000, 0x0000000, 0x000000} } }, |
176 | {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */ |
177 | {{{0} } }, /* 35: */ |
178 | {{{0} } }, /* 36: */ |
179 | {{{0} } }, /* 37: */ |
180 | {{{0} } }, /* 38: */ |
181 | {{{0} } }, /* 39: */ |
182 | {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */ |
183 | {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */ |
184 | {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */ |
185 | {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */ |
186 | {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */ |
187 | {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */ |
188 | {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */ |
189 | {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */ |
190 | {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */ |
191 | {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */ |
192 | {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */ |
193 | {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */ |
194 | {{{0} } }, /* 52: */ |
195 | {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */ |
196 | {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */ |
197 | {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */ |
198 | {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */ |
199 | {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */ |
200 | {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */ |
201 | {{{0} } }, /* 59: I2C0 */ |
202 | {{{0} } }, /* 60: I2C1 */ |
203 | {{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */ |
204 | {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */ |
205 | {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */ |
206 | }; |
207 | |
208 | /* |
209 | * top 12 bits of crb internal address (hub, agent) |
210 | */ |
211 | static const unsigned crb_hub_agt[64] = { |
212 | 0, |
213 | QLCNIC_HW_CRB_HUB_AGT_ADR_PS, |
214 | QLCNIC_HW_CRB_HUB_AGT_ADR_MN, |
215 | QLCNIC_HW_CRB_HUB_AGT_ADR_MS, |
216 | 0, |
217 | QLCNIC_HW_CRB_HUB_AGT_ADR_SRE, |
218 | QLCNIC_HW_CRB_HUB_AGT_ADR_NIU, |
219 | QLCNIC_HW_CRB_HUB_AGT_ADR_QMN, |
220 | QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0, |
221 | QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1, |
222 | QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2, |
223 | QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3, |
224 | QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, |
225 | QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, |
226 | QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, |
227 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4, |
228 | QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, |
229 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0, |
230 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1, |
231 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2, |
232 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3, |
233 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGND, |
234 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI, |
235 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0, |
236 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1, |
237 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2, |
238 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3, |
239 | 0, |
240 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI, |
241 | QLCNIC_HW_CRB_HUB_AGT_ADR_SN, |
242 | 0, |
243 | QLCNIC_HW_CRB_HUB_AGT_ADR_EG, |
244 | 0, |
245 | QLCNIC_HW_CRB_HUB_AGT_ADR_PS, |
246 | QLCNIC_HW_CRB_HUB_AGT_ADR_CAM, |
247 | 0, |
248 | 0, |
249 | 0, |
250 | 0, |
251 | 0, |
252 | QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR, |
253 | 0, |
254 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1, |
255 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2, |
256 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3, |
257 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4, |
258 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5, |
259 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6, |
260 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7, |
261 | QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA, |
262 | QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q, |
263 | QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB, |
264 | 0, |
265 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0, |
266 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8, |
267 | QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9, |
268 | QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0, |
269 | 0, |
270 | QLCNIC_HW_CRB_HUB_AGT_ADR_SMB, |
271 | QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0, |
272 | QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1, |
273 | 0, |
274 | QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC, |
275 | 0, |
276 | }; |
277 | |
278 | /* PCI Windowing for DDR regions. */ |
279 | |
280 | #define QLCNIC_PCIE_SEM_TIMEOUT 10000 |
281 | |
282 | static void qlcnic_read_window_reg(u32 addr, void __iomem *bar0, u32 *data) |
283 | { |
284 | u32 dest; |
285 | void __iomem *val; |
286 | |
287 | dest = addr & 0xFFFF0000; |
288 | val = bar0 + QLCNIC_FW_DUMP_REG1; |
289 | writel(val: dest, addr: val); |
290 | readl(addr: val); |
291 | val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr); |
292 | *data = readl(addr: val); |
293 | } |
294 | |
295 | static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data) |
296 | { |
297 | u32 dest; |
298 | void __iomem *val; |
299 | |
300 | dest = addr & 0xFFFF0000; |
301 | val = bar0 + QLCNIC_FW_DUMP_REG1; |
302 | writel(val: dest, addr: val); |
303 | readl(addr: val); |
304 | val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr); |
305 | writel(val: data, addr: val); |
306 | readl(addr: val); |
307 | } |
308 | |
309 | int |
310 | qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) |
311 | { |
312 | int timeout = 0, err = 0, done = 0; |
313 | |
314 | while (!done) { |
315 | done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), |
316 | &err); |
317 | if (done == 1) |
318 | break; |
319 | if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { |
320 | if (id_reg) { |
321 | done = QLCRD32(adapter, id_reg, &err); |
322 | if (done != -1) |
323 | dev_err(&adapter->pdev->dev, |
324 | "Failed to acquire sem=%d lock held by=%d\n" , |
325 | sem, done); |
326 | else |
327 | dev_err(&adapter->pdev->dev, |
328 | "Failed to acquire sem=%d lock" , |
329 | sem); |
330 | } else { |
331 | dev_err(&adapter->pdev->dev, |
332 | "Failed to acquire sem=%d lock" , sem); |
333 | } |
334 | return -EIO; |
335 | } |
336 | udelay(1200); |
337 | } |
338 | |
339 | if (id_reg) |
340 | QLCWR32(adapter, id_reg, adapter->portnum); |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | void |
346 | qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem) |
347 | { |
348 | int err = 0; |
349 | |
350 | QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err); |
351 | } |
352 | |
353 | int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr) |
354 | { |
355 | int err = 0; |
356 | u32 data; |
357 | |
358 | if (qlcnic_82xx_check(adapter)) |
359 | qlcnic_read_window_reg(addr, bar0: adapter->ahw->pci_base0, data: &data); |
360 | else { |
361 | data = QLCRD32(adapter, addr, &err); |
362 | if (err == -EIO) |
363 | return err; |
364 | } |
365 | return data; |
366 | } |
367 | |
368 | int qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data) |
369 | { |
370 | int ret = 0; |
371 | |
372 | if (qlcnic_82xx_check(adapter)) |
373 | qlcnic_write_window_reg(addr, bar0: adapter->ahw->pci_base0, data); |
374 | else |
375 | ret = qlcnic_83xx_wrt_reg_indirect(adapter, addr, data); |
376 | |
377 | return ret; |
378 | } |
379 | |
380 | static int |
381 | qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, |
382 | struct cmd_desc_type0 *cmd_desc_arr, int nr_desc) |
383 | { |
384 | u32 i, producer; |
385 | struct qlcnic_cmd_buffer *pbuf; |
386 | struct cmd_desc_type0 *cmd_desc; |
387 | struct qlcnic_host_tx_ring *tx_ring; |
388 | |
389 | i = 0; |
390 | |
391 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
392 | return -EIO; |
393 | |
394 | tx_ring = &adapter->tx_ring[0]; |
395 | __netif_tx_lock_bh(txq: tx_ring->txq); |
396 | |
397 | producer = tx_ring->producer; |
398 | |
399 | if (nr_desc >= qlcnic_tx_avail(tx_ring)) { |
400 | netif_tx_stop_queue(dev_queue: tx_ring->txq); |
401 | smp_mb(); |
402 | if (qlcnic_tx_avail(tx_ring) > nr_desc) { |
403 | if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) |
404 | netif_tx_wake_queue(dev_queue: tx_ring->txq); |
405 | } else { |
406 | adapter->stats.xmit_off++; |
407 | __netif_tx_unlock_bh(txq: tx_ring->txq); |
408 | return -EBUSY; |
409 | } |
410 | } |
411 | |
412 | do { |
413 | cmd_desc = &cmd_desc_arr[i]; |
414 | |
415 | pbuf = &tx_ring->cmd_buf_arr[producer]; |
416 | pbuf->skb = NULL; |
417 | pbuf->frag_count = 0; |
418 | |
419 | memcpy(&tx_ring->desc_head[producer], |
420 | cmd_desc, sizeof(struct cmd_desc_type0)); |
421 | |
422 | producer = get_next_index(producer, tx_ring->num_desc); |
423 | i++; |
424 | |
425 | } while (i != nr_desc); |
426 | |
427 | tx_ring->producer = producer; |
428 | |
429 | qlcnic_update_cmd_producer(tx_ring); |
430 | |
431 | __netif_tx_unlock_bh(txq: tx_ring->txq); |
432 | |
433 | return 0; |
434 | } |
435 | |
436 | int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, |
437 | u16 vlan_id, u8 op) |
438 | { |
439 | struct qlcnic_nic_req req; |
440 | struct qlcnic_mac_req *mac_req; |
441 | struct qlcnic_vlan_req *vlan_req; |
442 | u64 word; |
443 | |
444 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
445 | req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23); |
446 | |
447 | word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16); |
448 | req.req_hdr = cpu_to_le64(word); |
449 | |
450 | mac_req = (struct qlcnic_mac_req *)&req.words[0]; |
451 | mac_req->op = op; |
452 | memcpy(mac_req->mac_addr, addr, ETH_ALEN); |
453 | |
454 | vlan_req = (struct qlcnic_vlan_req *)&req.words[1]; |
455 | vlan_req->vlan_id = cpu_to_le16(vlan_id); |
456 | |
457 | return qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
458 | } |
459 | |
460 | int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) |
461 | { |
462 | struct qlcnic_mac_vlan_list *cur; |
463 | int err = -EINVAL; |
464 | |
465 | /* Delete MAC from the existing list */ |
466 | list_for_each_entry(cur, &adapter->mac_list, list) { |
467 | if (ether_addr_equal(addr1: addr, addr2: cur->mac_addr)) { |
468 | err = qlcnic_sre_macaddr_change(adapter, addr: cur->mac_addr, |
469 | id: 0, QLCNIC_MAC_DEL); |
470 | if (err) |
471 | return err; |
472 | list_del(entry: &cur->list); |
473 | kfree(objp: cur); |
474 | return err; |
475 | } |
476 | } |
477 | return err; |
478 | } |
479 | |
480 | int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan, |
481 | enum qlcnic_mac_type mac_type) |
482 | { |
483 | struct qlcnic_mac_vlan_list *cur; |
484 | |
485 | /* look up if already exists */ |
486 | list_for_each_entry(cur, &adapter->mac_list, list) { |
487 | if (ether_addr_equal(addr1: addr, addr2: cur->mac_addr) && |
488 | cur->vlan_id == vlan) |
489 | return 0; |
490 | } |
491 | |
492 | cur = kzalloc(size: sizeof(*cur), GFP_ATOMIC); |
493 | if (cur == NULL) |
494 | return -ENOMEM; |
495 | |
496 | memcpy(cur->mac_addr, addr, ETH_ALEN); |
497 | |
498 | if (qlcnic_sre_macaddr_change(adapter, |
499 | addr: cur->mac_addr, id: vlan, QLCNIC_MAC_ADD)) { |
500 | kfree(objp: cur); |
501 | return -EIO; |
502 | } |
503 | |
504 | cur->vlan_id = vlan; |
505 | cur->mac_type = mac_type; |
506 | |
507 | list_add_tail(new: &cur->list, head: &adapter->mac_list); |
508 | return 0; |
509 | } |
510 | |
511 | void qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter) |
512 | { |
513 | struct qlcnic_mac_vlan_list *cur; |
514 | struct list_head *head, *tmp; |
515 | |
516 | list_for_each_safe(head, tmp, &adapter->mac_list) { |
517 | cur = list_entry(head, struct qlcnic_mac_vlan_list, list); |
518 | if (cur->mac_type != QLCNIC_MULTICAST_MAC) |
519 | continue; |
520 | |
521 | qlcnic_sre_macaddr_change(adapter, addr: cur->mac_addr, |
522 | id: cur->vlan_id, QLCNIC_MAC_DEL); |
523 | list_del(entry: &cur->list); |
524 | kfree(objp: cur); |
525 | } |
526 | } |
527 | |
528 | static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) |
529 | { |
530 | struct qlcnic_adapter *adapter = netdev_priv(dev: netdev); |
531 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
532 | struct netdev_hw_addr *ha; |
533 | static const u8 bcast_addr[ETH_ALEN] = { |
534 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff |
535 | }; |
536 | u32 mode = VPORT_MISS_MODE_DROP; |
537 | |
538 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
539 | return; |
540 | |
541 | qlcnic_nic_add_mac(adapter, addr: adapter->mac_addr, vlan, |
542 | mac_type: QLCNIC_UNICAST_MAC); |
543 | qlcnic_nic_add_mac(adapter, addr: bcast_addr, vlan, mac_type: QLCNIC_BROADCAST_MAC); |
544 | |
545 | if (netdev->flags & IFF_PROMISC) { |
546 | if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) |
547 | mode = VPORT_MISS_MODE_ACCEPT_ALL; |
548 | } else if ((netdev->flags & IFF_ALLMULTI) || |
549 | (netdev_mc_count(netdev) > ahw->max_mc_count)) { |
550 | mode = VPORT_MISS_MODE_ACCEPT_MULTI; |
551 | } else if (!netdev_mc_empty(netdev)) { |
552 | qlcnic_flush_mcast_mac(adapter); |
553 | netdev_for_each_mc_addr(ha, netdev) |
554 | qlcnic_nic_add_mac(adapter, addr: ha->addr, vlan, |
555 | mac_type: QLCNIC_MULTICAST_MAC); |
556 | } |
557 | |
558 | /* configure unicast MAC address, if there is not sufficient space |
559 | * to store all the unicast addresses then enable promiscuous mode |
560 | */ |
561 | if (netdev_uc_count(netdev) > ahw->max_uc_count) { |
562 | mode = VPORT_MISS_MODE_ACCEPT_ALL; |
563 | } else if (!netdev_uc_empty(netdev)) { |
564 | netdev_for_each_uc_addr(ha, netdev) |
565 | qlcnic_nic_add_mac(adapter, addr: ha->addr, vlan, |
566 | mac_type: QLCNIC_UNICAST_MAC); |
567 | } |
568 | |
569 | if (mode == VPORT_MISS_MODE_ACCEPT_ALL && |
570 | !adapter->fdb_mac_learn) { |
571 | qlcnic_alloc_lb_filters_mem(adapter); |
572 | adapter->drv_mac_learn = 1; |
573 | if (adapter->flags & QLCNIC_ESWITCH_ENABLED) |
574 | adapter->rx_mac_learn = true; |
575 | } else { |
576 | adapter->drv_mac_learn = 0; |
577 | adapter->rx_mac_learn = false; |
578 | } |
579 | |
580 | qlcnic_nic_set_promisc(adapter, mode); |
581 | } |
582 | |
583 | void qlcnic_set_multi(struct net_device *netdev) |
584 | { |
585 | struct qlcnic_adapter *adapter = netdev_priv(dev: netdev); |
586 | |
587 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
588 | return; |
589 | |
590 | if (qlcnic_sriov_vf_check(adapter)) |
591 | qlcnic_sriov_vf_set_multi(netdev); |
592 | else |
593 | __qlcnic_set_multi(netdev, vlan: 0); |
594 | } |
595 | |
596 | int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) |
597 | { |
598 | struct qlcnic_nic_req req; |
599 | u64 word; |
600 | |
601 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
602 | |
603 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
604 | |
605 | word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE | |
606 | ((u64)adapter->portnum << 16); |
607 | req.req_hdr = cpu_to_le64(word); |
608 | |
609 | req.words[0] = cpu_to_le64(mode); |
610 | |
611 | return qlcnic_send_cmd_descs(adapter, |
612 | cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
613 | } |
614 | |
615 | void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter) |
616 | { |
617 | struct list_head *head = &adapter->mac_list; |
618 | struct qlcnic_mac_vlan_list *cur; |
619 | |
620 | while (!list_empty(head)) { |
621 | cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list); |
622 | qlcnic_sre_macaddr_change(adapter, |
623 | addr: cur->mac_addr, id: 0, QLCNIC_MAC_DEL); |
624 | list_del(entry: &cur->list); |
625 | kfree(objp: cur); |
626 | } |
627 | } |
628 | |
629 | void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter) |
630 | { |
631 | struct qlcnic_filter *tmp_fil; |
632 | struct hlist_node *n; |
633 | struct hlist_head *head; |
634 | int i; |
635 | unsigned long expires; |
636 | u8 cmd; |
637 | |
638 | for (i = 0; i < adapter->fhash.fbucket_size; i++) { |
639 | head = &(adapter->fhash.fhead[i]); |
640 | hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { |
641 | cmd = tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL : |
642 | QLCNIC_MAC_DEL; |
643 | expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ; |
644 | if (time_before(expires, jiffies)) { |
645 | qlcnic_sre_macaddr_change(adapter, |
646 | addr: tmp_fil->faddr, |
647 | id: tmp_fil->vlan_id, |
648 | cmd); |
649 | spin_lock_bh(lock: &adapter->mac_learn_lock); |
650 | adapter->fhash.fnum--; |
651 | hlist_del(n: &tmp_fil->fnode); |
652 | spin_unlock_bh(lock: &adapter->mac_learn_lock); |
653 | kfree(objp: tmp_fil); |
654 | } |
655 | } |
656 | } |
657 | for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) { |
658 | head = &(adapter->rx_fhash.fhead[i]); |
659 | |
660 | hlist_for_each_entry_safe(tmp_fil, n, head, fnode) |
661 | { |
662 | expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ; |
663 | if (time_before(expires, jiffies)) { |
664 | spin_lock_bh(lock: &adapter->rx_mac_learn_lock); |
665 | adapter->rx_fhash.fnum--; |
666 | hlist_del(n: &tmp_fil->fnode); |
667 | spin_unlock_bh(lock: &adapter->rx_mac_learn_lock); |
668 | kfree(objp: tmp_fil); |
669 | } |
670 | } |
671 | } |
672 | } |
673 | |
674 | void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) |
675 | { |
676 | struct qlcnic_filter *tmp_fil; |
677 | struct hlist_node *n; |
678 | struct hlist_head *head; |
679 | int i; |
680 | u8 cmd; |
681 | |
682 | for (i = 0; i < adapter->fhash.fbucket_size; i++) { |
683 | head = &(adapter->fhash.fhead[i]); |
684 | hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { |
685 | cmd = tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL : |
686 | QLCNIC_MAC_DEL; |
687 | qlcnic_sre_macaddr_change(adapter, |
688 | addr: tmp_fil->faddr, |
689 | id: tmp_fil->vlan_id, |
690 | cmd); |
691 | spin_lock_bh(lock: &adapter->mac_learn_lock); |
692 | adapter->fhash.fnum--; |
693 | hlist_del(n: &tmp_fil->fnode); |
694 | spin_unlock_bh(lock: &adapter->mac_learn_lock); |
695 | kfree(objp: tmp_fil); |
696 | } |
697 | } |
698 | } |
699 | |
700 | static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag) |
701 | { |
702 | struct qlcnic_nic_req req; |
703 | int rv; |
704 | |
705 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
706 | |
707 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
708 | req.req_hdr = cpu_to_le64(QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK | |
709 | ((u64) adapter->portnum << 16) | ((u64) 0x1 << 32)); |
710 | |
711 | req.words[0] = cpu_to_le64(flag); |
712 | |
713 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
714 | if (rv != 0) |
715 | dev_err(&adapter->pdev->dev, "%sting loopback mode failed\n" , |
716 | flag ? "Set" : "Reset" ); |
717 | return rv; |
718 | } |
719 | |
720 | int qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode) |
721 | { |
722 | if (qlcnic_set_fw_loopback(adapter, flag: mode)) |
723 | return -EIO; |
724 | |
725 | if (qlcnic_nic_set_promisc(adapter, |
726 | VPORT_MISS_MODE_ACCEPT_ALL)) { |
727 | qlcnic_set_fw_loopback(adapter, flag: 0); |
728 | return -EIO; |
729 | } |
730 | |
731 | msleep(msecs: 1000); |
732 | return 0; |
733 | } |
734 | |
735 | int qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) |
736 | { |
737 | struct net_device *netdev = adapter->netdev; |
738 | |
739 | mode = VPORT_MISS_MODE_DROP; |
740 | qlcnic_set_fw_loopback(adapter, flag: 0); |
741 | |
742 | if (netdev->flags & IFF_PROMISC) |
743 | mode = VPORT_MISS_MODE_ACCEPT_ALL; |
744 | else if (netdev->flags & IFF_ALLMULTI) |
745 | mode = VPORT_MISS_MODE_ACCEPT_MULTI; |
746 | |
747 | qlcnic_nic_set_promisc(adapter, mode); |
748 | msleep(msecs: 1000); |
749 | return 0; |
750 | } |
751 | |
752 | int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter) |
753 | { |
754 | u8 mac[ETH_ALEN]; |
755 | int ret; |
756 | |
757 | ret = qlcnic_get_mac_address(adapter, mac, |
758 | function: adapter->ahw->physical_port); |
759 | if (ret) |
760 | return ret; |
761 | |
762 | memcpy(adapter->ahw->phys_port_id, mac, ETH_ALEN); |
763 | adapter->flags |= QLCNIC_HAS_PHYS_PORT_ID; |
764 | |
765 | return 0; |
766 | } |
767 | |
768 | int qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter) |
769 | { |
770 | struct qlcnic_nic_req req; |
771 | int rv; |
772 | |
773 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
774 | |
775 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
776 | |
777 | req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE | |
778 | ((u64) adapter->portnum << 16)); |
779 | |
780 | req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32); |
781 | req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets | |
782 | ((u64) adapter->ahw->coal.rx_time_us) << 16); |
783 | req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out | |
784 | ((u64) adapter->ahw->coal.type) << 32 | |
785 | ((u64) adapter->ahw->coal.sts_ring_mask) << 40); |
786 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
787 | if (rv != 0) |
788 | dev_err(&adapter->netdev->dev, |
789 | "Could not send interrupt coalescing parameters\n" ); |
790 | |
791 | return rv; |
792 | } |
793 | |
794 | /* Send the interrupt coalescing parameter set by ethtool to the card. */ |
795 | int qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter, |
796 | struct ethtool_coalesce *ethcoal) |
797 | { |
798 | struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; |
799 | int rv; |
800 | |
801 | coal->flag = QLCNIC_INTR_DEFAULT; |
802 | coal->rx_time_us = ethcoal->rx_coalesce_usecs; |
803 | coal->rx_packets = ethcoal->rx_max_coalesced_frames; |
804 | |
805 | rv = qlcnic_82xx_set_rx_coalesce(adapter); |
806 | |
807 | if (rv) |
808 | netdev_err(dev: adapter->netdev, |
809 | format: "Failed to set Rx coalescing parameters\n" ); |
810 | |
811 | return rv; |
812 | } |
813 | |
814 | #define QLCNIC_ENABLE_IPV4_LRO BIT_0 |
815 | #define QLCNIC_ENABLE_IPV6_LRO (BIT_1 | BIT_9) |
816 | |
817 | int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable) |
818 | { |
819 | struct qlcnic_nic_req req; |
820 | u64 word; |
821 | int rv; |
822 | |
823 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
824 | return 0; |
825 | |
826 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
827 | |
828 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
829 | |
830 | word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16); |
831 | req.req_hdr = cpu_to_le64(word); |
832 | |
833 | word = 0; |
834 | if (enable) { |
835 | word = QLCNIC_ENABLE_IPV4_LRO; |
836 | if (adapter->ahw->extra_capability[0] & |
837 | QLCNIC_FW_CAP2_HW_LRO_IPV6) |
838 | word |= QLCNIC_ENABLE_IPV6_LRO; |
839 | } |
840 | |
841 | req.words[0] = cpu_to_le64(word); |
842 | |
843 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
844 | if (rv != 0) |
845 | dev_err(&adapter->netdev->dev, |
846 | "Could not send configure hw lro request\n" ); |
847 | |
848 | return rv; |
849 | } |
850 | |
851 | int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable) |
852 | { |
853 | struct qlcnic_nic_req req; |
854 | u64 word; |
855 | int rv; |
856 | |
857 | if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable) |
858 | return 0; |
859 | |
860 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
861 | |
862 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
863 | |
864 | word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING | |
865 | ((u64)adapter->portnum << 16); |
866 | req.req_hdr = cpu_to_le64(word); |
867 | |
868 | req.words[0] = cpu_to_le64(enable); |
869 | |
870 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
871 | if (rv != 0) |
872 | dev_err(&adapter->netdev->dev, |
873 | "Could not send configure bridge mode request\n" ); |
874 | |
875 | adapter->flags ^= QLCNIC_BRIDGE_ENABLED; |
876 | |
877 | return rv; |
878 | } |
879 | |
880 | |
881 | #define 0x3 |
882 | #define BIT_10 |
883 | #define (1ULL << 63) |
884 | #define 0x7ULL |
885 | |
886 | int (struct qlcnic_adapter *adapter, int enable) |
887 | { |
888 | struct qlcnic_nic_req req; |
889 | u64 word; |
890 | int i, rv; |
891 | |
892 | static const u64 key[] = { |
893 | 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL, |
894 | 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, |
895 | 0x255b0ec26d5a56daULL |
896 | }; |
897 | |
898 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
899 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
900 | |
901 | word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16); |
902 | req.req_hdr = cpu_to_le64(word); |
903 | |
904 | /* |
905 | * RSS request: |
906 | * bits 3-0: hash_method |
907 | * 5-4: hash_type_ipv4 |
908 | * 7-6: hash_type_ipv6 |
909 | * 8: enable |
910 | * 9: use indirection table |
911 | * 10: type-c rss |
912 | * 11: udp rss |
913 | * 47-12: reserved |
914 | * 62-48: indirection table mask |
915 | * 63: feature flag |
916 | */ |
917 | word = ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) | |
918 | ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) | |
919 | ((u64)(enable & 0x1) << 8) | |
920 | ((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) | |
921 | (u64)QLCNIC_ENABLE_TYPE_C_RSS | |
922 | (u64)QLCNIC_RSS_FEATURE_FLAG; |
923 | |
924 | req.words[0] = cpu_to_le64(word); |
925 | for (i = 0; i < 5; i++) |
926 | req.words[i+1] = cpu_to_le64(key[i]); |
927 | |
928 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
929 | if (rv != 0) |
930 | dev_err(&adapter->netdev->dev, "could not configure RSS\n" ); |
931 | |
932 | return rv; |
933 | } |
934 | |
935 | void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter, |
936 | __be32 ip, int cmd) |
937 | { |
938 | struct qlcnic_nic_req req; |
939 | struct qlcnic_ipaddr *ipa; |
940 | u64 word; |
941 | int rv; |
942 | |
943 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
944 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
945 | |
946 | word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16); |
947 | req.req_hdr = cpu_to_le64(word); |
948 | |
949 | req.words[0] = cpu_to_le64(cmd); |
950 | ipa = (struct qlcnic_ipaddr *)&req.words[1]; |
951 | ipa->ipv4 = ip; |
952 | |
953 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
954 | if (rv != 0) |
955 | dev_err(&adapter->netdev->dev, |
956 | "could not notify %s IP 0x%x request\n" , |
957 | (cmd == QLCNIC_IP_UP) ? "Add" : "Remove" , ip); |
958 | } |
959 | |
960 | int qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable) |
961 | { |
962 | struct qlcnic_nic_req req; |
963 | u64 word; |
964 | int rv; |
965 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
966 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
967 | |
968 | word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16); |
969 | req.req_hdr = cpu_to_le64(word); |
970 | req.words[0] = cpu_to_le64(enable | (enable << 8)); |
971 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
972 | if (rv != 0) |
973 | dev_err(&adapter->netdev->dev, |
974 | "could not configure link notification\n" ); |
975 | |
976 | return rv; |
977 | } |
978 | |
979 | static int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) |
980 | { |
981 | struct qlcnic_nic_req req; |
982 | u64 word; |
983 | int rv; |
984 | |
985 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
986 | return 0; |
987 | |
988 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
989 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
990 | |
991 | word = QLCNIC_H2C_OPCODE_LRO_REQUEST | |
992 | ((u64)adapter->portnum << 16) | |
993 | ((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ; |
994 | |
995 | req.req_hdr = cpu_to_le64(word); |
996 | |
997 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
998 | if (rv != 0) |
999 | dev_err(&adapter->netdev->dev, |
1000 | "could not cleanup lro flows\n" ); |
1001 | |
1002 | return rv; |
1003 | } |
1004 | |
1005 | /* |
1006 | * qlcnic_change_mtu - Change the Maximum Transfer Unit |
1007 | * @returns 0 on success, negative on failure |
1008 | */ |
1009 | |
1010 | int qlcnic_change_mtu(struct net_device *netdev, int mtu) |
1011 | { |
1012 | struct qlcnic_adapter *adapter = netdev_priv(dev: netdev); |
1013 | int rc = 0; |
1014 | |
1015 | rc = qlcnic_fw_cmd_set_mtu(adapter, mtu); |
1016 | |
1017 | if (!rc) |
1018 | netdev->mtu = mtu; |
1019 | |
1020 | return rc; |
1021 | } |
1022 | |
1023 | static netdev_features_t qlcnic_process_flags(struct qlcnic_adapter *adapter, |
1024 | netdev_features_t features) |
1025 | { |
1026 | u32 offload_flags = adapter->offload_flags; |
1027 | |
1028 | if (offload_flags & BIT_0) { |
1029 | features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | |
1030 | NETIF_F_IPV6_CSUM; |
1031 | adapter->rx_csum = 1; |
1032 | if (QLCNIC_IS_TSO_CAPABLE(adapter)) { |
1033 | if (!(offload_flags & BIT_1)) |
1034 | features &= ~NETIF_F_TSO; |
1035 | else |
1036 | features |= NETIF_F_TSO; |
1037 | |
1038 | if (!(offload_flags & BIT_2)) |
1039 | features &= ~NETIF_F_TSO6; |
1040 | else |
1041 | features |= NETIF_F_TSO6; |
1042 | } |
1043 | } else { |
1044 | features &= ~(NETIF_F_RXCSUM | |
1045 | NETIF_F_IP_CSUM | |
1046 | NETIF_F_IPV6_CSUM); |
1047 | |
1048 | if (QLCNIC_IS_TSO_CAPABLE(adapter)) |
1049 | features &= ~(NETIF_F_TSO | NETIF_F_TSO6); |
1050 | adapter->rx_csum = 0; |
1051 | } |
1052 | |
1053 | return features; |
1054 | } |
1055 | |
1056 | netdev_features_t qlcnic_fix_features(struct net_device *netdev, |
1057 | netdev_features_t features) |
1058 | { |
1059 | struct qlcnic_adapter *adapter = netdev_priv(dev: netdev); |
1060 | netdev_features_t changed; |
1061 | |
1062 | if (qlcnic_82xx_check(adapter) && |
1063 | (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { |
1064 | if (adapter->flags & QLCNIC_APP_CHANGED_FLAGS) { |
1065 | features = qlcnic_process_flags(adapter, features); |
1066 | } else { |
1067 | changed = features ^ netdev->features; |
1068 | features ^= changed & (NETIF_F_RXCSUM | |
1069 | NETIF_F_IP_CSUM | |
1070 | NETIF_F_IPV6_CSUM | |
1071 | NETIF_F_TSO | |
1072 | NETIF_F_TSO6); |
1073 | } |
1074 | } |
1075 | |
1076 | if (!(features & NETIF_F_RXCSUM)) |
1077 | features &= ~NETIF_F_LRO; |
1078 | |
1079 | return features; |
1080 | } |
1081 | |
1082 | |
1083 | int qlcnic_set_features(struct net_device *netdev, netdev_features_t features) |
1084 | { |
1085 | struct qlcnic_adapter *adapter = netdev_priv(dev: netdev); |
1086 | netdev_features_t changed = netdev->features ^ features; |
1087 | int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0; |
1088 | |
1089 | if (!(changed & NETIF_F_LRO)) |
1090 | return 0; |
1091 | |
1092 | netdev->features ^= NETIF_F_LRO; |
1093 | |
1094 | if (qlcnic_config_hw_lro(adapter, enable: hw_lro)) |
1095 | return -EIO; |
1096 | |
1097 | if (!hw_lro && qlcnic_82xx_check(adapter)) { |
1098 | if (qlcnic_send_lro_cleanup(adapter)) |
1099 | return -EIO; |
1100 | } |
1101 | |
1102 | return 0; |
1103 | } |
1104 | |
1105 | /* |
1106 | * Changes the CRB window to the specified window. |
1107 | */ |
1108 | /* Returns < 0 if off is not valid, |
1109 | * 1 if window access is needed. 'off' is set to offset from |
1110 | * CRB space in 128M pci map |
1111 | * 0 if no window access is needed. 'off' is set to 2M addr |
1112 | * In: 'off' is offset from base in 128M pci map |
1113 | */ |
1114 | static int qlcnic_pci_get_crb_addr_2M(struct qlcnic_hardware_context *ahw, |
1115 | ulong off, void __iomem **addr) |
1116 | { |
1117 | const struct crb_128M_2M_sub_block_map *m; |
1118 | |
1119 | if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE)) |
1120 | return -EINVAL; |
1121 | |
1122 | off -= QLCNIC_PCI_CRBSPACE; |
1123 | |
1124 | /* |
1125 | * Try direct map |
1126 | */ |
1127 | m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; |
1128 | |
1129 | if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { |
1130 | *addr = ahw->pci_base0 + m->start_2M + |
1131 | (off - m->start_128M); |
1132 | return 0; |
1133 | } |
1134 | |
1135 | /* |
1136 | * Not in direct map, use crb window |
1137 | */ |
1138 | *addr = ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); |
1139 | return 1; |
1140 | } |
1141 | |
1142 | /* |
1143 | * In: 'off' is offset from CRB space in 128M pci map |
1144 | * Out: 'off' is 2M pci map addr |
1145 | * side effect: lock crb window |
1146 | */ |
1147 | static int |
1148 | qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) |
1149 | { |
1150 | u32 window; |
1151 | void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M; |
1152 | |
1153 | off -= QLCNIC_PCI_CRBSPACE; |
1154 | |
1155 | window = CRB_HI(off); |
1156 | if (window == 0) { |
1157 | dev_err(&adapter->pdev->dev, "Invalid offset 0x%lx\n" , off); |
1158 | return -EIO; |
1159 | } |
1160 | |
1161 | writel(val: window, addr); |
1162 | if (readl(addr) != window) { |
1163 | if (printk_ratelimit()) |
1164 | dev_warn(&adapter->pdev->dev, |
1165 | "failed to set CRB window to %d off 0x%lx\n" , |
1166 | window, off); |
1167 | return -EIO; |
1168 | } |
1169 | return 0; |
1170 | } |
1171 | |
1172 | int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, |
1173 | u32 data) |
1174 | { |
1175 | unsigned long flags; |
1176 | int rv; |
1177 | void __iomem *addr = NULL; |
1178 | |
1179 | rv = qlcnic_pci_get_crb_addr_2M(ahw: adapter->ahw, off, addr: &addr); |
1180 | |
1181 | if (rv == 0) { |
1182 | writel(val: data, addr); |
1183 | return 0; |
1184 | } |
1185 | |
1186 | if (rv > 0) { |
1187 | /* indirect access */ |
1188 | write_lock_irqsave(&adapter->ahw->crb_lock, flags); |
1189 | crb_win_lock(adapter); |
1190 | rv = qlcnic_pci_set_crbwindow_2M(adapter, off); |
1191 | if (!rv) |
1192 | writel(val: data, addr); |
1193 | crb_win_unlock(adapter); |
1194 | write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); |
1195 | return rv; |
1196 | } |
1197 | |
1198 | dev_err(&adapter->pdev->dev, |
1199 | "%s: invalid offset: 0x%016lx\n" , __func__, off); |
1200 | dump_stack(); |
1201 | return -EIO; |
1202 | } |
1203 | |
1204 | int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off, |
1205 | int *err) |
1206 | { |
1207 | unsigned long flags; |
1208 | int rv; |
1209 | u32 data = -1; |
1210 | void __iomem *addr = NULL; |
1211 | |
1212 | rv = qlcnic_pci_get_crb_addr_2M(ahw: adapter->ahw, off, addr: &addr); |
1213 | |
1214 | if (rv == 0) |
1215 | return readl(addr); |
1216 | |
1217 | if (rv > 0) { |
1218 | /* indirect access */ |
1219 | write_lock_irqsave(&adapter->ahw->crb_lock, flags); |
1220 | crb_win_lock(adapter); |
1221 | if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) |
1222 | data = readl(addr); |
1223 | crb_win_unlock(adapter); |
1224 | write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); |
1225 | return data; |
1226 | } |
1227 | |
1228 | dev_err(&adapter->pdev->dev, |
1229 | "%s: invalid offset: 0x%016lx\n" , __func__, off); |
1230 | dump_stack(); |
1231 | return -1; |
1232 | } |
1233 | |
1234 | void __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw, |
1235 | u32 offset) |
1236 | { |
1237 | void __iomem *addr = NULL; |
1238 | |
1239 | WARN_ON(qlcnic_pci_get_crb_addr_2M(ahw, offset, &addr)); |
1240 | |
1241 | return addr; |
1242 | } |
1243 | |
1244 | static int qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, |
1245 | u32 window, u64 off, u64 *data, int op) |
1246 | { |
1247 | void __iomem *addr; |
1248 | u32 start; |
1249 | |
1250 | mutex_lock(&adapter->ahw->mem_lock); |
1251 | |
1252 | writel(val: window, addr: adapter->ahw->ocm_win_crb); |
1253 | /* read back to flush */ |
1254 | readl(addr: adapter->ahw->ocm_win_crb); |
1255 | start = QLCNIC_PCI_OCM0_2M + off; |
1256 | |
1257 | addr = adapter->ahw->pci_base0 + start; |
1258 | |
1259 | if (op == 0) /* read */ |
1260 | *data = readq(addr); |
1261 | else /* write */ |
1262 | writeq(val: *data, addr); |
1263 | |
1264 | /* Set window to 0 */ |
1265 | writel(val: 0, addr: adapter->ahw->ocm_win_crb); |
1266 | readl(addr: adapter->ahw->ocm_win_crb); |
1267 | |
1268 | mutex_unlock(lock: &adapter->ahw->mem_lock); |
1269 | return 0; |
1270 | } |
1271 | |
1272 | static void |
1273 | qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) |
1274 | { |
1275 | void __iomem *addr = adapter->ahw->pci_base0 + |
1276 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); |
1277 | |
1278 | mutex_lock(&adapter->ahw->mem_lock); |
1279 | *data = readq(addr); |
1280 | mutex_unlock(lock: &adapter->ahw->mem_lock); |
1281 | } |
1282 | |
1283 | static void |
1284 | qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) |
1285 | { |
1286 | void __iomem *addr = adapter->ahw->pci_base0 + |
1287 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); |
1288 | |
1289 | mutex_lock(&adapter->ahw->mem_lock); |
1290 | writeq(val: data, addr); |
1291 | mutex_unlock(lock: &adapter->ahw->mem_lock); |
1292 | } |
1293 | |
1294 | |
1295 | |
1296 | /* Set MS memory control data for different adapters */ |
1297 | static void qlcnic_set_ms_controls(struct qlcnic_adapter *adapter, u64 off, |
1298 | struct qlcnic_ms_reg_ctrl *ms) |
1299 | { |
1300 | ms->control = QLCNIC_MS_CTRL; |
1301 | ms->low = QLCNIC_MS_ADDR_LO; |
1302 | ms->hi = QLCNIC_MS_ADDR_HI; |
1303 | if (off & 0xf) { |
1304 | ms->wd[0] = QLCNIC_MS_WRTDATA_LO; |
1305 | ms->rd[0] = QLCNIC_MS_RDDATA_LO; |
1306 | ms->wd[1] = QLCNIC_MS_WRTDATA_HI; |
1307 | ms->rd[1] = QLCNIC_MS_RDDATA_HI; |
1308 | ms->wd[2] = QLCNIC_MS_WRTDATA_ULO; |
1309 | ms->wd[3] = QLCNIC_MS_WRTDATA_UHI; |
1310 | ms->rd[2] = QLCNIC_MS_RDDATA_ULO; |
1311 | ms->rd[3] = QLCNIC_MS_RDDATA_UHI; |
1312 | } else { |
1313 | ms->wd[0] = QLCNIC_MS_WRTDATA_ULO; |
1314 | ms->rd[0] = QLCNIC_MS_RDDATA_ULO; |
1315 | ms->wd[1] = QLCNIC_MS_WRTDATA_UHI; |
1316 | ms->rd[1] = QLCNIC_MS_RDDATA_UHI; |
1317 | ms->wd[2] = QLCNIC_MS_WRTDATA_LO; |
1318 | ms->wd[3] = QLCNIC_MS_WRTDATA_HI; |
1319 | ms->rd[2] = QLCNIC_MS_RDDATA_LO; |
1320 | ms->rd[3] = QLCNIC_MS_RDDATA_HI; |
1321 | } |
1322 | |
1323 | ms->ocm_window = OCM_WIN_P3P(off); |
1324 | ms->off = GET_MEM_OFFS_2M(off); |
1325 | } |
1326 | |
1327 | int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) |
1328 | { |
1329 | int j, ret = 0; |
1330 | u32 temp, off8; |
1331 | struct qlcnic_ms_reg_ctrl ms; |
1332 | |
1333 | /* Only 64-bit aligned access */ |
1334 | if (off & 7) |
1335 | return -EIO; |
1336 | |
1337 | memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl)); |
1338 | if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, |
1339 | QLCNIC_ADDR_QDR_NET_MAX) || |
1340 | ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, |
1341 | QLCNIC_ADDR_DDR_NET_MAX))) |
1342 | return -EIO; |
1343 | |
1344 | qlcnic_set_ms_controls(adapter, off, ms: &ms); |
1345 | |
1346 | if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) |
1347 | return qlcnic_pci_mem_access_direct(adapter, window: ms.ocm_window, |
1348 | off: ms.off, data: &data, op: 1); |
1349 | |
1350 | off8 = off & ~0xf; |
1351 | |
1352 | mutex_lock(&adapter->ahw->mem_lock); |
1353 | |
1354 | qlcnic_ind_wr(adapter, addr: ms.low, data: off8); |
1355 | qlcnic_ind_wr(adapter, addr: ms.hi, data: 0); |
1356 | |
1357 | qlcnic_ind_wr(adapter, addr: ms.control, TA_CTL_ENABLE); |
1358 | qlcnic_ind_wr(adapter, addr: ms.control, QLCNIC_TA_START_ENABLE); |
1359 | |
1360 | for (j = 0; j < MAX_CTL_CHECK; j++) { |
1361 | temp = qlcnic_ind_rd(adapter, addr: ms.control); |
1362 | if ((temp & TA_CTL_BUSY) == 0) |
1363 | break; |
1364 | } |
1365 | |
1366 | if (j >= MAX_CTL_CHECK) { |
1367 | ret = -EIO; |
1368 | goto done; |
1369 | } |
1370 | |
1371 | /* This is the modify part of read-modify-write */ |
1372 | qlcnic_ind_wr(adapter, addr: ms.wd[0], data: qlcnic_ind_rd(adapter, addr: ms.rd[0])); |
1373 | qlcnic_ind_wr(adapter, addr: ms.wd[1], data: qlcnic_ind_rd(adapter, addr: ms.rd[1])); |
1374 | /* This is the write part of read-modify-write */ |
1375 | qlcnic_ind_wr(adapter, addr: ms.wd[2], data: data & 0xffffffff); |
1376 | qlcnic_ind_wr(adapter, addr: ms.wd[3], data: (data >> 32) & 0xffffffff); |
1377 | |
1378 | qlcnic_ind_wr(adapter, addr: ms.control, QLCNIC_TA_WRITE_ENABLE); |
1379 | qlcnic_ind_wr(adapter, addr: ms.control, QLCNIC_TA_WRITE_START); |
1380 | |
1381 | for (j = 0; j < MAX_CTL_CHECK; j++) { |
1382 | temp = qlcnic_ind_rd(adapter, addr: ms.control); |
1383 | if ((temp & TA_CTL_BUSY) == 0) |
1384 | break; |
1385 | } |
1386 | |
1387 | if (j >= MAX_CTL_CHECK) { |
1388 | if (printk_ratelimit()) |
1389 | dev_err(&adapter->pdev->dev, |
1390 | "failed to write through agent\n" ); |
1391 | ret = -EIO; |
1392 | } else |
1393 | ret = 0; |
1394 | |
1395 | done: |
1396 | mutex_unlock(lock: &adapter->ahw->mem_lock); |
1397 | |
1398 | return ret; |
1399 | } |
1400 | |
1401 | int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) |
1402 | { |
1403 | int j, ret; |
1404 | u32 temp, off8; |
1405 | u64 val; |
1406 | struct qlcnic_ms_reg_ctrl ms; |
1407 | |
1408 | /* Only 64-bit aligned access */ |
1409 | if (off & 7) |
1410 | return -EIO; |
1411 | if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET, |
1412 | QLCNIC_ADDR_QDR_NET_MAX) || |
1413 | ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, |
1414 | QLCNIC_ADDR_DDR_NET_MAX))) |
1415 | return -EIO; |
1416 | |
1417 | memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl)); |
1418 | qlcnic_set_ms_controls(adapter, off, ms: &ms); |
1419 | |
1420 | if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) |
1421 | return qlcnic_pci_mem_access_direct(adapter, window: ms.ocm_window, |
1422 | off: ms.off, data, op: 0); |
1423 | |
1424 | mutex_lock(&adapter->ahw->mem_lock); |
1425 | |
1426 | off8 = off & ~0xf; |
1427 | |
1428 | qlcnic_ind_wr(adapter, addr: ms.low, data: off8); |
1429 | qlcnic_ind_wr(adapter, addr: ms.hi, data: 0); |
1430 | |
1431 | qlcnic_ind_wr(adapter, addr: ms.control, TA_CTL_ENABLE); |
1432 | qlcnic_ind_wr(adapter, addr: ms.control, QLCNIC_TA_START_ENABLE); |
1433 | |
1434 | for (j = 0; j < MAX_CTL_CHECK; j++) { |
1435 | temp = qlcnic_ind_rd(adapter, addr: ms.control); |
1436 | if ((temp & TA_CTL_BUSY) == 0) |
1437 | break; |
1438 | } |
1439 | |
1440 | if (j >= MAX_CTL_CHECK) { |
1441 | if (printk_ratelimit()) |
1442 | dev_err(&adapter->pdev->dev, |
1443 | "failed to read through agent\n" ); |
1444 | ret = -EIO; |
1445 | } else { |
1446 | |
1447 | temp = qlcnic_ind_rd(adapter, addr: ms.rd[3]); |
1448 | val = (u64)temp << 32; |
1449 | val |= qlcnic_ind_rd(adapter, addr: ms.rd[2]); |
1450 | *data = val; |
1451 | ret = 0; |
1452 | } |
1453 | |
1454 | mutex_unlock(lock: &adapter->ahw->mem_lock); |
1455 | |
1456 | return ret; |
1457 | } |
1458 | |
1459 | int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) |
1460 | { |
1461 | int offset, board_type, magic, err = 0; |
1462 | struct pci_dev *pdev = adapter->pdev; |
1463 | |
1464 | offset = QLCNIC_FW_MAGIC_OFFSET; |
1465 | if (qlcnic_rom_fast_read(adapter, addr: offset, valp: &magic)) |
1466 | return -EIO; |
1467 | |
1468 | if (magic != QLCNIC_BDINFO_MAGIC) { |
1469 | dev_err(&pdev->dev, "invalid board config, magic=%08x\n" , |
1470 | magic); |
1471 | return -EIO; |
1472 | } |
1473 | |
1474 | offset = QLCNIC_BRDTYPE_OFFSET; |
1475 | if (qlcnic_rom_fast_read(adapter, addr: offset, valp: &board_type)) |
1476 | return -EIO; |
1477 | |
1478 | adapter->ahw->board_type = board_type; |
1479 | |
1480 | if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { |
1481 | u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err); |
1482 | if (err == -EIO) |
1483 | return err; |
1484 | if ((gpio & 0x8000) == 0) |
1485 | board_type = QLCNIC_BRDTYPE_P3P_10G_TP; |
1486 | } |
1487 | |
1488 | switch (board_type) { |
1489 | case QLCNIC_BRDTYPE_P3P_HMEZ: |
1490 | case QLCNIC_BRDTYPE_P3P_XG_LOM: |
1491 | case QLCNIC_BRDTYPE_P3P_10G_CX4: |
1492 | case QLCNIC_BRDTYPE_P3P_10G_CX4_LP: |
1493 | case QLCNIC_BRDTYPE_P3P_IMEZ: |
1494 | case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS: |
1495 | case QLCNIC_BRDTYPE_P3P_10G_SFP_CT: |
1496 | case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: |
1497 | case QLCNIC_BRDTYPE_P3P_10G_XFP: |
1498 | case QLCNIC_BRDTYPE_P3P_10000_BASE_T: |
1499 | adapter->ahw->port_type = QLCNIC_XGBE; |
1500 | break; |
1501 | case QLCNIC_BRDTYPE_P3P_REF_QG: |
1502 | case QLCNIC_BRDTYPE_P3P_4_GB: |
1503 | case QLCNIC_BRDTYPE_P3P_4_GB_MM: |
1504 | adapter->ahw->port_type = QLCNIC_GBE; |
1505 | break; |
1506 | case QLCNIC_BRDTYPE_P3P_10G_TP: |
1507 | adapter->ahw->port_type = (adapter->portnum < 2) ? |
1508 | QLCNIC_XGBE : QLCNIC_GBE; |
1509 | break; |
1510 | default: |
1511 | dev_err(&pdev->dev, "unknown board type %x\n" , board_type); |
1512 | adapter->ahw->port_type = QLCNIC_XGBE; |
1513 | break; |
1514 | } |
1515 | |
1516 | return 0; |
1517 | } |
1518 | |
1519 | static int |
1520 | qlcnic_wol_supported(struct qlcnic_adapter *adapter) |
1521 | { |
1522 | u32 wol_cfg; |
1523 | int err = 0; |
1524 | |
1525 | wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); |
1526 | if (wol_cfg & (1UL << adapter->portnum)) { |
1527 | wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); |
1528 | if (err == -EIO) |
1529 | return err; |
1530 | if (wol_cfg & (1 << adapter->portnum)) |
1531 | return 1; |
1532 | } |
1533 | |
1534 | return 0; |
1535 | } |
1536 | |
1537 | int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) |
1538 | { |
1539 | struct qlcnic_nic_req req; |
1540 | int rv; |
1541 | u64 word; |
1542 | |
1543 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
1544 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
1545 | |
1546 | word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16); |
1547 | req.req_hdr = cpu_to_le64(word); |
1548 | |
1549 | req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum); |
1550 | req.words[1] = cpu_to_le64(state); |
1551 | |
1552 | rv = qlcnic_send_cmd_descs(adapter, cmd_desc_arr: (struct cmd_desc_type0 *)&req, nr_desc: 1); |
1553 | if (rv) |
1554 | dev_err(&adapter->pdev->dev, "LED configuration failed.\n" ); |
1555 | |
1556 | return rv; |
1557 | } |
1558 | |
1559 | void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter) |
1560 | { |
1561 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
1562 | struct qlcnic_cmd_args cmd; |
1563 | u8 beacon_state; |
1564 | int err = 0; |
1565 | |
1566 | if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { |
1567 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1568 | QLCNIC_CMD_GET_LED_STATUS); |
1569 | if (!err) { |
1570 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1571 | if (err) { |
1572 | netdev_err(dev: adapter->netdev, |
1573 | format: "Failed to get current beacon state, err=%d\n" , |
1574 | err); |
1575 | } else { |
1576 | beacon_state = cmd.rsp.arg[1]; |
1577 | if (beacon_state == QLCNIC_BEACON_DISABLE) |
1578 | ahw->beacon_state = QLCNIC_BEACON_OFF; |
1579 | else if (beacon_state == QLCNIC_BEACON_EANBLE) |
1580 | ahw->beacon_state = QLCNIC_BEACON_ON; |
1581 | } |
1582 | } |
1583 | qlcnic_free_mbx_args(cmd: &cmd); |
1584 | } |
1585 | |
1586 | return; |
1587 | } |
1588 | |
1589 | void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) |
1590 | { |
1591 | void __iomem *msix_base_addr; |
1592 | u32 func; |
1593 | u32 msix_base; |
1594 | |
1595 | pci_read_config_dword(dev: adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, val: &func); |
1596 | msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE; |
1597 | msix_base = readl(addr: msix_base_addr); |
1598 | func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE; |
1599 | adapter->ahw->pci_func = func; |
1600 | } |
1601 | |
1602 | void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf, |
1603 | loff_t offset, size_t size) |
1604 | { |
1605 | int err = 0; |
1606 | u32 data; |
1607 | u64 qmdata; |
1608 | |
1609 | if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) { |
1610 | qlcnic_pci_camqm_read_2M(adapter, off: offset, data: &qmdata); |
1611 | memcpy(buf, &qmdata, size); |
1612 | } else { |
1613 | data = QLCRD32(adapter, offset, &err); |
1614 | memcpy(buf, &data, size); |
1615 | } |
1616 | } |
1617 | |
1618 | void qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf, |
1619 | loff_t offset, size_t size) |
1620 | { |
1621 | u32 data; |
1622 | u64 qmdata; |
1623 | |
1624 | if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) { |
1625 | memcpy(&qmdata, buf, size); |
1626 | qlcnic_pci_camqm_write_2M(adapter, off: offset, data: qmdata); |
1627 | } else { |
1628 | memcpy(&data, buf, size); |
1629 | QLCWR32(adapter, offset, data); |
1630 | } |
1631 | } |
1632 | |
1633 | int qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter) |
1634 | { |
1635 | return qlcnic_pcie_sem_lock(adapter, sem: 5, id_reg: 0); |
1636 | } |
1637 | |
1638 | void qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter) |
1639 | { |
1640 | qlcnic_pcie_sem_unlock(adapter, sem: 5); |
1641 | } |
1642 | |
1643 | int qlcnic_82xx_shutdown(struct pci_dev *pdev) |
1644 | { |
1645 | struct qlcnic_adapter *adapter = pci_get_drvdata(pdev); |
1646 | struct net_device *netdev = adapter->netdev; |
1647 | |
1648 | netif_device_detach(dev: netdev); |
1649 | |
1650 | qlcnic_cancel_idc_work(adapter); |
1651 | |
1652 | if (netif_running(dev: netdev)) |
1653 | qlcnic_down(adapter, netdev); |
1654 | |
1655 | qlcnic_clr_all_drv_state(adapter, failed: 0); |
1656 | |
1657 | clear_bit(__QLCNIC_RESETTING, addr: &adapter->state); |
1658 | |
1659 | if (qlcnic_wol_supported(adapter)) |
1660 | device_wakeup_enable(dev: &pdev->dev); |
1661 | |
1662 | return 0; |
1663 | } |
1664 | |
1665 | int qlcnic_82xx_resume(struct qlcnic_adapter *adapter) |
1666 | { |
1667 | struct net_device *netdev = adapter->netdev; |
1668 | int err; |
1669 | |
1670 | err = qlcnic_start_firmware(adapter); |
1671 | if (err) { |
1672 | dev_err(&adapter->pdev->dev, "failed to start firmware\n" ); |
1673 | return err; |
1674 | } |
1675 | |
1676 | if (netif_running(dev: netdev)) { |
1677 | err = qlcnic_up(adapter, netdev); |
1678 | if (!err) |
1679 | qlcnic_restore_indev_addr(netdev, NETDEV_UP); |
1680 | } |
1681 | |
1682 | netif_device_attach(dev: netdev); |
1683 | qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); |
1684 | return err; |
1685 | } |
1686 | |