Commit | Line | Data |
---|---|---|
4863dea3 SG |
1 | /* |
2 | * Copyright (C) 2015 Cavium, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of version 2 of the GNU General Public License | |
6 | * as published by the Free Software Foundation. | |
7 | */ | |
8 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/pci.h> | |
12 | #include <linux/etherdevice.h> | |
13 | #include <linux/of.h> | |
14 | ||
15 | #include "nic_reg.h" | |
16 | #include "nic.h" | |
17 | #include "q_struct.h" | |
18 | #include "thunder_bgx.h" | |
19 | ||
20 | #define DRV_NAME "thunder-nic" | |
21 | #define DRV_VERSION "1.0" | |
22 | ||
23 | struct nicpf { | |
24 | struct pci_dev *pdev; | |
4863dea3 SG |
25 | u8 node; |
26 | unsigned int flags; | |
27 | u8 num_vf_en; /* No of VF enabled */ | |
28 | bool vf_enabled[MAX_NUM_VFS_SUPPORTED]; | |
29 | void __iomem *reg_base; /* Register start address */ | |
92dc8769 SG |
30 | u8 num_sqs_en; /* Secondary qsets enabled */ |
31 | u64 nicvf[MAX_NUM_VFS_SUPPORTED]; | |
32 | u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF]; | |
33 | u8 pqs_vf[MAX_NUM_VFS_SUPPORTED]; | |
34 | bool sqs_used[MAX_NUM_VFS_SUPPORTED]; | |
4863dea3 SG |
35 | struct pkind_cfg pkind; |
36 | #define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF)) | |
37 | #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) | |
38 | #define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) | |
39 | u8 vf_lmac_map[MAX_LMAC]; | |
40 | struct delayed_work dwork; | |
41 | struct workqueue_struct *check_link; | |
42 | u8 link[MAX_LMAC]; | |
43 | u8 duplex[MAX_LMAC]; | |
44 | u32 speed[MAX_LMAC]; | |
45 | u16 cpi_base[MAX_NUM_VFS_SUPPORTED]; | |
34411b68 | 46 | u16 rssi_base[MAX_NUM_VFS_SUPPORTED]; |
4863dea3 SG |
47 | u16 rss_ind_tbl_size; |
48 | bool mbx_lock[MAX_NUM_VFS_SUPPORTED]; | |
49 | ||
50 | /* MSI-X */ | |
51 | bool msix_enabled; | |
52 | u8 num_vec; | |
53 | struct msix_entry msix_entries[NIC_PF_MSIX_VECTORS]; | |
54 | bool irq_allocated[NIC_PF_MSIX_VECTORS]; | |
55 | }; | |
56 | ||
57 | /* Supported devices */ | |
58 | static const struct pci_device_id nic_id_table[] = { | |
59 | { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) }, | |
60 | { 0, } /* end of table */ | |
61 | }; | |
62 | ||
63 | MODULE_AUTHOR("Sunil Goutham"); | |
64 | MODULE_DESCRIPTION("Cavium Thunder NIC Physical Function Driver"); | |
65 | MODULE_LICENSE("GPL v2"); | |
66 | MODULE_VERSION(DRV_VERSION); | |
67 | MODULE_DEVICE_TABLE(pci, nic_id_table); | |
68 | ||
69 | /* The Cavium ThunderX network controller can *only* be found in SoCs | |
70 | * containing the ThunderX ARM64 CPU implementation. All accesses to the device | |
71 | * registers on this platform are implicitly strongly ordered with respect | |
72 | * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use | |
73 | * with no memory barriers in this driver. The readq()/writeq() functions add | |
74 | * explicit ordering operation which in this case are redundant, and only | |
75 | * add overhead. | |
76 | */ | |
77 | ||
78 | /* Register read/write APIs */ | |
79 | static void nic_reg_write(struct nicpf *nic, u64 offset, u64 val) | |
80 | { | |
81 | writeq_relaxed(val, nic->reg_base + offset); | |
82 | } | |
83 | ||
84 | static u64 nic_reg_read(struct nicpf *nic, u64 offset) | |
85 | { | |
86 | return readq_relaxed(nic->reg_base + offset); | |
87 | } | |
88 | ||
89 | /* PF -> VF mailbox communication APIs */ | |
90 | static void nic_enable_mbx_intr(struct nicpf *nic) | |
91 | { | |
92 | /* Enable mailbox interrupt for all 128 VFs */ | |
93 | nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0ull); | |
94 | nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), ~0ull); | |
95 | } | |
96 | ||
97 | static void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) | |
98 | { | |
99 | nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf)); | |
100 | } | |
101 | ||
102 | static u64 nic_get_mbx_addr(int vf) | |
103 | { | |
104 | return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT); | |
105 | } | |
106 | ||
107 | /* Send a mailbox message to VF | |
108 | * @vf: vf to which this message to be sent | |
109 | * @mbx: Message to be sent | |
110 | */ | |
111 | static void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) | |
112 | { | |
113 | void __iomem *mbx_addr = nic->reg_base + nic_get_mbx_addr(vf); | |
114 | u64 *msg = (u64 *)mbx; | |
115 | ||
116 | /* In first revision HW, mbox interrupt is triggerred | |
117 | * when PF writes to MBOX(1), in next revisions when | |
118 | * PF writes to MBOX(0) | |
119 | */ | |
40fb5f8a | 120 | if (pass1_silicon(nic->pdev)) { |
4863dea3 SG |
121 | /* see the comment for nic_reg_write()/nic_reg_read() |
122 | * functions above | |
123 | */ | |
124 | writeq_relaxed(msg[0], mbx_addr); | |
125 | writeq_relaxed(msg[1], mbx_addr + 8); | |
126 | } else { | |
127 | writeq_relaxed(msg[1], mbx_addr + 8); | |
128 | writeq_relaxed(msg[0], mbx_addr); | |
129 | } | |
130 | } | |
131 | ||
132 | /* Responds to VF's READY message with VF's | |
133 | * ID, node, MAC address e.t.c | |
134 | * @vf: VF which sent READY message | |
135 | */ | |
136 | static void nic_mbx_send_ready(struct nicpf *nic, int vf) | |
137 | { | |
138 | union nic_mbx mbx = {}; | |
139 | int bgx_idx, lmac; | |
140 | const char *mac; | |
141 | ||
142 | mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; | |
143 | mbx.nic_cfg.vf_id = vf; | |
144 | ||
145 | mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; | |
146 | ||
92dc8769 SG |
147 | if (vf < MAX_LMAC) { |
148 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
149 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
4863dea3 | 150 | |
92dc8769 SG |
151 | mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); |
152 | if (mac) | |
153 | ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); | |
154 | } | |
155 | mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; | |
4863dea3 | 156 | mbx.nic_cfg.node_id = nic->node; |
d77a2384 SG |
157 | |
158 | mbx.nic_cfg.loopback_supported = vf < MAX_LMAC; | |
159 | ||
4863dea3 SG |
160 | nic_send_msg_to_vf(nic, vf, &mbx); |
161 | } | |
162 | ||
163 | /* ACKs VF's mailbox message | |
164 | * @vf: VF to which ACK to be sent | |
165 | */ | |
166 | static void nic_mbx_send_ack(struct nicpf *nic, int vf) | |
167 | { | |
168 | union nic_mbx mbx = {}; | |
169 | ||
170 | mbx.msg.msg = NIC_MBOX_MSG_ACK; | |
171 | nic_send_msg_to_vf(nic, vf, &mbx); | |
172 | } | |
173 | ||
174 | /* NACKs VF's mailbox message that PF is not able to | |
175 | * complete the action | |
176 | * @vf: VF to which ACK to be sent | |
177 | */ | |
178 | static void nic_mbx_send_nack(struct nicpf *nic, int vf) | |
179 | { | |
180 | union nic_mbx mbx = {}; | |
181 | ||
182 | mbx.msg.msg = NIC_MBOX_MSG_NACK; | |
183 | nic_send_msg_to_vf(nic, vf, &mbx); | |
184 | } | |
185 | ||
186 | /* Flush all in flight receive packets to memory and | |
187 | * bring down an active RQ | |
188 | */ | |
189 | static int nic_rcv_queue_sw_sync(struct nicpf *nic) | |
190 | { | |
191 | u16 timeout = ~0x00; | |
192 | ||
193 | nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); | |
194 | /* Wait till sync cycle is finished */ | |
195 | while (timeout) { | |
196 | if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) | |
197 | break; | |
198 | timeout--; | |
199 | } | |
200 | nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); | |
201 | if (!timeout) { | |
202 | dev_err(&nic->pdev->dev, "Receive queue software sync failed"); | |
203 | return 1; | |
204 | } | |
205 | return 0; | |
206 | } | |
207 | ||
208 | /* Get BGX Rx/Tx stats and respond to VF's request */ | |
209 | static void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) | |
210 | { | |
211 | int bgx_idx, lmac; | |
212 | union nic_mbx mbx = {}; | |
213 | ||
214 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); | |
215 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); | |
216 | ||
217 | mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; | |
218 | mbx.bgx_stats.vf_id = bgx->vf_id; | |
219 | mbx.bgx_stats.rx = bgx->rx; | |
220 | mbx.bgx_stats.idx = bgx->idx; | |
221 | if (bgx->rx) | |
222 | mbx.bgx_stats.stats = bgx_get_rx_stats(nic->node, bgx_idx, | |
223 | lmac, bgx->idx); | |
224 | else | |
225 | mbx.bgx_stats.stats = bgx_get_tx_stats(nic->node, bgx_idx, | |
226 | lmac, bgx->idx); | |
227 | nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); | |
228 | } | |
229 | ||
230 | /* Update hardware min/max frame size */ | |
231 | static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) | |
232 | { | |
233 | if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) { | |
234 | dev_err(&nic->pdev->dev, | |
235 | "Invalid MTU setting from VF%d rejected, should be between %d and %d\n", | |
236 | vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS); | |
237 | return 1; | |
238 | } | |
239 | new_frs += ETH_HLEN; | |
240 | if (new_frs <= nic->pkind.maxlen) | |
241 | return 0; | |
242 | ||
243 | nic->pkind.maxlen = new_frs; | |
244 | nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(u64 *)&nic->pkind); | |
245 | return 0; | |
246 | } | |
247 | ||
248 | /* Set minimum transmit packet size */ | |
249 | static void nic_set_tx_pkt_pad(struct nicpf *nic, int size) | |
250 | { | |
251 | int lmac; | |
252 | u64 lmac_cfg; | |
253 | ||
254 | /* Max value that can be set is 60 */ | |
255 | if (size > 60) | |
256 | size = 60; | |
257 | ||
258 | for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) { | |
259 | lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); | |
260 | lmac_cfg &= ~(0xF << 2); | |
261 | lmac_cfg |= ((size / 4) << 2); | |
262 | nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); | |
263 | } | |
264 | } | |
265 | ||
266 | /* Function to check number of LMACs present and set VF::LMAC mapping. | |
267 | * Mapping will be used while initializing channels. | |
268 | */ | |
269 | static void nic_set_lmac_vf_mapping(struct nicpf *nic) | |
270 | { | |
271 | unsigned bgx_map = bgx_get_map(nic->node); | |
272 | int bgx, next_bgx_lmac = 0; | |
273 | int lmac, lmac_cnt = 0; | |
274 | u64 lmac_credit; | |
275 | ||
276 | nic->num_vf_en = 0; | |
277 | ||
278 | for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) { | |
279 | if (!(bgx_map & (1 << bgx))) | |
280 | continue; | |
281 | lmac_cnt = bgx_get_lmac_count(nic->node, bgx); | |
282 | for (lmac = 0; lmac < lmac_cnt; lmac++) | |
283 | nic->vf_lmac_map[next_bgx_lmac++] = | |
284 | NIC_SET_VF_LMAC_MAP(bgx, lmac); | |
285 | nic->num_vf_en += lmac_cnt; | |
286 | ||
287 | /* Program LMAC credits */ | |
288 | lmac_credit = (1ull << 1); /* channel credit enable */ | |
289 | lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ | |
290 | /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ | |
291 | lmac_credit |= (((((48 * 1024) / lmac_cnt) - | |
292 | NIC_HW_MAX_FRS) / 16) << 12); | |
293 | lmac = bgx * MAX_LMAC_PER_BGX; | |
294 | for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) | |
295 | nic_reg_write(nic, | |
296 | NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), | |
297 | lmac_credit); | |
298 | } | |
299 | } | |
300 | ||
301 | #define BGX0_BLOCK 8 | |
302 | #define BGX1_BLOCK 9 | |
303 | ||
304 | static void nic_init_hw(struct nicpf *nic) | |
305 | { | |
306 | int i; | |
4c0b6eaf | 307 | u64 cqm_cfg; |
4863dea3 | 308 | |
4863dea3 SG |
309 | /* Enable NIC HW block */ |
310 | nic_reg_write(nic, NIC_PF_CFG, 0x3); | |
311 | ||
312 | /* Enable backpressure */ | |
313 | nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); | |
314 | ||
315 | /* Disable TNS mode on both interfaces */ | |
316 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, | |
317 | (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); | |
318 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), | |
319 | (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); | |
320 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, | |
321 | (1ULL << 63) | BGX0_BLOCK); | |
322 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), | |
323 | (1ULL << 63) | BGX1_BLOCK); | |
324 | ||
325 | /* PKIND configuration */ | |
326 | nic->pkind.minlen = 0; | |
327 | nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN; | |
328 | nic->pkind.lenerr_en = 1; | |
329 | nic->pkind.rx_hdr = 0; | |
330 | nic->pkind.hdr_sl = 0; | |
331 | ||
332 | for (i = 0; i < NIC_MAX_PKIND; i++) | |
333 | nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), | |
334 | *(u64 *)&nic->pkind); | |
335 | ||
336 | nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); | |
337 | ||
338 | /* Timer config */ | |
339 | nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); | |
aa2e259b SG |
340 | |
341 | /* Enable VLAN ethertype matching and stripping */ | |
342 | nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, | |
343 | (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); | |
4c0b6eaf SG |
344 | |
345 | /* Check if HW expected value is higher (could be in future chips) */ | |
346 | cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); | |
347 | if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) | |
348 | nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); | |
4863dea3 SG |
349 | } |
350 | ||
351 | /* Channel parse index configuration */ | |
352 | static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) | |
353 | { | |
354 | u32 vnic, bgx, lmac, chan; | |
355 | u32 padd, cpi_count = 0; | |
356 | u64 cpi_base, cpi, rssi_base, rssi; | |
357 | u8 qset, rq_idx = 0; | |
358 | ||
359 | vnic = cfg->vf_id; | |
360 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); | |
361 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); | |
362 | ||
363 | chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); | |
364 | cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX); | |
365 | rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX); | |
366 | ||
367 | /* Rx channel configuration */ | |
368 | nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), | |
369 | (1ull << 63) | (vnic << 0)); | |
370 | nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), | |
371 | ((u64)cfg->cpi_alg << 62) | (cpi_base << 48)); | |
372 | ||
373 | if (cfg->cpi_alg == CPI_ALG_NONE) | |
374 | cpi_count = 1; | |
375 | else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ | |
376 | cpi_count = 8; | |
377 | else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ | |
378 | cpi_count = 16; | |
379 | else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ | |
380 | cpi_count = NIC_MAX_CPI_PER_LMAC; | |
381 | ||
382 | /* RSS Qset, Qidx mapping */ | |
383 | qset = cfg->vf_id; | |
384 | rssi = rssi_base; | |
385 | for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { | |
386 | nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), | |
387 | (qset << 3) | rq_idx); | |
388 | rq_idx++; | |
389 | } | |
390 | ||
391 | rssi = 0; | |
392 | cpi = cpi_base; | |
393 | for (; cpi < (cpi_base + cpi_count); cpi++) { | |
394 | /* Determine port to channel adder */ | |
395 | if (cfg->cpi_alg != CPI_ALG_DIFF) | |
396 | padd = cpi % cpi_count; | |
397 | else | |
398 | padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ | |
399 | ||
400 | /* Leave RSS_SIZE as '0' to disable RSS */ | |
40fb5f8a | 401 | if (pass1_silicon(nic->pdev)) { |
34411b68 TS |
402 | nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), |
403 | (vnic << 24) | (padd << 16) | | |
404 | (rssi_base + rssi)); | |
405 | } else { | |
406 | /* Set MPI_ALG to '0' to disable MCAM parsing */ | |
407 | nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), | |
408 | (padd << 16)); | |
409 | /* MPI index is same as CPI if MPI_ALG is not enabled */ | |
410 | nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), | |
411 | (vnic << 24) | (rssi_base + rssi)); | |
412 | } | |
4863dea3 SG |
413 | |
414 | if ((rssi + 1) >= cfg->rq_cnt) | |
415 | continue; | |
416 | ||
417 | if (cfg->cpi_alg == CPI_ALG_VLAN) | |
418 | rssi++; | |
419 | else if (cfg->cpi_alg == CPI_ALG_VLAN16) | |
420 | rssi = ((cpi - cpi_base) & 0xe) >> 1; | |
421 | else if (cfg->cpi_alg == CPI_ALG_DIFF) | |
422 | rssi = ((cpi - cpi_base) & 0x38) >> 3; | |
423 | } | |
424 | nic->cpi_base[cfg->vf_id] = cpi_base; | |
34411b68 | 425 | nic->rssi_base[cfg->vf_id] = rssi_base; |
4863dea3 SG |
426 | } |
427 | ||
428 | /* Responsds to VF with its RSS indirection table size */ | |
429 | static void nic_send_rss_size(struct nicpf *nic, int vf) | |
430 | { | |
431 | union nic_mbx mbx = {}; | |
432 | u64 *msg; | |
433 | ||
434 | msg = (u64 *)&mbx; | |
435 | ||
436 | mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE; | |
437 | mbx.rss_size.ind_tbl_size = nic->rss_ind_tbl_size; | |
438 | nic_send_msg_to_vf(nic, vf, &mbx); | |
439 | } | |
440 | ||
441 | /* Receive side scaling configuration | |
442 | * configure: | |
443 | * - RSS index | |
444 | * - indir table i.e hash::RQ mapping | |
445 | * - no of hash bits to consider | |
446 | */ | |
447 | static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) | |
448 | { | |
449 | u8 qset, idx = 0; | |
450 | u64 cpi_cfg, cpi_base, rssi_base, rssi; | |
34411b68 | 451 | u64 idx_addr; |
4863dea3 | 452 | |
34411b68 | 453 | rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset; |
4863dea3 SG |
454 | |
455 | rssi = rssi_base; | |
456 | qset = cfg->vf_id; | |
457 | ||
458 | for (; rssi < (rssi_base + cfg->tbl_len); rssi++) { | |
92dc8769 SG |
459 | u8 svf = cfg->ind_tbl[idx] >> 3; |
460 | ||
461 | if (svf) | |
462 | qset = nic->vf_sqs[cfg->vf_id][svf - 1]; | |
463 | else | |
464 | qset = cfg->vf_id; | |
4863dea3 SG |
465 | nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), |
466 | (qset << 3) | (cfg->ind_tbl[idx] & 0x7)); | |
467 | idx++; | |
468 | } | |
469 | ||
34411b68 | 470 | cpi_base = nic->cpi_base[cfg->vf_id]; |
40fb5f8a | 471 | if (pass1_silicon(nic->pdev)) |
34411b68 TS |
472 | idx_addr = NIC_PF_CPI_0_2047_CFG; |
473 | else | |
474 | idx_addr = NIC_PF_MPI_0_2047_CFG; | |
475 | cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3)); | |
4863dea3 SG |
476 | cpi_cfg &= ~(0xFULL << 20); |
477 | cpi_cfg |= (cfg->hash_bits << 20); | |
34411b68 | 478 | nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg); |
4863dea3 SG |
479 | } |
480 | ||
481 | /* 4 level transmit side scheduler configutation | |
482 | * for TNS bypass mode | |
483 | * | |
484 | * Sample configuration for SQ0 | |
485 | * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 | |
486 | * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 | |
487 | * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 | |
488 | * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 | |
489 | * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 | |
490 | * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 | |
491 | * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 | |
492 | * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 | |
493 | */ | |
92dc8769 SG |
494 | static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, |
495 | struct sq_cfg_msg *sq) | |
4863dea3 SG |
496 | { |
497 | u32 bgx, lmac, chan; | |
498 | u32 tl2, tl3, tl4; | |
499 | u32 rr_quantum; | |
92dc8769 SG |
500 | u8 sq_idx = sq->sq_num; |
501 | u8 pqs_vnic; | |
3e29adba | 502 | int svf; |
92dc8769 SG |
503 | |
504 | if (sq->sqs_mode) | |
505 | pqs_vnic = nic->pqs_vf[vnic]; | |
506 | else | |
507 | pqs_vnic = vnic; | |
508 | ||
509 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); | |
510 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); | |
4863dea3 | 511 | |
4863dea3 SG |
512 | /* 24 bytes for FCS, IPG and preamble */ |
513 | rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); | |
514 | ||
3e29adba SG |
515 | if (!sq->sqs_mode) { |
516 | tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX); | |
517 | } else { | |
518 | for (svf = 0; svf < MAX_SQS_PER_VF; svf++) { | |
519 | if (nic->vf_sqs[pqs_vnic][svf] == vnic) | |
520 | break; | |
521 | } | |
522 | tl4 = (MAX_LMAC_PER_BGX * NIC_TL4_PER_LMAC); | |
523 | tl4 += (lmac * NIC_TL4_PER_LMAC * MAX_SQS_PER_VF); | |
524 | tl4 += (svf * NIC_TL4_PER_LMAC); | |
525 | tl4 += (bgx * NIC_TL4_PER_BGX); | |
526 | } | |
4863dea3 | 527 | tl4 += sq_idx; |
92dc8769 | 528 | |
4863dea3 SG |
529 | tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3); |
530 | nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | | |
531 | ((u64)vnic << NIC_QS_ID_SHIFT) | | |
532 | ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4); | |
533 | nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), | |
534 | ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum); | |
535 | ||
536 | nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); | |
537 | chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); | |
538 | nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); | |
539 | /* Enable backpressure on the channel */ | |
540 | nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); | |
541 | ||
542 | tl2 = tl3 >> 2; | |
543 | nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); | |
544 | nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); | |
545 | /* No priorities as of now */ | |
546 | nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); | |
547 | } | |
548 | ||
92dc8769 SG |
549 | /* Send primary nicvf pointer to secondary QS's VF */ |
550 | static void nic_send_pnicvf(struct nicpf *nic, int sqs) | |
551 | { | |
552 | union nic_mbx mbx = {}; | |
553 | ||
554 | mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; | |
555 | mbx.nicvf.nicvf = nic->nicvf[nic->pqs_vf[sqs]]; | |
556 | nic_send_msg_to_vf(nic, sqs, &mbx); | |
557 | } | |
558 | ||
559 | /* Send SQS's nicvf pointer to primary QS's VF */ | |
560 | static void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf) | |
561 | { | |
562 | union nic_mbx mbx = {}; | |
563 | int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id]; | |
564 | ||
565 | mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; | |
566 | mbx.nicvf.sqs_id = nicvf->sqs_id; | |
567 | mbx.nicvf.nicvf = nic->nicvf[sqs_id]; | |
568 | nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx); | |
569 | } | |
570 | ||
571 | /* Find next available Qset that can be assigned as a | |
572 | * secondary Qset to a VF. | |
573 | */ | |
574 | static int nic_nxt_avail_sqs(struct nicpf *nic) | |
575 | { | |
576 | int sqs; | |
577 | ||
578 | for (sqs = 0; sqs < nic->num_sqs_en; sqs++) { | |
579 | if (!nic->sqs_used[sqs]) | |
580 | nic->sqs_used[sqs] = true; | |
581 | else | |
582 | continue; | |
583 | return sqs + nic->num_vf_en; | |
584 | } | |
585 | return -1; | |
586 | } | |
587 | ||
588 | /* Allocate additional Qsets for requested VF */ | |
589 | static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) | |
590 | { | |
591 | union nic_mbx mbx = {}; | |
592 | int idx, alloc_qs = 0; | |
593 | int sqs_id; | |
594 | ||
595 | if (!nic->num_sqs_en) | |
596 | goto send_mbox; | |
597 | ||
598 | for (idx = 0; idx < sqs->qs_count; idx++) { | |
599 | sqs_id = nic_nxt_avail_sqs(nic); | |
600 | if (sqs_id < 0) | |
601 | break; | |
602 | nic->vf_sqs[sqs->vf_id][idx] = sqs_id; | |
603 | nic->pqs_vf[sqs_id] = sqs->vf_id; | |
604 | alloc_qs++; | |
605 | } | |
606 | ||
607 | send_mbox: | |
608 | mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; | |
609 | mbx.sqs_alloc.vf_id = sqs->vf_id; | |
610 | mbx.sqs_alloc.qs_count = alloc_qs; | |
611 | nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); | |
612 | } | |
613 | ||
d77a2384 SG |
614 | static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) |
615 | { | |
616 | int bgx_idx, lmac_idx; | |
617 | ||
618 | if (lbk->vf_id > MAX_LMAC) | |
619 | return -1; | |
620 | ||
621 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); | |
622 | lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); | |
623 | ||
624 | bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); | |
625 | ||
626 | return 0; | |
627 | } | |
628 | ||
f406ce42 PF |
629 | static void nic_enable_vf(struct nicpf *nic, int vf, bool enable) |
630 | { | |
631 | int bgx, lmac; | |
632 | ||
633 | nic->vf_enabled[vf] = enable; | |
634 | ||
635 | if (vf >= nic->num_vf_en) | |
636 | return; | |
637 | ||
638 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
639 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
640 | ||
641 | bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable); | |
642 | } | |
643 | ||
4863dea3 SG |
644 | /* Interrupt handler to handle mailbox messages from VFs */ |
645 | static void nic_handle_mbx_intr(struct nicpf *nic, int vf) | |
646 | { | |
647 | union nic_mbx mbx = {}; | |
648 | u64 *mbx_data; | |
649 | u64 mbx_addr; | |
650 | u64 reg_addr; | |
92dc8769 | 651 | u64 cfg; |
4863dea3 SG |
652 | int bgx, lmac; |
653 | int i; | |
654 | int ret = 0; | |
655 | ||
656 | nic->mbx_lock[vf] = true; | |
657 | ||
658 | mbx_addr = nic_get_mbx_addr(vf); | |
659 | mbx_data = (u64 *)&mbx; | |
660 | ||
661 | for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { | |
662 | *mbx_data = nic_reg_read(nic, mbx_addr); | |
663 | mbx_data++; | |
664 | mbx_addr += sizeof(u64); | |
665 | } | |
666 | ||
667 | dev_dbg(&nic->pdev->dev, "%s: Mailbox msg %d from VF%d\n", | |
668 | __func__, mbx.msg.msg, vf); | |
669 | switch (mbx.msg.msg) { | |
670 | case NIC_MBOX_MSG_READY: | |
671 | nic_mbx_send_ready(nic, vf); | |
92dc8769 SG |
672 | if (vf < MAX_LMAC) { |
673 | nic->link[vf] = 0; | |
674 | nic->duplex[vf] = 0; | |
675 | nic->speed[vf] = 0; | |
676 | } | |
4863dea3 SG |
677 | ret = 1; |
678 | break; | |
679 | case NIC_MBOX_MSG_QS_CFG: | |
680 | reg_addr = NIC_PF_QSET_0_127_CFG | | |
681 | (mbx.qs.num << NIC_QS_ID_SHIFT); | |
92dc8769 SG |
682 | cfg = mbx.qs.cfg; |
683 | /* Check if its a secondary Qset */ | |
684 | if (vf >= nic->num_vf_en) { | |
685 | cfg = cfg & (~0x7FULL); | |
686 | /* Assign this Qset to primary Qset's VF */ | |
687 | cfg |= nic->pqs_vf[vf]; | |
688 | } | |
689 | nic_reg_write(nic, reg_addr, cfg); | |
4863dea3 SG |
690 | break; |
691 | case NIC_MBOX_MSG_RQ_CFG: | |
692 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | | |
693 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
694 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
695 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
696 | break; | |
697 | case NIC_MBOX_MSG_RQ_BP_CFG: | |
698 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | | |
699 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
700 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
701 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
702 | break; | |
703 | case NIC_MBOX_MSG_RQ_SW_SYNC: | |
704 | ret = nic_rcv_queue_sw_sync(nic); | |
705 | break; | |
706 | case NIC_MBOX_MSG_RQ_DROP_CFG: | |
707 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | | |
708 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
709 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
710 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
711 | break; | |
712 | case NIC_MBOX_MSG_SQ_CFG: | |
713 | reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | | |
714 | (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | | |
715 | (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); | |
716 | nic_reg_write(nic, reg_addr, mbx.sq.cfg); | |
92dc8769 | 717 | nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); |
4863dea3 SG |
718 | break; |
719 | case NIC_MBOX_MSG_SET_MAC: | |
92dc8769 SG |
720 | if (vf >= nic->num_vf_en) |
721 | break; | |
4863dea3 SG |
722 | lmac = mbx.mac.vf_id; |
723 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); | |
724 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); | |
e610cb32 | 725 | bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); |
4863dea3 SG |
726 | break; |
727 | case NIC_MBOX_MSG_SET_MAX_FRS: | |
728 | ret = nic_update_hw_frs(nic, mbx.frs.max_frs, | |
729 | mbx.frs.vf_id); | |
730 | break; | |
731 | case NIC_MBOX_MSG_CPI_CFG: | |
732 | nic_config_cpi(nic, &mbx.cpi_cfg); | |
733 | break; | |
734 | case NIC_MBOX_MSG_RSS_SIZE: | |
735 | nic_send_rss_size(nic, vf); | |
736 | goto unlock; | |
737 | case NIC_MBOX_MSG_RSS_CFG: | |
738 | case NIC_MBOX_MSG_RSS_CFG_CONT: | |
739 | nic_config_rss(nic, &mbx.rss_cfg); | |
740 | break; | |
741 | case NIC_MBOX_MSG_CFG_DONE: | |
742 | /* Last message of VF config msg sequence */ | |
f406ce42 | 743 | nic_enable_vf(nic, vf, true); |
4863dea3 SG |
744 | goto unlock; |
745 | case NIC_MBOX_MSG_SHUTDOWN: | |
746 | /* First msg in VF teardown sequence */ | |
92dc8769 SG |
747 | if (vf >= nic->num_vf_en) |
748 | nic->sqs_used[vf - nic->num_vf_en] = false; | |
749 | nic->pqs_vf[vf] = 0; | |
f406ce42 | 750 | nic_enable_vf(nic, vf, false); |
92dc8769 SG |
751 | break; |
752 | case NIC_MBOX_MSG_ALLOC_SQS: | |
753 | nic_alloc_sqs(nic, &mbx.sqs_alloc); | |
754 | goto unlock; | |
755 | case NIC_MBOX_MSG_NICVF_PTR: | |
756 | nic->nicvf[vf] = mbx.nicvf.nicvf; | |
4863dea3 | 757 | break; |
92dc8769 SG |
758 | case NIC_MBOX_MSG_PNICVF_PTR: |
759 | nic_send_pnicvf(nic, vf); | |
760 | goto unlock; | |
761 | case NIC_MBOX_MSG_SNICVF_PTR: | |
762 | nic_send_snicvf(nic, &mbx.nicvf); | |
763 | goto unlock; | |
4863dea3 SG |
764 | case NIC_MBOX_MSG_BGX_STATS: |
765 | nic_get_bgx_stats(nic, &mbx.bgx_stats); | |
766 | goto unlock; | |
d77a2384 SG |
767 | case NIC_MBOX_MSG_LOOPBACK: |
768 | ret = nic_config_loopback(nic, &mbx.lbk); | |
769 | break; | |
4863dea3 SG |
770 | default: |
771 | dev_err(&nic->pdev->dev, | |
772 | "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); | |
773 | break; | |
774 | } | |
775 | ||
776 | if (!ret) | |
777 | nic_mbx_send_ack(nic, vf); | |
778 | else if (mbx.msg.msg != NIC_MBOX_MSG_READY) | |
779 | nic_mbx_send_nack(nic, vf); | |
780 | unlock: | |
781 | nic->mbx_lock[vf] = false; | |
782 | } | |
783 | ||
784 | static void nic_mbx_intr_handler (struct nicpf *nic, int mbx) | |
785 | { | |
786 | u64 intr; | |
787 | u8 vf, vf_per_mbx_reg = 64; | |
788 | ||
789 | intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); | |
790 | dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); | |
791 | for (vf = 0; vf < vf_per_mbx_reg; vf++) { | |
792 | if (intr & (1ULL << vf)) { | |
793 | dev_dbg(&nic->pdev->dev, "Intr from VF %d\n", | |
794 | vf + (mbx * vf_per_mbx_reg)); | |
92dc8769 | 795 | |
4863dea3 SG |
796 | nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg)); |
797 | nic_clear_mbx_intr(nic, vf, mbx); | |
798 | } | |
799 | } | |
800 | } | |
801 | ||
802 | static irqreturn_t nic_mbx0_intr_handler (int irq, void *nic_irq) | |
803 | { | |
804 | struct nicpf *nic = (struct nicpf *)nic_irq; | |
805 | ||
806 | nic_mbx_intr_handler(nic, 0); | |
807 | ||
808 | return IRQ_HANDLED; | |
809 | } | |
810 | ||
811 | static irqreturn_t nic_mbx1_intr_handler (int irq, void *nic_irq) | |
812 | { | |
813 | struct nicpf *nic = (struct nicpf *)nic_irq; | |
814 | ||
815 | nic_mbx_intr_handler(nic, 1); | |
816 | ||
817 | return IRQ_HANDLED; | |
818 | } | |
819 | ||
820 | static int nic_enable_msix(struct nicpf *nic) | |
821 | { | |
822 | int i, ret; | |
823 | ||
824 | nic->num_vec = NIC_PF_MSIX_VECTORS; | |
825 | ||
826 | for (i = 0; i < nic->num_vec; i++) | |
827 | nic->msix_entries[i].entry = i; | |
828 | ||
829 | ret = pci_enable_msix(nic->pdev, nic->msix_entries, nic->num_vec); | |
830 | if (ret) { | |
831 | dev_err(&nic->pdev->dev, | |
832 | "Request for #%d msix vectors failed\n", | |
833 | nic->num_vec); | |
834 | return ret; | |
835 | } | |
836 | ||
837 | nic->msix_enabled = 1; | |
838 | return 0; | |
839 | } | |
840 | ||
841 | static void nic_disable_msix(struct nicpf *nic) | |
842 | { | |
843 | if (nic->msix_enabled) { | |
844 | pci_disable_msix(nic->pdev); | |
845 | nic->msix_enabled = 0; | |
846 | nic->num_vec = 0; | |
847 | } | |
848 | } | |
849 | ||
850 | static void nic_free_all_interrupts(struct nicpf *nic) | |
851 | { | |
852 | int irq; | |
853 | ||
854 | for (irq = 0; irq < nic->num_vec; irq++) { | |
855 | if (nic->irq_allocated[irq]) | |
856 | free_irq(nic->msix_entries[irq].vector, nic); | |
857 | nic->irq_allocated[irq] = false; | |
858 | } | |
859 | } | |
860 | ||
861 | static int nic_register_interrupts(struct nicpf *nic) | |
862 | { | |
863 | int ret; | |
864 | ||
865 | /* Enable MSI-X */ | |
866 | ret = nic_enable_msix(nic); | |
867 | if (ret) | |
868 | return ret; | |
869 | ||
870 | /* Register mailbox interrupt handlers */ | |
871 | ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX0].vector, | |
872 | nic_mbx0_intr_handler, 0, "NIC Mbox0", nic); | |
873 | if (ret) | |
874 | goto fail; | |
875 | ||
876 | nic->irq_allocated[NIC_PF_INTR_ID_MBOX0] = true; | |
877 | ||
878 | ret = request_irq(nic->msix_entries[NIC_PF_INTR_ID_MBOX1].vector, | |
879 | nic_mbx1_intr_handler, 0, "NIC Mbox1", nic); | |
880 | if (ret) | |
881 | goto fail; | |
882 | ||
883 | nic->irq_allocated[NIC_PF_INTR_ID_MBOX1] = true; | |
884 | ||
885 | /* Enable mailbox interrupt */ | |
886 | nic_enable_mbx_intr(nic); | |
887 | return 0; | |
888 | ||
889 | fail: | |
890 | dev_err(&nic->pdev->dev, "Request irq failed\n"); | |
891 | nic_free_all_interrupts(nic); | |
892 | return ret; | |
893 | } | |
894 | ||
895 | static void nic_unregister_interrupts(struct nicpf *nic) | |
896 | { | |
897 | nic_free_all_interrupts(nic); | |
898 | nic_disable_msix(nic); | |
899 | } | |
900 | ||
92dc8769 SG |
901 | static int nic_num_sqs_en(struct nicpf *nic, int vf_en) |
902 | { | |
903 | int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE; | |
904 | u16 total_vf; | |
905 | ||
906 | /* Check if its a multi-node environment */ | |
907 | if (nr_node_ids > 1) | |
908 | sqs_per_vf = MAX_SQS_PER_VF; | |
909 | ||
910 | pos = pci_find_ext_capability(nic->pdev, PCI_EXT_CAP_ID_SRIOV); | |
911 | pci_read_config_word(nic->pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf); | |
912 | return min(total_vf - vf_en, vf_en * sqs_per_vf); | |
913 | } | |
914 | ||
4863dea3 SG |
915 | static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) |
916 | { | |
917 | int pos = 0; | |
92dc8769 | 918 | int vf_en; |
4863dea3 SG |
919 | int err; |
920 | u16 total_vf_cnt; | |
921 | ||
922 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); | |
923 | if (!pos) { | |
924 | dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n"); | |
925 | return -ENODEV; | |
926 | } | |
927 | ||
928 | pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt); | |
929 | if (total_vf_cnt < nic->num_vf_en) | |
930 | nic->num_vf_en = total_vf_cnt; | |
931 | ||
932 | if (!total_vf_cnt) | |
933 | return 0; | |
934 | ||
92dc8769 SG |
935 | vf_en = nic->num_vf_en; |
936 | nic->num_sqs_en = nic_num_sqs_en(nic, nic->num_vf_en); | |
937 | vf_en += nic->num_sqs_en; | |
938 | ||
939 | err = pci_enable_sriov(pdev, vf_en); | |
4863dea3 SG |
940 | if (err) { |
941 | dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", | |
92dc8769 | 942 | vf_en); |
4863dea3 SG |
943 | nic->num_vf_en = 0; |
944 | return err; | |
945 | } | |
946 | ||
947 | dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", | |
92dc8769 | 948 | vf_en); |
4863dea3 SG |
949 | |
950 | nic->flags |= NIC_SRIOV_ENABLED; | |
951 | return 0; | |
952 | } | |
953 | ||
954 | /* Poll for BGX LMAC link status and update corresponding VF | |
955 | * if there is a change, valid only if internal L2 switch | |
956 | * is not present otherwise VF link is always treated as up | |
957 | */ | |
958 | static void nic_poll_for_link(struct work_struct *work) | |
959 | { | |
960 | union nic_mbx mbx = {}; | |
961 | struct nicpf *nic; | |
962 | struct bgx_link_status link; | |
963 | u8 vf, bgx, lmac; | |
964 | ||
965 | nic = container_of(work, struct nicpf, dwork.work); | |
966 | ||
967 | mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; | |
968 | ||
f406ce42 | 969 | for (vf = 0; vf < nic->num_vf_en; vf++) { |
4863dea3 SG |
970 | /* Poll only if VF is UP */ |
971 | if (!nic->vf_enabled[vf]) | |
972 | continue; | |
973 | ||
974 | /* Get BGX, LMAC indices for the VF */ | |
975 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
976 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
977 | /* Get interface link status */ | |
978 | bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); | |
979 | ||
980 | /* Inform VF only if link status changed */ | |
981 | if (nic->link[vf] == link.link_up) | |
982 | continue; | |
983 | ||
984 | if (!nic->mbx_lock[vf]) { | |
985 | nic->link[vf] = link.link_up; | |
986 | nic->duplex[vf] = link.duplex; | |
987 | nic->speed[vf] = link.speed; | |
988 | ||
989 | /* Send a mbox message to VF with current link status */ | |
990 | mbx.link_status.link_up = link.link_up; | |
991 | mbx.link_status.duplex = link.duplex; | |
992 | mbx.link_status.speed = link.speed; | |
993 | nic_send_msg_to_vf(nic, vf, &mbx); | |
994 | } | |
995 | } | |
996 | queue_delayed_work(nic->check_link, &nic->dwork, HZ * 2); | |
997 | } | |
998 | ||
999 | static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1000 | { | |
1001 | struct device *dev = &pdev->dev; | |
1002 | struct nicpf *nic; | |
1003 | int err; | |
1004 | ||
1005 | BUILD_BUG_ON(sizeof(union nic_mbx) > 16); | |
1006 | ||
1007 | nic = devm_kzalloc(dev, sizeof(*nic), GFP_KERNEL); | |
1008 | if (!nic) | |
1009 | return -ENOMEM; | |
1010 | ||
1011 | pci_set_drvdata(pdev, nic); | |
1012 | ||
1013 | nic->pdev = pdev; | |
1014 | ||
1015 | err = pci_enable_device(pdev); | |
1016 | if (err) { | |
1017 | dev_err(dev, "Failed to enable PCI device\n"); | |
1018 | pci_set_drvdata(pdev, NULL); | |
1019 | return err; | |
1020 | } | |
1021 | ||
1022 | err = pci_request_regions(pdev, DRV_NAME); | |
1023 | if (err) { | |
1024 | dev_err(dev, "PCI request regions failed 0x%x\n", err); | |
1025 | goto err_disable_device; | |
1026 | } | |
1027 | ||
1028 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); | |
1029 | if (err) { | |
1030 | dev_err(dev, "Unable to get usable DMA configuration\n"); | |
1031 | goto err_release_regions; | |
1032 | } | |
1033 | ||
1034 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); | |
1035 | if (err) { | |
1036 | dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n"); | |
1037 | goto err_release_regions; | |
1038 | } | |
1039 | ||
1040 | /* MAP PF's configuration registers */ | |
1041 | nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); | |
1042 | if (!nic->reg_base) { | |
1043 | dev_err(dev, "Cannot map config register space, aborting\n"); | |
1044 | err = -ENOMEM; | |
1045 | goto err_release_regions; | |
1046 | } | |
1047 | ||
d768b678 | 1048 | nic->node = nic_get_node_id(pdev); |
4863dea3 SG |
1049 | |
1050 | nic_set_lmac_vf_mapping(nic); | |
1051 | ||
1052 | /* Initialize hardware */ | |
1053 | nic_init_hw(nic); | |
1054 | ||
1055 | /* Set RSS TBL size for each VF */ | |
1056 | nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; | |
1057 | ||
1058 | /* Register interrupts */ | |
1059 | err = nic_register_interrupts(nic); | |
1060 | if (err) | |
1061 | goto err_release_regions; | |
1062 | ||
1063 | /* Configure SRIOV */ | |
1064 | err = nic_sriov_init(pdev, nic); | |
1065 | if (err) | |
1066 | goto err_unregister_interrupts; | |
1067 | ||
1068 | /* Register a physical link status poll fn() */ | |
1069 | nic->check_link = alloc_workqueue("check_link_status", | |
1070 | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); | |
1071 | if (!nic->check_link) { | |
1072 | err = -ENOMEM; | |
1073 | goto err_disable_sriov; | |
1074 | } | |
1075 | ||
1076 | INIT_DELAYED_WORK(&nic->dwork, nic_poll_for_link); | |
1077 | queue_delayed_work(nic->check_link, &nic->dwork, 0); | |
1078 | ||
1079 | return 0; | |
1080 | ||
1081 | err_disable_sriov: | |
1082 | if (nic->flags & NIC_SRIOV_ENABLED) | |
1083 | pci_disable_sriov(pdev); | |
1084 | err_unregister_interrupts: | |
1085 | nic_unregister_interrupts(nic); | |
1086 | err_release_regions: | |
1087 | pci_release_regions(pdev); | |
1088 | err_disable_device: | |
1089 | pci_disable_device(pdev); | |
1090 | pci_set_drvdata(pdev, NULL); | |
1091 | return err; | |
1092 | } | |
1093 | ||
1094 | static void nic_remove(struct pci_dev *pdev) | |
1095 | { | |
1096 | struct nicpf *nic = pci_get_drvdata(pdev); | |
1097 | ||
1098 | if (nic->flags & NIC_SRIOV_ENABLED) | |
1099 | pci_disable_sriov(pdev); | |
1100 | ||
1101 | if (nic->check_link) { | |
1102 | /* Destroy work Queue */ | |
a7b1f535 | 1103 | cancel_delayed_work_sync(&nic->dwork); |
4863dea3 SG |
1104 | destroy_workqueue(nic->check_link); |
1105 | } | |
1106 | ||
1107 | nic_unregister_interrupts(nic); | |
1108 | pci_release_regions(pdev); | |
1109 | pci_disable_device(pdev); | |
1110 | pci_set_drvdata(pdev, NULL); | |
1111 | } | |
1112 | ||
1113 | static struct pci_driver nic_driver = { | |
1114 | .name = DRV_NAME, | |
1115 | .id_table = nic_id_table, | |
1116 | .probe = nic_probe, | |
1117 | .remove = nic_remove, | |
1118 | }; | |
1119 | ||
1120 | static int __init nic_init_module(void) | |
1121 | { | |
1122 | pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION); | |
1123 | ||
1124 | return pci_register_driver(&nic_driver); | |
1125 | } | |
1126 | ||
1127 | static void __exit nic_cleanup_module(void) | |
1128 | { | |
1129 | pci_unregister_driver(&nic_driver); | |
1130 | } | |
1131 | ||
1132 | module_init(nic_init_module); | |
1133 | module_exit(nic_cleanup_module); |