]>
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> | |
712c3185 | 14 | #include <linux/if_vlan.h> |
4863dea3 SG |
15 | |
16 | #include "nic_reg.h" | |
17 | #include "nic.h" | |
18 | #include "q_struct.h" | |
19 | #include "thunder_bgx.h" | |
20 | ||
21 | #define DRV_NAME "thunder-nic" | |
22 | #define DRV_VERSION "1.0" | |
23 | ||
a5c3d498 SG |
24 | struct hw_info { |
25 | u8 bgx_cnt; | |
26 | u8 chans_per_lmac; | |
27 | u8 chans_per_bgx; /* Rx/Tx chans */ | |
0025d93e SG |
28 | u8 chans_per_rgx; |
29 | u8 chans_per_lbk; | |
a5c3d498 SG |
30 | u16 cpi_cnt; |
31 | u16 rssi_cnt; | |
32 | u16 rss_ind_tbl_size; | |
33 | u16 tl4_cnt; | |
34 | u16 tl3_cnt; | |
35 | u8 tl2_cnt; | |
36 | u8 tl1_cnt; | |
37 | bool tl1_per_bgx; /* TL1 per BGX or per LMAC */ | |
38 | }; | |
39 | ||
4863dea3 SG |
40 | struct nicpf { |
41 | struct pci_dev *pdev; | |
a5c3d498 | 42 | struct hw_info *hw; |
4863dea3 SG |
43 | u8 node; |
44 | unsigned int flags; | |
45 | u8 num_vf_en; /* No of VF enabled */ | |
46 | bool vf_enabled[MAX_NUM_VFS_SUPPORTED]; | |
47 | void __iomem *reg_base; /* Register start address */ | |
92dc8769 SG |
48 | u8 num_sqs_en; /* Secondary qsets enabled */ |
49 | u64 nicvf[MAX_NUM_VFS_SUPPORTED]; | |
50 | u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF]; | |
51 | u8 pqs_vf[MAX_NUM_VFS_SUPPORTED]; | |
52 | bool sqs_used[MAX_NUM_VFS_SUPPORTED]; | |
4863dea3 SG |
53 | struct pkind_cfg pkind; |
54 | #define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF)) | |
55 | #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) | |
56 | #define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) | |
949b5331 | 57 | u8 *vf_lmac_map; |
4863dea3 SG |
58 | struct delayed_work dwork; |
59 | struct workqueue_struct *check_link; | |
949b5331 SG |
60 | u8 *link; |
61 | u8 *duplex; | |
62 | u32 *speed; | |
4863dea3 | 63 | u16 cpi_base[MAX_NUM_VFS_SUPPORTED]; |
34411b68 | 64 | u16 rssi_base[MAX_NUM_VFS_SUPPORTED]; |
4863dea3 SG |
65 | bool mbx_lock[MAX_NUM_VFS_SUPPORTED]; |
66 | ||
67 | /* MSI-X */ | |
68 | bool msix_enabled; | |
69 | u8 num_vec; | |
52358aad | 70 | struct msix_entry *msix_entries; |
4863dea3 | 71 | bool irq_allocated[NIC_PF_MSIX_VECTORS]; |
52358aad | 72 | char irq_name[NIC_PF_MSIX_VECTORS][20]; |
4863dea3 SG |
73 | }; |
74 | ||
75 | /* Supported devices */ | |
76 | static const struct pci_device_id nic_id_table[] = { | |
77 | { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) }, | |
78 | { 0, } /* end of table */ | |
79 | }; | |
80 | ||
81 | MODULE_AUTHOR("Sunil Goutham"); | |
82 | MODULE_DESCRIPTION("Cavium Thunder NIC Physical Function Driver"); | |
83 | MODULE_LICENSE("GPL v2"); | |
84 | MODULE_VERSION(DRV_VERSION); | |
85 | MODULE_DEVICE_TABLE(pci, nic_id_table); | |
86 | ||
87 | /* The Cavium ThunderX network controller can *only* be found in SoCs | |
88 | * containing the ThunderX ARM64 CPU implementation. All accesses to the device | |
89 | * registers on this platform are implicitly strongly ordered with respect | |
90 | * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use | |
91 | * with no memory barriers in this driver. The readq()/writeq() functions add | |
92 | * explicit ordering operation which in this case are redundant, and only | |
93 | * add overhead. | |
94 | */ | |
95 | ||
96 | /* Register read/write APIs */ | |
97 | static void nic_reg_write(struct nicpf *nic, u64 offset, u64 val) | |
98 | { | |
99 | writeq_relaxed(val, nic->reg_base + offset); | |
100 | } | |
101 | ||
102 | static u64 nic_reg_read(struct nicpf *nic, u64 offset) | |
103 | { | |
104 | return readq_relaxed(nic->reg_base + offset); | |
105 | } | |
106 | ||
107 | /* PF -> VF mailbox communication APIs */ | |
108 | static void nic_enable_mbx_intr(struct nicpf *nic) | |
109 | { | |
52358aad SG |
110 | int vf_cnt = pci_sriov_get_totalvfs(nic->pdev); |
111 | ||
112 | #define INTR_MASK(vfs) ((vfs < 64) ? (BIT_ULL(vfs) - 1) : (~0ull)) | |
113 | ||
114 | /* Clear it, to avoid spurious interrupts (if any) */ | |
115 | nic_reg_write(nic, NIC_PF_MAILBOX_INT, INTR_MASK(vf_cnt)); | |
116 | ||
117 | /* Enable mailbox interrupt for all VFs */ | |
118 | nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, INTR_MASK(vf_cnt)); | |
119 | /* One mailbox intr enable reg per 64 VFs */ | |
120 | if (vf_cnt > 64) { | |
121 | nic_reg_write(nic, NIC_PF_MAILBOX_INT + sizeof(u64), | |
122 | INTR_MASK(vf_cnt - 64)); | |
123 | nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), | |
124 | INTR_MASK(vf_cnt - 64)); | |
125 | } | |
4863dea3 SG |
126 | } |
127 | ||
128 | static void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) | |
129 | { | |
130 | nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf)); | |
131 | } | |
132 | ||
133 | static u64 nic_get_mbx_addr(int vf) | |
134 | { | |
135 | return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT); | |
136 | } | |
137 | ||
138 | /* Send a mailbox message to VF | |
139 | * @vf: vf to which this message to be sent | |
140 | * @mbx: Message to be sent | |
141 | */ | |
142 | static void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) | |
143 | { | |
144 | void __iomem *mbx_addr = nic->reg_base + nic_get_mbx_addr(vf); | |
145 | u64 *msg = (u64 *)mbx; | |
146 | ||
147 | /* In first revision HW, mbox interrupt is triggerred | |
148 | * when PF writes to MBOX(1), in next revisions when | |
149 | * PF writes to MBOX(0) | |
150 | */ | |
40fb5f8a | 151 | if (pass1_silicon(nic->pdev)) { |
4863dea3 SG |
152 | /* see the comment for nic_reg_write()/nic_reg_read() |
153 | * functions above | |
154 | */ | |
155 | writeq_relaxed(msg[0], mbx_addr); | |
156 | writeq_relaxed(msg[1], mbx_addr + 8); | |
157 | } else { | |
158 | writeq_relaxed(msg[1], mbx_addr + 8); | |
159 | writeq_relaxed(msg[0], mbx_addr); | |
160 | } | |
161 | } | |
162 | ||
163 | /* Responds to VF's READY message with VF's | |
164 | * ID, node, MAC address e.t.c | |
165 | * @vf: VF which sent READY message | |
166 | */ | |
167 | static void nic_mbx_send_ready(struct nicpf *nic, int vf) | |
168 | { | |
169 | union nic_mbx mbx = {}; | |
170 | int bgx_idx, lmac; | |
171 | const char *mac; | |
172 | ||
173 | mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; | |
174 | mbx.nic_cfg.vf_id = vf; | |
175 | ||
176 | mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; | |
177 | ||
949b5331 | 178 | if (vf < nic->num_vf_en) { |
92dc8769 SG |
179 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
180 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
4863dea3 | 181 | |
92dc8769 SG |
182 | mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); |
183 | if (mac) | |
184 | ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); | |
185 | } | |
186 | mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; | |
4863dea3 | 187 | mbx.nic_cfg.node_id = nic->node; |
d77a2384 | 188 | |
949b5331 | 189 | mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en; |
d77a2384 | 190 | |
4863dea3 SG |
191 | nic_send_msg_to_vf(nic, vf, &mbx); |
192 | } | |
193 | ||
194 | /* ACKs VF's mailbox message | |
195 | * @vf: VF to which ACK to be sent | |
196 | */ | |
197 | static void nic_mbx_send_ack(struct nicpf *nic, int vf) | |
198 | { | |
199 | union nic_mbx mbx = {}; | |
200 | ||
201 | mbx.msg.msg = NIC_MBOX_MSG_ACK; | |
202 | nic_send_msg_to_vf(nic, vf, &mbx); | |
203 | } | |
204 | ||
205 | /* NACKs VF's mailbox message that PF is not able to | |
206 | * complete the action | |
207 | * @vf: VF to which ACK to be sent | |
208 | */ | |
209 | static void nic_mbx_send_nack(struct nicpf *nic, int vf) | |
210 | { | |
211 | union nic_mbx mbx = {}; | |
212 | ||
213 | mbx.msg.msg = NIC_MBOX_MSG_NACK; | |
214 | nic_send_msg_to_vf(nic, vf, &mbx); | |
215 | } | |
216 | ||
217 | /* Flush all in flight receive packets to memory and | |
218 | * bring down an active RQ | |
219 | */ | |
220 | static int nic_rcv_queue_sw_sync(struct nicpf *nic) | |
221 | { | |
222 | u16 timeout = ~0x00; | |
223 | ||
224 | nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); | |
225 | /* Wait till sync cycle is finished */ | |
226 | while (timeout) { | |
227 | if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) | |
228 | break; | |
229 | timeout--; | |
230 | } | |
231 | nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); | |
232 | if (!timeout) { | |
233 | dev_err(&nic->pdev->dev, "Receive queue software sync failed"); | |
234 | return 1; | |
235 | } | |
236 | return 0; | |
237 | } | |
238 | ||
239 | /* Get BGX Rx/Tx stats and respond to VF's request */ | |
240 | static void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) | |
241 | { | |
242 | int bgx_idx, lmac; | |
243 | union nic_mbx mbx = {}; | |
244 | ||
245 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); | |
246 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); | |
247 | ||
248 | mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; | |
249 | mbx.bgx_stats.vf_id = bgx->vf_id; | |
250 | mbx.bgx_stats.rx = bgx->rx; | |
251 | mbx.bgx_stats.idx = bgx->idx; | |
252 | if (bgx->rx) | |
253 | mbx.bgx_stats.stats = bgx_get_rx_stats(nic->node, bgx_idx, | |
254 | lmac, bgx->idx); | |
255 | else | |
256 | mbx.bgx_stats.stats = bgx_get_tx_stats(nic->node, bgx_idx, | |
257 | lmac, bgx->idx); | |
258 | nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); | |
259 | } | |
260 | ||
261 | /* Update hardware min/max frame size */ | |
262 | static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) | |
263 | { | |
712c3185 SG |
264 | int bgx, lmac, lmac_cnt; |
265 | u64 lmac_credits; | |
266 | ||
267 | if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) | |
4863dea3 | 268 | return 1; |
4863dea3 | 269 | |
712c3185 SG |
270 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
271 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
272 | lmac += bgx * MAX_LMAC_PER_BGX; | |
273 | ||
274 | new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4; | |
275 | ||
276 | /* Update corresponding LMAC credits */ | |
277 | lmac_cnt = bgx_get_lmac_count(nic->node, bgx); | |
278 | lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8)); | |
279 | lmac_credits &= ~(0xFFFFFULL << 12); | |
280 | lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12); | |
281 | nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits); | |
282 | ||
283 | /* Enforce MTU in HW | |
284 | * This config is supported only from 88xx pass 2.0 onwards. | |
285 | */ | |
286 | if (!pass1_silicon(nic->pdev)) | |
287 | nic_reg_write(nic, | |
288 | NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs); | |
4863dea3 SG |
289 | return 0; |
290 | } | |
291 | ||
292 | /* Set minimum transmit packet size */ | |
293 | static void nic_set_tx_pkt_pad(struct nicpf *nic, int size) | |
294 | { | |
949b5331 SG |
295 | int lmac, max_lmac; |
296 | u16 sdevid; | |
4863dea3 SG |
297 | u64 lmac_cfg; |
298 | ||
57e81d44 SG |
299 | /* There is a issue in HW where-in while sending GSO sized |
300 | * pkts as part of TSO, if pkt len falls below this size | |
301 | * NIC will zero PAD packet and also updates IP total length. | |
302 | * Hence set this value to lessthan min pkt size of MAC+IP+TCP | |
303 | * headers, BGX will do the padding to transmit 64 byte pkt. | |
304 | */ | |
305 | if (size > 52) | |
306 | size = 52; | |
4863dea3 | 307 | |
949b5331 SG |
308 | pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); |
309 | /* 81xx's RGX has only one LMAC */ | |
310 | if (sdevid == PCI_SUBSYS_DEVID_81XX_NIC_PF) | |
311 | max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1; | |
312 | else | |
313 | max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; | |
314 | ||
315 | for (lmac = 0; lmac < max_lmac; lmac++) { | |
4863dea3 SG |
316 | lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); |
317 | lmac_cfg &= ~(0xF << 2); | |
318 | lmac_cfg |= ((size / 4) << 2); | |
319 | nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); | |
320 | } | |
321 | } | |
322 | ||
323 | /* Function to check number of LMACs present and set VF::LMAC mapping. | |
324 | * Mapping will be used while initializing channels. | |
325 | */ | |
326 | static void nic_set_lmac_vf_mapping(struct nicpf *nic) | |
327 | { | |
328 | unsigned bgx_map = bgx_get_map(nic->node); | |
329 | int bgx, next_bgx_lmac = 0; | |
330 | int lmac, lmac_cnt = 0; | |
331 | u64 lmac_credit; | |
332 | ||
333 | nic->num_vf_en = 0; | |
334 | ||
a5c3d498 | 335 | for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) { |
4863dea3 SG |
336 | if (!(bgx_map & (1 << bgx))) |
337 | continue; | |
338 | lmac_cnt = bgx_get_lmac_count(nic->node, bgx); | |
339 | for (lmac = 0; lmac < lmac_cnt; lmac++) | |
340 | nic->vf_lmac_map[next_bgx_lmac++] = | |
341 | NIC_SET_VF_LMAC_MAP(bgx, lmac); | |
342 | nic->num_vf_en += lmac_cnt; | |
343 | ||
344 | /* Program LMAC credits */ | |
345 | lmac_credit = (1ull << 1); /* channel credit enable */ | |
346 | lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ | |
347 | /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ | |
348 | lmac_credit |= (((((48 * 1024) / lmac_cnt) - | |
349 | NIC_HW_MAX_FRS) / 16) << 12); | |
350 | lmac = bgx * MAX_LMAC_PER_BGX; | |
351 | for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) | |
352 | nic_reg_write(nic, | |
353 | NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), | |
354 | lmac_credit); | |
6465859a SG |
355 | |
356 | /* On CN81XX there are only 8 VFs but max possible no of | |
357 | * interfaces are 9. | |
358 | */ | |
359 | if (nic->num_vf_en >= pci_sriov_get_totalvfs(nic->pdev)) { | |
360 | nic->num_vf_en = pci_sriov_get_totalvfs(nic->pdev); | |
361 | break; | |
362 | } | |
4863dea3 SG |
363 | } |
364 | } | |
365 | ||
949b5331 | 366 | static void nic_free_lmacmem(struct nicpf *nic) |
a5c3d498 | 367 | { |
949b5331 SG |
368 | kfree(nic->vf_lmac_map); |
369 | kfree(nic->link); | |
370 | kfree(nic->duplex); | |
371 | kfree(nic->speed); | |
372 | } | |
373 | ||
374 | static int nic_get_hw_info(struct nicpf *nic) | |
375 | { | |
376 | u8 max_lmac; | |
a5c3d498 SG |
377 | u16 sdevid; |
378 | struct hw_info *hw = nic->hw; | |
379 | ||
380 | pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); | |
381 | ||
382 | switch (sdevid) { | |
383 | case PCI_SUBSYS_DEVID_88XX_NIC_PF: | |
384 | hw->bgx_cnt = MAX_BGX_PER_CN88XX; | |
385 | hw->chans_per_lmac = 16; | |
386 | hw->chans_per_bgx = 128; | |
387 | hw->cpi_cnt = 2048; | |
388 | hw->rssi_cnt = 4096; | |
389 | hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; | |
390 | hw->tl3_cnt = 256; | |
391 | hw->tl2_cnt = 64; | |
392 | hw->tl1_cnt = 2; | |
393 | hw->tl1_per_bgx = true; | |
394 | break; | |
0025d93e SG |
395 | case PCI_SUBSYS_DEVID_81XX_NIC_PF: |
396 | hw->bgx_cnt = MAX_BGX_PER_CN81XX; | |
397 | hw->chans_per_lmac = 8; | |
398 | hw->chans_per_bgx = 32; | |
399 | hw->chans_per_rgx = 8; | |
400 | hw->chans_per_lbk = 24; | |
401 | hw->cpi_cnt = 512; | |
402 | hw->rssi_cnt = 256; | |
403 | hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */ | |
404 | hw->tl3_cnt = 64; | |
405 | hw->tl2_cnt = 16; | |
406 | hw->tl1_cnt = 10; | |
407 | hw->tl1_per_bgx = false; | |
408 | break; | |
409 | case PCI_SUBSYS_DEVID_83XX_NIC_PF: | |
410 | hw->bgx_cnt = MAX_BGX_PER_CN83XX; | |
411 | hw->chans_per_lmac = 8; | |
412 | hw->chans_per_bgx = 32; | |
413 | hw->chans_per_lbk = 64; | |
414 | hw->cpi_cnt = 2048; | |
415 | hw->rssi_cnt = 1024; | |
416 | hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */ | |
417 | hw->tl3_cnt = 256; | |
418 | hw->tl2_cnt = 64; | |
419 | hw->tl1_cnt = 18; | |
420 | hw->tl1_per_bgx = false; | |
421 | break; | |
a5c3d498 SG |
422 | } |
423 | hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->pdev); | |
949b5331 SG |
424 | |
425 | /* Allocate memory for LMAC tracking elements */ | |
426 | max_lmac = hw->bgx_cnt * MAX_LMAC_PER_BGX; | |
427 | nic->vf_lmac_map = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL); | |
428 | if (!nic->vf_lmac_map) | |
429 | goto error; | |
430 | nic->link = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL); | |
431 | if (!nic->link) | |
432 | goto error; | |
433 | nic->duplex = kmalloc_array(max_lmac, sizeof(u8), GFP_KERNEL); | |
434 | if (!nic->duplex) | |
435 | goto error; | |
436 | nic->speed = kmalloc_array(max_lmac, sizeof(u32), GFP_KERNEL); | |
437 | if (!nic->speed) | |
438 | goto error; | |
439 | return 0; | |
440 | ||
441 | error: | |
442 | nic_free_lmacmem(nic); | |
443 | return -ENOMEM; | |
a5c3d498 SG |
444 | } |
445 | ||
4863dea3 SG |
446 | #define BGX0_BLOCK 8 |
447 | #define BGX1_BLOCK 9 | |
448 | ||
949b5331 | 449 | static int nic_init_hw(struct nicpf *nic) |
4863dea3 | 450 | { |
949b5331 | 451 | int i, err; |
4c0b6eaf | 452 | u64 cqm_cfg; |
4863dea3 | 453 | |
a5c3d498 | 454 | /* Get HW capability info */ |
949b5331 SG |
455 | err = nic_get_hw_info(nic); |
456 | if (err) | |
457 | return err; | |
a5c3d498 | 458 | |
4863dea3 SG |
459 | /* Enable NIC HW block */ |
460 | nic_reg_write(nic, NIC_PF_CFG, 0x3); | |
461 | ||
462 | /* Enable backpressure */ | |
463 | nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); | |
464 | ||
0025d93e SG |
465 | /* TNS and TNS bypass modes are present only on 88xx */ |
466 | if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { | |
467 | /* Disable TNS mode on both interfaces */ | |
468 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, | |
469 | (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); | |
470 | nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), | |
471 | (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); | |
472 | } | |
473 | ||
4863dea3 SG |
474 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, |
475 | (1ULL << 63) | BGX0_BLOCK); | |
476 | nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), | |
477 | (1ULL << 63) | BGX1_BLOCK); | |
478 | ||
479 | /* PKIND configuration */ | |
480 | nic->pkind.minlen = 0; | |
712c3185 | 481 | nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4; |
4863dea3 SG |
482 | nic->pkind.lenerr_en = 1; |
483 | nic->pkind.rx_hdr = 0; | |
484 | nic->pkind.hdr_sl = 0; | |
485 | ||
486 | for (i = 0; i < NIC_MAX_PKIND; i++) | |
487 | nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), | |
488 | *(u64 *)&nic->pkind); | |
489 | ||
490 | nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); | |
491 | ||
492 | /* Timer config */ | |
493 | nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); | |
aa2e259b SG |
494 | |
495 | /* Enable VLAN ethertype matching and stripping */ | |
496 | nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, | |
497 | (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); | |
4c0b6eaf SG |
498 | |
499 | /* Check if HW expected value is higher (could be in future chips) */ | |
500 | cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); | |
501 | if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) | |
502 | nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); | |
949b5331 SG |
503 | |
504 | return 0; | |
4863dea3 SG |
505 | } |
506 | ||
507 | /* Channel parse index configuration */ | |
508 | static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) | |
509 | { | |
a5c3d498 | 510 | struct hw_info *hw = nic->hw; |
4863dea3 SG |
511 | u32 vnic, bgx, lmac, chan; |
512 | u32 padd, cpi_count = 0; | |
513 | u64 cpi_base, cpi, rssi_base, rssi; | |
514 | u8 qset, rq_idx = 0; | |
515 | ||
516 | vnic = cfg->vf_id; | |
517 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); | |
518 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); | |
519 | ||
a5c3d498 | 520 | chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); |
6465859a SG |
521 | cpi_base = vnic * NIC_MAX_CPI_PER_LMAC; |
522 | rssi_base = vnic * hw->rss_ind_tbl_size; | |
4863dea3 SG |
523 | |
524 | /* Rx channel configuration */ | |
525 | nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), | |
526 | (1ull << 63) | (vnic << 0)); | |
527 | nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), | |
528 | ((u64)cfg->cpi_alg << 62) | (cpi_base << 48)); | |
529 | ||
530 | if (cfg->cpi_alg == CPI_ALG_NONE) | |
531 | cpi_count = 1; | |
532 | else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ | |
533 | cpi_count = 8; | |
534 | else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ | |
535 | cpi_count = 16; | |
536 | else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ | |
537 | cpi_count = NIC_MAX_CPI_PER_LMAC; | |
538 | ||
539 | /* RSS Qset, Qidx mapping */ | |
540 | qset = cfg->vf_id; | |
541 | rssi = rssi_base; | |
542 | for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { | |
543 | nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), | |
544 | (qset << 3) | rq_idx); | |
545 | rq_idx++; | |
546 | } | |
547 | ||
548 | rssi = 0; | |
549 | cpi = cpi_base; | |
550 | for (; cpi < (cpi_base + cpi_count); cpi++) { | |
551 | /* Determine port to channel adder */ | |
552 | if (cfg->cpi_alg != CPI_ALG_DIFF) | |
553 | padd = cpi % cpi_count; | |
554 | else | |
555 | padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ | |
556 | ||
557 | /* Leave RSS_SIZE as '0' to disable RSS */ | |
40fb5f8a | 558 | if (pass1_silicon(nic->pdev)) { |
34411b68 TS |
559 | nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), |
560 | (vnic << 24) | (padd << 16) | | |
561 | (rssi_base + rssi)); | |
562 | } else { | |
563 | /* Set MPI_ALG to '0' to disable MCAM parsing */ | |
564 | nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), | |
565 | (padd << 16)); | |
566 | /* MPI index is same as CPI if MPI_ALG is not enabled */ | |
567 | nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), | |
568 | (vnic << 24) | (rssi_base + rssi)); | |
569 | } | |
4863dea3 SG |
570 | |
571 | if ((rssi + 1) >= cfg->rq_cnt) | |
572 | continue; | |
573 | ||
574 | if (cfg->cpi_alg == CPI_ALG_VLAN) | |
575 | rssi++; | |
576 | else if (cfg->cpi_alg == CPI_ALG_VLAN16) | |
577 | rssi = ((cpi - cpi_base) & 0xe) >> 1; | |
578 | else if (cfg->cpi_alg == CPI_ALG_DIFF) | |
579 | rssi = ((cpi - cpi_base) & 0x38) >> 3; | |
580 | } | |
581 | nic->cpi_base[cfg->vf_id] = cpi_base; | |
34411b68 | 582 | nic->rssi_base[cfg->vf_id] = rssi_base; |
4863dea3 SG |
583 | } |
584 | ||
585 | /* Responsds to VF with its RSS indirection table size */ | |
586 | static void nic_send_rss_size(struct nicpf *nic, int vf) | |
587 | { | |
588 | union nic_mbx mbx = {}; | |
589 | u64 *msg; | |
590 | ||
591 | msg = (u64 *)&mbx; | |
592 | ||
593 | mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE; | |
a5c3d498 | 594 | mbx.rss_size.ind_tbl_size = nic->hw->rss_ind_tbl_size; |
4863dea3 SG |
595 | nic_send_msg_to_vf(nic, vf, &mbx); |
596 | } | |
597 | ||
598 | /* Receive side scaling configuration | |
599 | * configure: | |
600 | * - RSS index | |
601 | * - indir table i.e hash::RQ mapping | |
602 | * - no of hash bits to consider | |
603 | */ | |
604 | static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) | |
605 | { | |
606 | u8 qset, idx = 0; | |
607 | u64 cpi_cfg, cpi_base, rssi_base, rssi; | |
34411b68 | 608 | u64 idx_addr; |
4863dea3 | 609 | |
34411b68 | 610 | rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset; |
4863dea3 SG |
611 | |
612 | rssi = rssi_base; | |
613 | qset = cfg->vf_id; | |
614 | ||
615 | for (; rssi < (rssi_base + cfg->tbl_len); rssi++) { | |
92dc8769 SG |
616 | u8 svf = cfg->ind_tbl[idx] >> 3; |
617 | ||
618 | if (svf) | |
619 | qset = nic->vf_sqs[cfg->vf_id][svf - 1]; | |
620 | else | |
621 | qset = cfg->vf_id; | |
4863dea3 SG |
622 | nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), |
623 | (qset << 3) | (cfg->ind_tbl[idx] & 0x7)); | |
624 | idx++; | |
625 | } | |
626 | ||
34411b68 | 627 | cpi_base = nic->cpi_base[cfg->vf_id]; |
40fb5f8a | 628 | if (pass1_silicon(nic->pdev)) |
34411b68 TS |
629 | idx_addr = NIC_PF_CPI_0_2047_CFG; |
630 | else | |
631 | idx_addr = NIC_PF_MPI_0_2047_CFG; | |
632 | cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3)); | |
4863dea3 SG |
633 | cpi_cfg &= ~(0xFULL << 20); |
634 | cpi_cfg |= (cfg->hash_bits << 20); | |
34411b68 | 635 | nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg); |
4863dea3 SG |
636 | } |
637 | ||
638 | /* 4 level transmit side scheduler configutation | |
639 | * for TNS bypass mode | |
640 | * | |
0025d93e | 641 | * Sample configuration for SQ0 on 88xx |
4863dea3 SG |
642 | * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 |
643 | * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 | |
644 | * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 | |
645 | * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 | |
646 | * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 | |
647 | * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 | |
648 | * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 | |
649 | * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 | |
650 | */ | |
92dc8769 SG |
651 | static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, |
652 | struct sq_cfg_msg *sq) | |
4863dea3 | 653 | { |
a5c3d498 | 654 | struct hw_info *hw = nic->hw; |
4863dea3 SG |
655 | u32 bgx, lmac, chan; |
656 | u32 tl2, tl3, tl4; | |
657 | u32 rr_quantum; | |
92dc8769 SG |
658 | u8 sq_idx = sq->sq_num; |
659 | u8 pqs_vnic; | |
3e29adba | 660 | int svf; |
92dc8769 SG |
661 | |
662 | if (sq->sqs_mode) | |
663 | pqs_vnic = nic->pqs_vf[vnic]; | |
664 | else | |
665 | pqs_vnic = vnic; | |
666 | ||
667 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); | |
668 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); | |
4863dea3 | 669 | |
4863dea3 SG |
670 | /* 24 bytes for FCS, IPG and preamble */ |
671 | rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); | |
672 | ||
a5c3d498 SG |
673 | /* For 88xx 0-511 TL4 transmits via BGX0 and |
674 | * 512-1023 TL4s transmit via BGX1. | |
675 | */ | |
0025d93e SG |
676 | if (hw->tl1_per_bgx) { |
677 | tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt); | |
678 | if (!sq->sqs_mode) { | |
679 | tl4 += (lmac * MAX_QUEUES_PER_QSET); | |
680 | } else { | |
681 | for (svf = 0; svf < MAX_SQS_PER_VF; svf++) { | |
682 | if (nic->vf_sqs[pqs_vnic][svf] == vnic) | |
683 | break; | |
684 | } | |
685 | tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET); | |
686 | tl4 += (lmac * MAX_QUEUES_PER_QSET * MAX_SQS_PER_VF); | |
687 | tl4 += (svf * MAX_QUEUES_PER_QSET); | |
3e29adba | 688 | } |
0025d93e SG |
689 | } else { |
690 | tl4 = (vnic * MAX_QUEUES_PER_QSET); | |
3e29adba | 691 | } |
4863dea3 | 692 | tl4 += sq_idx; |
92dc8769 | 693 | |
a5c3d498 | 694 | tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt); |
4863dea3 SG |
695 | nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | |
696 | ((u64)vnic << NIC_QS_ID_SHIFT) | | |
697 | ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4); | |
698 | nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), | |
699 | ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum); | |
700 | ||
701 | nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); | |
a5c3d498 SG |
702 | |
703 | /* On 88xx 0-127 channels are for BGX0 and | |
704 | * 127-255 channels for BGX1. | |
0025d93e SG |
705 | * |
706 | * On 81xx/83xx TL3_CHAN reg should be configured with channel | |
707 | * within LMAC i.e 0-7 and not the actual channel number like on 88xx | |
a5c3d498 SG |
708 | */ |
709 | chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); | |
0025d93e SG |
710 | if (hw->tl1_per_bgx) |
711 | nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); | |
712 | else | |
713 | nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0); | |
a5c3d498 | 714 | |
4863dea3 SG |
715 | /* Enable backpressure on the channel */ |
716 | nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); | |
717 | ||
718 | tl2 = tl3 >> 2; | |
719 | nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); | |
720 | nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); | |
721 | /* No priorities as of now */ | |
722 | nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); | |
0025d93e SG |
723 | |
724 | /* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1' | |
725 | * on 81xx/83xx TL2 needs to be configured to transmit to one of the | |
726 | * possible LMACs. | |
727 | * | |
728 | * This register doesn't exist on 88xx. | |
729 | */ | |
730 | if (!hw->tl1_per_bgx) | |
731 | nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3), | |
732 | lmac + (bgx * MAX_LMAC_PER_BGX)); | |
4863dea3 SG |
733 | } |
734 | ||
92dc8769 SG |
735 | /* Send primary nicvf pointer to secondary QS's VF */ |
736 | static void nic_send_pnicvf(struct nicpf *nic, int sqs) | |
737 | { | |
738 | union nic_mbx mbx = {}; | |
739 | ||
740 | mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; | |
741 | mbx.nicvf.nicvf = nic->nicvf[nic->pqs_vf[sqs]]; | |
742 | nic_send_msg_to_vf(nic, sqs, &mbx); | |
743 | } | |
744 | ||
745 | /* Send SQS's nicvf pointer to primary QS's VF */ | |
746 | static void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf) | |
747 | { | |
748 | union nic_mbx mbx = {}; | |
749 | int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id]; | |
750 | ||
751 | mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; | |
752 | mbx.nicvf.sqs_id = nicvf->sqs_id; | |
753 | mbx.nicvf.nicvf = nic->nicvf[sqs_id]; | |
754 | nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx); | |
755 | } | |
756 | ||
757 | /* Find next available Qset that can be assigned as a | |
758 | * secondary Qset to a VF. | |
759 | */ | |
760 | static int nic_nxt_avail_sqs(struct nicpf *nic) | |
761 | { | |
762 | int sqs; | |
763 | ||
764 | for (sqs = 0; sqs < nic->num_sqs_en; sqs++) { | |
765 | if (!nic->sqs_used[sqs]) | |
766 | nic->sqs_used[sqs] = true; | |
767 | else | |
768 | continue; | |
769 | return sqs + nic->num_vf_en; | |
770 | } | |
771 | return -1; | |
772 | } | |
773 | ||
774 | /* Allocate additional Qsets for requested VF */ | |
775 | static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) | |
776 | { | |
777 | union nic_mbx mbx = {}; | |
778 | int idx, alloc_qs = 0; | |
779 | int sqs_id; | |
780 | ||
781 | if (!nic->num_sqs_en) | |
782 | goto send_mbox; | |
783 | ||
784 | for (idx = 0; idx < sqs->qs_count; idx++) { | |
785 | sqs_id = nic_nxt_avail_sqs(nic); | |
786 | if (sqs_id < 0) | |
787 | break; | |
788 | nic->vf_sqs[sqs->vf_id][idx] = sqs_id; | |
789 | nic->pqs_vf[sqs_id] = sqs->vf_id; | |
790 | alloc_qs++; | |
791 | } | |
792 | ||
793 | send_mbox: | |
794 | mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; | |
795 | mbx.sqs_alloc.vf_id = sqs->vf_id; | |
796 | mbx.sqs_alloc.qs_count = alloc_qs; | |
797 | nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); | |
798 | } | |
799 | ||
d77a2384 SG |
800 | static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) |
801 | { | |
802 | int bgx_idx, lmac_idx; | |
803 | ||
949b5331 | 804 | if (lbk->vf_id >= nic->num_vf_en) |
d77a2384 SG |
805 | return -1; |
806 | ||
807 | bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); | |
808 | lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); | |
809 | ||
810 | bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); | |
811 | ||
d5b2d7a7 SG |
812 | /* Enable moving average calculation. |
813 | * Keep the LVL/AVG delay to HW enforced minimum so that, not too many | |
814 | * packets sneek in between average calculations. | |
815 | */ | |
816 | nic_reg_write(nic, NIC_PF_CQ_AVG_CFG, | |
817 | (BIT_ULL(20) | 0x2ull << 14 | 0x1)); | |
818 | nic_reg_write(nic, NIC_PF_RRM_AVG_CFG, | |
819 | (BIT_ULL(20) | 0x3ull << 14 | 0x1)); | |
820 | ||
d77a2384 SG |
821 | return 0; |
822 | } | |
823 | ||
3458c40d JJ |
824 | /* Reset statistics counters */ |
825 | static int nic_reset_stat_counters(struct nicpf *nic, | |
826 | int vf, struct reset_stat_cfg *cfg) | |
827 | { | |
828 | int i, stat, qnum; | |
829 | u64 reg_addr; | |
830 | ||
831 | for (i = 0; i < RX_STATS_ENUM_LAST; i++) { | |
832 | if (cfg->rx_stat_mask & BIT(i)) { | |
833 | reg_addr = NIC_PF_VNIC_0_127_RX_STAT_0_13 | | |
834 | (vf << NIC_QS_ID_SHIFT) | | |
835 | (i << 3); | |
836 | nic_reg_write(nic, reg_addr, 0); | |
837 | } | |
838 | } | |
839 | ||
840 | for (i = 0; i < TX_STATS_ENUM_LAST; i++) { | |
841 | if (cfg->tx_stat_mask & BIT(i)) { | |
842 | reg_addr = NIC_PF_VNIC_0_127_TX_STAT_0_4 | | |
843 | (vf << NIC_QS_ID_SHIFT) | | |
844 | (i << 3); | |
845 | nic_reg_write(nic, reg_addr, 0); | |
846 | } | |
847 | } | |
848 | ||
849 | for (i = 0; i <= 15; i++) { | |
850 | qnum = i >> 1; | |
851 | stat = i & 1 ? 1 : 0; | |
852 | reg_addr = (vf << NIC_QS_ID_SHIFT) | | |
853 | (qnum << NIC_Q_NUM_SHIFT) | (stat << 3); | |
854 | if (cfg->rq_stat_mask & BIT(i)) { | |
855 | reg_addr |= NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1; | |
856 | nic_reg_write(nic, reg_addr, 0); | |
857 | } | |
858 | if (cfg->sq_stat_mask & BIT(i)) { | |
859 | reg_addr |= NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1; | |
860 | nic_reg_write(nic, reg_addr, 0); | |
861 | } | |
862 | } | |
964cb69b | 863 | |
3458c40d JJ |
864 | return 0; |
865 | } | |
866 | ||
e22e86ea ZS |
867 | static void nic_enable_tunnel_parsing(struct nicpf *nic, int vf) |
868 | { | |
869 | u64 prot_def = (IPV6_PROT << 32) | (IPV4_PROT << 16) | ET_PROT; | |
870 | u64 vxlan_prot_def = (IPV6_PROT_DEF << 32) | | |
871 | (IPV4_PROT_DEF) << 16 | ET_PROT_DEF; | |
872 | ||
873 | /* Configure tunnel parsing parameters */ | |
874 | nic_reg_write(nic, NIC_PF_RX_GENEVE_DEF, | |
875 | (1ULL << 63 | UDP_GENEVE_PORT_NUM)); | |
876 | nic_reg_write(nic, NIC_PF_RX_GENEVE_PROT_DEF, | |
877 | ((7ULL << 61) | prot_def)); | |
878 | nic_reg_write(nic, NIC_PF_RX_NVGRE_PROT_DEF, | |
879 | ((7ULL << 61) | prot_def)); | |
880 | nic_reg_write(nic, NIC_PF_RX_VXLAN_DEF_0_1, | |
881 | ((1ULL << 63) | UDP_VXLAN_PORT_NUM)); | |
882 | nic_reg_write(nic, NIC_PF_RX_VXLAN_PROT_DEF, | |
883 | ((0xfULL << 60) | vxlan_prot_def)); | |
884 | } | |
885 | ||
f406ce42 PF |
886 | static void nic_enable_vf(struct nicpf *nic, int vf, bool enable) |
887 | { | |
888 | int bgx, lmac; | |
889 | ||
890 | nic->vf_enabled[vf] = enable; | |
891 | ||
892 | if (vf >= nic->num_vf_en) | |
893 | return; | |
894 | ||
895 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
896 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
897 | ||
898 | bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable); | |
899 | } | |
900 | ||
430da208 SG |
901 | static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) |
902 | { | |
903 | int bgx, lmac; | |
904 | struct pfc pfc; | |
905 | union nic_mbx mbx = {}; | |
906 | ||
907 | if (vf >= nic->num_vf_en) | |
908 | return; | |
909 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
910 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
911 | ||
912 | if (cfg->get) { | |
913 | bgx_lmac_get_pfc(nic->node, bgx, lmac, &pfc); | |
914 | mbx.pfc.msg = NIC_MBOX_MSG_PFC; | |
915 | mbx.pfc.autoneg = pfc.autoneg; | |
916 | mbx.pfc.fc_rx = pfc.fc_rx; | |
917 | mbx.pfc.fc_tx = pfc.fc_tx; | |
918 | nic_send_msg_to_vf(nic, vf, &mbx); | |
919 | } else { | |
920 | bgx_lmac_set_pfc(nic->node, bgx, lmac, cfg); | |
921 | nic_mbx_send_ack(nic, vf); | |
922 | } | |
923 | } | |
924 | ||
4863dea3 SG |
925 | /* Interrupt handler to handle mailbox messages from VFs */ |
926 | static void nic_handle_mbx_intr(struct nicpf *nic, int vf) | |
927 | { | |
928 | union nic_mbx mbx = {}; | |
929 | u64 *mbx_data; | |
930 | u64 mbx_addr; | |
931 | u64 reg_addr; | |
92dc8769 | 932 | u64 cfg; |
4863dea3 SG |
933 | int bgx, lmac; |
934 | int i; | |
935 | int ret = 0; | |
936 | ||
937 | nic->mbx_lock[vf] = true; | |
938 | ||
939 | mbx_addr = nic_get_mbx_addr(vf); | |
940 | mbx_data = (u64 *)&mbx; | |
941 | ||
942 | for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { | |
943 | *mbx_data = nic_reg_read(nic, mbx_addr); | |
944 | mbx_data++; | |
945 | mbx_addr += sizeof(u64); | |
946 | } | |
947 | ||
ecae29cb | 948 | dev_dbg(&nic->pdev->dev, "%s: Mailbox msg 0x%02x from VF%d\n", |
4863dea3 SG |
949 | __func__, mbx.msg.msg, vf); |
950 | switch (mbx.msg.msg) { | |
951 | case NIC_MBOX_MSG_READY: | |
952 | nic_mbx_send_ready(nic, vf); | |
949b5331 | 953 | if (vf < nic->num_vf_en) { |
92dc8769 SG |
954 | nic->link[vf] = 0; |
955 | nic->duplex[vf] = 0; | |
956 | nic->speed[vf] = 0; | |
957 | } | |
ecae29cb | 958 | goto unlock; |
4863dea3 SG |
959 | case NIC_MBOX_MSG_QS_CFG: |
960 | reg_addr = NIC_PF_QSET_0_127_CFG | | |
961 | (mbx.qs.num << NIC_QS_ID_SHIFT); | |
92dc8769 SG |
962 | cfg = mbx.qs.cfg; |
963 | /* Check if its a secondary Qset */ | |
964 | if (vf >= nic->num_vf_en) { | |
965 | cfg = cfg & (~0x7FULL); | |
966 | /* Assign this Qset to primary Qset's VF */ | |
967 | cfg |= nic->pqs_vf[vf]; | |
968 | } | |
969 | nic_reg_write(nic, reg_addr, cfg); | |
4863dea3 SG |
970 | break; |
971 | case NIC_MBOX_MSG_RQ_CFG: | |
972 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | | |
973 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
974 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
975 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
02a72bd8 SG |
976 | /* Enable CQE_RX2_S extension in CQE_RX descriptor. |
977 | * This gets appended by default on 81xx/83xx chips, | |
978 | * for consistency enabling the same on 88xx pass2 | |
979 | * where this is introduced. | |
980 | */ | |
981 | if (pass2_silicon(nic->pdev)) | |
982 | nic_reg_write(nic, NIC_PF_RX_CFG, 0x01); | |
e22e86ea ZS |
983 | if (!pass1_silicon(nic->pdev)) |
984 | nic_enable_tunnel_parsing(nic, vf); | |
4863dea3 SG |
985 | break; |
986 | case NIC_MBOX_MSG_RQ_BP_CFG: | |
987 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | | |
988 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
989 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
990 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
991 | break; | |
992 | case NIC_MBOX_MSG_RQ_SW_SYNC: | |
993 | ret = nic_rcv_queue_sw_sync(nic); | |
994 | break; | |
995 | case NIC_MBOX_MSG_RQ_DROP_CFG: | |
996 | reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | | |
997 | (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | | |
998 | (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); | |
999 | nic_reg_write(nic, reg_addr, mbx.rq.cfg); | |
1000 | break; | |
1001 | case NIC_MBOX_MSG_SQ_CFG: | |
1002 | reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | | |
1003 | (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | | |
1004 | (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); | |
1005 | nic_reg_write(nic, reg_addr, mbx.sq.cfg); | |
92dc8769 | 1006 | nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); |
4863dea3 SG |
1007 | break; |
1008 | case NIC_MBOX_MSG_SET_MAC: | |
ecae29cb RB |
1009 | if (vf >= nic->num_vf_en) { |
1010 | ret = -1; /* NACK */ | |
92dc8769 | 1011 | break; |
ecae29cb | 1012 | } |
4863dea3 SG |
1013 | lmac = mbx.mac.vf_id; |
1014 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); | |
1015 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); | |
e610cb32 | 1016 | bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); |
4863dea3 SG |
1017 | break; |
1018 | case NIC_MBOX_MSG_SET_MAX_FRS: | |
1019 | ret = nic_update_hw_frs(nic, mbx.frs.max_frs, | |
1020 | mbx.frs.vf_id); | |
1021 | break; | |
1022 | case NIC_MBOX_MSG_CPI_CFG: | |
1023 | nic_config_cpi(nic, &mbx.cpi_cfg); | |
1024 | break; | |
1025 | case NIC_MBOX_MSG_RSS_SIZE: | |
1026 | nic_send_rss_size(nic, vf); | |
1027 | goto unlock; | |
1028 | case NIC_MBOX_MSG_RSS_CFG: | |
1029 | case NIC_MBOX_MSG_RSS_CFG_CONT: | |
1030 | nic_config_rss(nic, &mbx.rss_cfg); | |
1031 | break; | |
1032 | case NIC_MBOX_MSG_CFG_DONE: | |
1033 | /* Last message of VF config msg sequence */ | |
f406ce42 | 1034 | nic_enable_vf(nic, vf, true); |
4863dea3 SG |
1035 | goto unlock; |
1036 | case NIC_MBOX_MSG_SHUTDOWN: | |
1037 | /* First msg in VF teardown sequence */ | |
92dc8769 SG |
1038 | if (vf >= nic->num_vf_en) |
1039 | nic->sqs_used[vf - nic->num_vf_en] = false; | |
1040 | nic->pqs_vf[vf] = 0; | |
f406ce42 | 1041 | nic_enable_vf(nic, vf, false); |
92dc8769 SG |
1042 | break; |
1043 | case NIC_MBOX_MSG_ALLOC_SQS: | |
1044 | nic_alloc_sqs(nic, &mbx.sqs_alloc); | |
1045 | goto unlock; | |
1046 | case NIC_MBOX_MSG_NICVF_PTR: | |
1047 | nic->nicvf[vf] = mbx.nicvf.nicvf; | |
4863dea3 | 1048 | break; |
92dc8769 SG |
1049 | case NIC_MBOX_MSG_PNICVF_PTR: |
1050 | nic_send_pnicvf(nic, vf); | |
1051 | goto unlock; | |
1052 | case NIC_MBOX_MSG_SNICVF_PTR: | |
1053 | nic_send_snicvf(nic, &mbx.nicvf); | |
1054 | goto unlock; | |
4863dea3 SG |
1055 | case NIC_MBOX_MSG_BGX_STATS: |
1056 | nic_get_bgx_stats(nic, &mbx.bgx_stats); | |
1057 | goto unlock; | |
d77a2384 SG |
1058 | case NIC_MBOX_MSG_LOOPBACK: |
1059 | ret = nic_config_loopback(nic, &mbx.lbk); | |
1060 | break; | |
3458c40d JJ |
1061 | case NIC_MBOX_MSG_RESET_STAT_COUNTER: |
1062 | ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat); | |
1063 | break; | |
430da208 SG |
1064 | case NIC_MBOX_MSG_PFC: |
1065 | nic_pause_frame(nic, vf, &mbx.pfc); | |
1066 | goto unlock; | |
4863dea3 SG |
1067 | default: |
1068 | dev_err(&nic->pdev->dev, | |
1069 | "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); | |
1070 | break; | |
1071 | } | |
1072 | ||
ecae29cb | 1073 | if (!ret) { |
4863dea3 | 1074 | nic_mbx_send_ack(nic, vf); |
ecae29cb RB |
1075 | } else if (mbx.msg.msg != NIC_MBOX_MSG_READY) { |
1076 | dev_err(&nic->pdev->dev, "NACK for MBOX 0x%02x from VF %d\n", | |
1077 | mbx.msg.msg, vf); | |
4863dea3 | 1078 | nic_mbx_send_nack(nic, vf); |
ecae29cb | 1079 | } |
4863dea3 SG |
1080 | unlock: |
1081 | nic->mbx_lock[vf] = false; | |
1082 | } | |
1083 | ||
52358aad | 1084 | static irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq) |
4863dea3 | 1085 | { |
52358aad SG |
1086 | struct nicpf *nic = (struct nicpf *)nic_irq; |
1087 | int mbx; | |
4863dea3 SG |
1088 | u64 intr; |
1089 | u8 vf, vf_per_mbx_reg = 64; | |
1090 | ||
52358aad SG |
1091 | if (irq == nic->msix_entries[NIC_PF_INTR_ID_MBOX0].vector) |
1092 | mbx = 0; | |
1093 | else | |
1094 | mbx = 1; | |
1095 | ||
4863dea3 SG |
1096 | intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); |
1097 | dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); | |
1098 | for (vf = 0; vf < vf_per_mbx_reg; vf++) { | |
1099 | if (intr & (1ULL << vf)) { | |
1100 | dev_dbg(&nic->pdev->dev, "Intr from VF %d\n", | |
1101 | vf + (mbx * vf_per_mbx_reg)); | |
92dc8769 | 1102 | |
4863dea3 SG |
1103 | nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg)); |
1104 | nic_clear_mbx_intr(nic, vf, mbx); | |
1105 | } | |
1106 | } | |
4863dea3 SG |
1107 | return IRQ_HANDLED; |
1108 | } | |
1109 | ||
1110 | static int nic_enable_msix(struct nicpf *nic) | |
1111 | { | |
1112 | int i, ret; | |
1113 | ||
52358aad SG |
1114 | nic->num_vec = pci_msix_vec_count(nic->pdev); |
1115 | ||
1116 | nic->msix_entries = kmalloc_array(nic->num_vec, | |
1117 | sizeof(struct msix_entry), | |
1118 | GFP_KERNEL); | |
1119 | if (!nic->msix_entries) | |
1120 | return -ENOMEM; | |
4863dea3 SG |
1121 | |
1122 | for (i = 0; i < nic->num_vec; i++) | |
1123 | nic->msix_entries[i].entry = i; | |
1124 | ||
1125 | ret = pci_enable_msix(nic->pdev, nic->msix_entries, nic->num_vec); | |
1126 | if (ret) { | |
1127 | dev_err(&nic->pdev->dev, | |
52358aad SG |
1128 | "Request for #%d msix vectors failed, returned %d\n", |
1129 | nic->num_vec, ret); | |
1130 | kfree(nic->msix_entries); | |
4863dea3 SG |
1131 | return ret; |
1132 | } | |
1133 | ||
1134 | nic->msix_enabled = 1; | |
1135 | return 0; | |
1136 | } | |
1137 | ||
1138 | static void nic_disable_msix(struct nicpf *nic) | |
1139 | { | |
1140 | if (nic->msix_enabled) { | |
1141 | pci_disable_msix(nic->pdev); | |
52358aad | 1142 | kfree(nic->msix_entries); |
4863dea3 SG |
1143 | nic->msix_enabled = 0; |
1144 | nic->num_vec = 0; | |
1145 | } | |
1146 | } | |
1147 | ||
1148 | static void nic_free_all_interrupts(struct nicpf *nic) | |
1149 | { | |
1150 | int irq; | |
1151 | ||
1152 | for (irq = 0; irq < nic->num_vec; irq++) { | |
1153 | if (nic->irq_allocated[irq]) | |
1154 | free_irq(nic->msix_entries[irq].vector, nic); | |
1155 | nic->irq_allocated[irq] = false; | |
1156 | } | |
1157 | } | |
1158 | ||
1159 | static int nic_register_interrupts(struct nicpf *nic) | |
1160 | { | |
52358aad | 1161 | int i, ret; |
4863dea3 SG |
1162 | |
1163 | /* Enable MSI-X */ | |
1164 | ret = nic_enable_msix(nic); | |
1165 | if (ret) | |
1166 | return ret; | |
1167 | ||
52358aad SG |
1168 | /* Register mailbox interrupt handler */ |
1169 | for (i = NIC_PF_INTR_ID_MBOX0; i < nic->num_vec; i++) { | |
1170 | sprintf(nic->irq_name[i], | |
1171 | "NICPF Mbox%d", (i - NIC_PF_INTR_ID_MBOX0)); | |
4863dea3 | 1172 | |
52358aad SG |
1173 | ret = request_irq(nic->msix_entries[i].vector, |
1174 | nic_mbx_intr_handler, 0, | |
1175 | nic->irq_name[i], nic); | |
1176 | if (ret) | |
1177 | goto fail; | |
4863dea3 | 1178 | |
52358aad SG |
1179 | nic->irq_allocated[i] = true; |
1180 | } | |
4863dea3 SG |
1181 | |
1182 | /* Enable mailbox interrupt */ | |
1183 | nic_enable_mbx_intr(nic); | |
1184 | return 0; | |
1185 | ||
1186 | fail: | |
1187 | dev_err(&nic->pdev->dev, "Request irq failed\n"); | |
1188 | nic_free_all_interrupts(nic); | |
52358aad | 1189 | nic_disable_msix(nic); |
4863dea3 SG |
1190 | return ret; |
1191 | } | |
1192 | ||
1193 | static void nic_unregister_interrupts(struct nicpf *nic) | |
1194 | { | |
1195 | nic_free_all_interrupts(nic); | |
1196 | nic_disable_msix(nic); | |
1197 | } | |
1198 | ||
92dc8769 SG |
1199 | static int nic_num_sqs_en(struct nicpf *nic, int vf_en) |
1200 | { | |
1201 | int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE; | |
1202 | u16 total_vf; | |
1203 | ||
3a397ebe SG |
1204 | /* Secondary Qsets are needed only if CPU count is |
1205 | * morethan MAX_QUEUES_PER_QSET. | |
1206 | */ | |
1207 | if (num_online_cpus() <= MAX_QUEUES_PER_QSET) | |
1208 | return 0; | |
1209 | ||
92dc8769 SG |
1210 | /* Check if its a multi-node environment */ |
1211 | if (nr_node_ids > 1) | |
1212 | sqs_per_vf = MAX_SQS_PER_VF; | |
1213 | ||
1214 | pos = pci_find_ext_capability(nic->pdev, PCI_EXT_CAP_ID_SRIOV); | |
1215 | pci_read_config_word(nic->pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf); | |
1216 | return min(total_vf - vf_en, vf_en * sqs_per_vf); | |
1217 | } | |
1218 | ||
4863dea3 SG |
1219 | static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) |
1220 | { | |
1221 | int pos = 0; | |
92dc8769 | 1222 | int vf_en; |
4863dea3 SG |
1223 | int err; |
1224 | u16 total_vf_cnt; | |
1225 | ||
1226 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); | |
1227 | if (!pos) { | |
1228 | dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n"); | |
1229 | return -ENODEV; | |
1230 | } | |
1231 | ||
1232 | pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt); | |
1233 | if (total_vf_cnt < nic->num_vf_en) | |
1234 | nic->num_vf_en = total_vf_cnt; | |
1235 | ||
1236 | if (!total_vf_cnt) | |
1237 | return 0; | |
1238 | ||
92dc8769 SG |
1239 | vf_en = nic->num_vf_en; |
1240 | nic->num_sqs_en = nic_num_sqs_en(nic, nic->num_vf_en); | |
1241 | vf_en += nic->num_sqs_en; | |
1242 | ||
1243 | err = pci_enable_sriov(pdev, vf_en); | |
4863dea3 SG |
1244 | if (err) { |
1245 | dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", | |
92dc8769 | 1246 | vf_en); |
4863dea3 SG |
1247 | nic->num_vf_en = 0; |
1248 | return err; | |
1249 | } | |
1250 | ||
1251 | dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", | |
92dc8769 | 1252 | vf_en); |
4863dea3 SG |
1253 | |
1254 | nic->flags |= NIC_SRIOV_ENABLED; | |
1255 | return 0; | |
1256 | } | |
1257 | ||
1258 | /* Poll for BGX LMAC link status and update corresponding VF | |
1259 | * if there is a change, valid only if internal L2 switch | |
1260 | * is not present otherwise VF link is always treated as up | |
1261 | */ | |
1262 | static void nic_poll_for_link(struct work_struct *work) | |
1263 | { | |
1264 | union nic_mbx mbx = {}; | |
1265 | struct nicpf *nic; | |
1266 | struct bgx_link_status link; | |
1267 | u8 vf, bgx, lmac; | |
1268 | ||
1269 | nic = container_of(work, struct nicpf, dwork.work); | |
1270 | ||
1271 | mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; | |
1272 | ||
f406ce42 | 1273 | for (vf = 0; vf < nic->num_vf_en; vf++) { |
4863dea3 SG |
1274 | /* Poll only if VF is UP */ |
1275 | if (!nic->vf_enabled[vf]) | |
1276 | continue; | |
1277 | ||
1278 | /* Get BGX, LMAC indices for the VF */ | |
1279 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
1280 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); | |
1281 | /* Get interface link status */ | |
1282 | bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); | |
1283 | ||
1284 | /* Inform VF only if link status changed */ | |
1285 | if (nic->link[vf] == link.link_up) | |
1286 | continue; | |
1287 | ||
1288 | if (!nic->mbx_lock[vf]) { | |
1289 | nic->link[vf] = link.link_up; | |
1290 | nic->duplex[vf] = link.duplex; | |
1291 | nic->speed[vf] = link.speed; | |
1292 | ||
1293 | /* Send a mbox message to VF with current link status */ | |
1294 | mbx.link_status.link_up = link.link_up; | |
1295 | mbx.link_status.duplex = link.duplex; | |
1296 | mbx.link_status.speed = link.speed; | |
1cc70259 | 1297 | mbx.link_status.mac_type = link.mac_type; |
4863dea3 SG |
1298 | nic_send_msg_to_vf(nic, vf, &mbx); |
1299 | } | |
1300 | } | |
1301 | queue_delayed_work(nic->check_link, &nic->dwork, HZ * 2); | |
1302 | } | |
1303 | ||
1304 | static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1305 | { | |
1306 | struct device *dev = &pdev->dev; | |
1307 | struct nicpf *nic; | |
1308 | int err; | |
1309 | ||
1310 | BUILD_BUG_ON(sizeof(union nic_mbx) > 16); | |
1311 | ||
1312 | nic = devm_kzalloc(dev, sizeof(*nic), GFP_KERNEL); | |
1313 | if (!nic) | |
1314 | return -ENOMEM; | |
1315 | ||
a5c3d498 SG |
1316 | nic->hw = devm_kzalloc(dev, sizeof(struct hw_info), GFP_KERNEL); |
1317 | if (!nic->hw) { | |
1318 | devm_kfree(dev, nic); | |
1319 | return -ENOMEM; | |
1320 | } | |
1321 | ||
4863dea3 SG |
1322 | pci_set_drvdata(pdev, nic); |
1323 | ||
1324 | nic->pdev = pdev; | |
1325 | ||
1326 | err = pci_enable_device(pdev); | |
1327 | if (err) { | |
1328 | dev_err(dev, "Failed to enable PCI device\n"); | |
1329 | pci_set_drvdata(pdev, NULL); | |
1330 | return err; | |
1331 | } | |
1332 | ||
1333 | err = pci_request_regions(pdev, DRV_NAME); | |
1334 | if (err) { | |
1335 | dev_err(dev, "PCI request regions failed 0x%x\n", err); | |
1336 | goto err_disable_device; | |
1337 | } | |
1338 | ||
1339 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); | |
1340 | if (err) { | |
1341 | dev_err(dev, "Unable to get usable DMA configuration\n"); | |
1342 | goto err_release_regions; | |
1343 | } | |
1344 | ||
1345 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); | |
1346 | if (err) { | |
1347 | dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n"); | |
1348 | goto err_release_regions; | |
1349 | } | |
1350 | ||
1351 | /* MAP PF's configuration registers */ | |
1352 | nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); | |
1353 | if (!nic->reg_base) { | |
1354 | dev_err(dev, "Cannot map config register space, aborting\n"); | |
1355 | err = -ENOMEM; | |
1356 | goto err_release_regions; | |
1357 | } | |
1358 | ||
d768b678 | 1359 | nic->node = nic_get_node_id(pdev); |
4863dea3 | 1360 | |
4863dea3 | 1361 | /* Initialize hardware */ |
949b5331 SG |
1362 | err = nic_init_hw(nic); |
1363 | if (err) | |
1364 | goto err_release_regions; | |
4863dea3 | 1365 | |
a5c3d498 | 1366 | nic_set_lmac_vf_mapping(nic); |
4863dea3 SG |
1367 | |
1368 | /* Register interrupts */ | |
1369 | err = nic_register_interrupts(nic); | |
1370 | if (err) | |
1371 | goto err_release_regions; | |
1372 | ||
1373 | /* Configure SRIOV */ | |
1374 | err = nic_sriov_init(pdev, nic); | |
1375 | if (err) | |
1376 | goto err_unregister_interrupts; | |
1377 | ||
1378 | /* Register a physical link status poll fn() */ | |
1379 | nic->check_link = alloc_workqueue("check_link_status", | |
1380 | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); | |
1381 | if (!nic->check_link) { | |
1382 | err = -ENOMEM; | |
1383 | goto err_disable_sriov; | |
1384 | } | |
1385 | ||
1386 | INIT_DELAYED_WORK(&nic->dwork, nic_poll_for_link); | |
1387 | queue_delayed_work(nic->check_link, &nic->dwork, 0); | |
1388 | ||
1389 | return 0; | |
1390 | ||
1391 | err_disable_sriov: | |
1392 | if (nic->flags & NIC_SRIOV_ENABLED) | |
1393 | pci_disable_sriov(pdev); | |
1394 | err_unregister_interrupts: | |
1395 | nic_unregister_interrupts(nic); | |
1396 | err_release_regions: | |
1397 | pci_release_regions(pdev); | |
1398 | err_disable_device: | |
949b5331 | 1399 | nic_free_lmacmem(nic); |
a5c3d498 SG |
1400 | devm_kfree(dev, nic->hw); |
1401 | devm_kfree(dev, nic); | |
4863dea3 SG |
1402 | pci_disable_device(pdev); |
1403 | pci_set_drvdata(pdev, NULL); | |
1404 | return err; | |
1405 | } | |
1406 | ||
1407 | static void nic_remove(struct pci_dev *pdev) | |
1408 | { | |
1409 | struct nicpf *nic = pci_get_drvdata(pdev); | |
1410 | ||
1411 | if (nic->flags & NIC_SRIOV_ENABLED) | |
1412 | pci_disable_sriov(pdev); | |
1413 | ||
1414 | if (nic->check_link) { | |
1415 | /* Destroy work Queue */ | |
a7b1f535 | 1416 | cancel_delayed_work_sync(&nic->dwork); |
4863dea3 SG |
1417 | destroy_workqueue(nic->check_link); |
1418 | } | |
1419 | ||
1420 | nic_unregister_interrupts(nic); | |
1421 | pci_release_regions(pdev); | |
a5c3d498 | 1422 | |
949b5331 | 1423 | nic_free_lmacmem(nic); |
a5c3d498 SG |
1424 | devm_kfree(&pdev->dev, nic->hw); |
1425 | devm_kfree(&pdev->dev, nic); | |
1426 | ||
4863dea3 SG |
1427 | pci_disable_device(pdev); |
1428 | pci_set_drvdata(pdev, NULL); | |
1429 | } | |
1430 | ||
1431 | static struct pci_driver nic_driver = { | |
1432 | .name = DRV_NAME, | |
1433 | .id_table = nic_id_table, | |
1434 | .probe = nic_probe, | |
1435 | .remove = nic_remove, | |
1436 | }; | |
1437 | ||
1438 | static int __init nic_init_module(void) | |
1439 | { | |
1440 | pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION); | |
1441 | ||
1442 | return pci_register_driver(&nic_driver); | |
1443 | } | |
1444 | ||
1445 | static void __exit nic_cleanup_module(void) | |
1446 | { | |
1447 | pci_unregister_driver(&nic_driver); | |
1448 | } | |
1449 | ||
1450 | module_init(nic_init_module); | |
1451 | module_exit(nic_cleanup_module); |