1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. |
4 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. |
5 | */ |
6 | #include <linux/errno.h> |
7 | #include <linux/types.h> |
8 | #include <linux/pci.h> |
9 | #include "wq_enet_desc.h" |
10 | #include "rq_enet_desc.h" |
11 | #include "cq_enet_desc.h" |
12 | #include "vnic_resource.h" |
13 | #include "vnic_dev.h" |
14 | #include "vnic_wq.h" |
15 | #include "vnic_rq.h" |
16 | #include "vnic_cq.h" |
17 | #include "vnic_intr.h" |
18 | #include "vnic_stats.h" |
19 | #include "vnic_nic.h" |
20 | #include "fnic.h" |
21 | |
22 | int fnic_get_vnic_config(struct fnic *fnic) |
23 | { |
24 | struct vnic_fc_config *c = &fnic->config; |
25 | int err; |
26 | |
27 | #define GET_CONFIG(m) \ |
28 | do { \ |
29 | err = vnic_dev_spec(fnic->vdev, \ |
30 | offsetof(struct vnic_fc_config, m), \ |
31 | sizeof(c->m), &c->m); \ |
32 | if (err) { \ |
33 | shost_printk(KERN_ERR, fnic->lport->host, \ |
34 | "Error getting %s, %d\n", #m, \ |
35 | err); \ |
36 | return err; \ |
37 | } \ |
38 | } while (0); |
39 | |
40 | GET_CONFIG(node_wwn); |
41 | GET_CONFIG(port_wwn); |
42 | GET_CONFIG(wq_enet_desc_count); |
43 | GET_CONFIG(wq_copy_desc_count); |
44 | GET_CONFIG(rq_desc_count); |
45 | GET_CONFIG(maxdatafieldsize); |
46 | GET_CONFIG(ed_tov); |
47 | GET_CONFIG(ra_tov); |
48 | GET_CONFIG(intr_timer); |
49 | GET_CONFIG(intr_timer_type); |
50 | GET_CONFIG(flags); |
51 | GET_CONFIG(flogi_retries); |
52 | GET_CONFIG(flogi_timeout); |
53 | GET_CONFIG(plogi_retries); |
54 | GET_CONFIG(plogi_timeout); |
55 | GET_CONFIG(io_throttle_count); |
56 | GET_CONFIG(link_down_timeout); |
57 | GET_CONFIG(port_down_timeout); |
58 | GET_CONFIG(port_down_io_retries); |
59 | GET_CONFIG(luns_per_tgt); |
60 | |
61 | c->wq_enet_desc_count = |
62 | min_t(u32, VNIC_FNIC_WQ_DESCS_MAX, |
63 | max_t(u32, VNIC_FNIC_WQ_DESCS_MIN, |
64 | c->wq_enet_desc_count)); |
65 | c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16); |
66 | |
67 | c->wq_copy_desc_count = |
68 | min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX, |
69 | max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN, |
70 | c->wq_copy_desc_count)); |
71 | c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16); |
72 | |
73 | c->rq_desc_count = |
74 | min_t(u32, VNIC_FNIC_RQ_DESCS_MAX, |
75 | max_t(u32, VNIC_FNIC_RQ_DESCS_MIN, |
76 | c->rq_desc_count)); |
77 | c->rq_desc_count = ALIGN(c->rq_desc_count, 16); |
78 | |
79 | c->maxdatafieldsize = |
80 | min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX, |
81 | max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN, |
82 | c->maxdatafieldsize)); |
83 | c->ed_tov = |
84 | min_t(u32, VNIC_FNIC_EDTOV_MAX, |
85 | max_t(u32, VNIC_FNIC_EDTOV_MIN, |
86 | c->ed_tov)); |
87 | |
88 | c->ra_tov = |
89 | min_t(u32, VNIC_FNIC_RATOV_MAX, |
90 | max_t(u32, VNIC_FNIC_RATOV_MIN, |
91 | c->ra_tov)); |
92 | |
93 | c->flogi_retries = |
94 | min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries); |
95 | |
96 | c->flogi_timeout = |
97 | min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX, |
98 | max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN, |
99 | c->flogi_timeout)); |
100 | |
101 | c->plogi_retries = |
102 | min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries); |
103 | |
104 | c->plogi_timeout = |
105 | min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX, |
106 | max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN, |
107 | c->plogi_timeout)); |
108 | |
109 | c->io_throttle_count = |
110 | min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX, |
111 | max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN, |
112 | c->io_throttle_count)); |
113 | |
114 | c->link_down_timeout = |
115 | min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX, |
116 | c->link_down_timeout); |
117 | |
118 | c->port_down_timeout = |
119 | min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX, |
120 | c->port_down_timeout); |
121 | |
122 | c->port_down_io_retries = |
123 | min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX, |
124 | c->port_down_io_retries); |
125 | |
126 | c->luns_per_tgt = |
127 | min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX, |
128 | max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN, |
129 | c->luns_per_tgt)); |
130 | |
131 | c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); |
132 | c->intr_timer_type = c->intr_timer_type; |
133 | |
134 | shost_printk(KERN_INFO, fnic->lport->host, |
135 | "vNIC MAC addr %pM " |
136 | "wq/wq_copy/rq %d/%d/%d\n" , |
137 | fnic->ctlr.ctl_src_addr, |
138 | c->wq_enet_desc_count, c->wq_copy_desc_count, |
139 | c->rq_desc_count); |
140 | shost_printk(KERN_INFO, fnic->lport->host, |
141 | "vNIC node wwn %llx port wwn %llx\n" , |
142 | c->node_wwn, c->port_wwn); |
143 | shost_printk(KERN_INFO, fnic->lport->host, |
144 | "vNIC ed_tov %d ra_tov %d\n" , |
145 | c->ed_tov, c->ra_tov); |
146 | shost_printk(KERN_INFO, fnic->lport->host, |
147 | "vNIC mtu %d intr timer %d\n" , |
148 | c->maxdatafieldsize, c->intr_timer); |
149 | shost_printk(KERN_INFO, fnic->lport->host, |
150 | "vNIC flags 0x%x luns per tgt %d\n" , |
151 | c->flags, c->luns_per_tgt); |
152 | shost_printk(KERN_INFO, fnic->lport->host, |
153 | "vNIC flogi_retries %d flogi timeout %d\n" , |
154 | c->flogi_retries, c->flogi_timeout); |
155 | shost_printk(KERN_INFO, fnic->lport->host, |
156 | "vNIC plogi retries %d plogi timeout %d\n" , |
157 | c->plogi_retries, c->plogi_timeout); |
158 | shost_printk(KERN_INFO, fnic->lport->host, |
159 | "vNIC io throttle count %d link dn timeout %d\n" , |
160 | c->io_throttle_count, c->link_down_timeout); |
161 | shost_printk(KERN_INFO, fnic->lport->host, |
162 | "vNIC port dn io retries %d port dn timeout %d\n" , |
163 | c->port_down_io_retries, c->port_down_timeout); |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | int fnic_set_nic_config(struct fnic *fnic, u8 , |
169 | u8 , |
170 | u8 , u8 , u8 , |
171 | u8 tso_ipid_split_en, u8 ig_vlan_strip_en) |
172 | { |
173 | u64 a0, a1; |
174 | u32 nic_cfg; |
175 | int wait = 1000; |
176 | |
177 | vnic_set_nic_cfg(nic_cfg: &nic_cfg, rss_default_cpu, |
178 | rss_hash_type, rss_hash_bits, rss_base_cpu, |
179 | rss_enable, tso_ipid_split_en, ig_vlan_strip_en); |
180 | |
181 | a0 = nic_cfg; |
182 | a1 = 0; |
183 | |
184 | return vnic_dev_cmd(vdev: fnic->vdev, cmd: CMD_NIC_CFG, a0: &a0, a1: &a1, wait); |
185 | } |
186 | |
187 | void fnic_get_res_counts(struct fnic *fnic) |
188 | { |
189 | fnic->wq_count = vnic_dev_get_res_count(vdev: fnic->vdev, type: RES_TYPE_WQ); |
190 | fnic->raw_wq_count = fnic->wq_count - 1; |
191 | fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count; |
192 | fnic->rq_count = vnic_dev_get_res_count(vdev: fnic->vdev, type: RES_TYPE_RQ); |
193 | fnic->cq_count = vnic_dev_get_res_count(vdev: fnic->vdev, type: RES_TYPE_CQ); |
194 | fnic->intr_count = vnic_dev_get_res_count(vdev: fnic->vdev, |
195 | type: RES_TYPE_INTR_CTRL); |
196 | } |
197 | |
198 | void fnic_free_vnic_resources(struct fnic *fnic) |
199 | { |
200 | unsigned int i; |
201 | |
202 | for (i = 0; i < fnic->raw_wq_count; i++) |
203 | vnic_wq_free(wq: &fnic->wq[i]); |
204 | |
205 | for (i = 0; i < fnic->wq_copy_count; i++) |
206 | vnic_wq_copy_free(wq: &fnic->wq_copy[i]); |
207 | |
208 | for (i = 0; i < fnic->rq_count; i++) |
209 | vnic_rq_free(rq: &fnic->rq[i]); |
210 | |
211 | for (i = 0; i < fnic->cq_count; i++) |
212 | vnic_cq_free(cq: &fnic->cq[i]); |
213 | |
214 | for (i = 0; i < fnic->intr_count; i++) |
215 | vnic_intr_free(intr: &fnic->intr[i]); |
216 | } |
217 | |
218 | int fnic_alloc_vnic_resources(struct fnic *fnic) |
219 | { |
220 | enum vnic_dev_intr_mode intr_mode; |
221 | unsigned int mask_on_assertion; |
222 | unsigned int interrupt_offset; |
223 | unsigned int error_interrupt_enable; |
224 | unsigned int error_interrupt_offset; |
225 | unsigned int i, cq_index; |
226 | unsigned int wq_copy_cq_desc_count; |
227 | int err; |
228 | |
229 | intr_mode = vnic_dev_get_intr_mode(vdev: fnic->vdev); |
230 | |
231 | shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n" , |
232 | intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" : |
233 | intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" : |
234 | intr_mode == VNIC_DEV_INTR_MODE_MSIX ? |
235 | "MSI-X" : "unknown" ); |
236 | |
237 | shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: " |
238 | "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n" , |
239 | fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count, |
240 | fnic->rq_count, fnic->cq_count, fnic->intr_count); |
241 | |
242 | /* Allocate Raw WQ used for FCS frames */ |
243 | for (i = 0; i < fnic->raw_wq_count; i++) { |
244 | err = vnic_wq_alloc(vdev: fnic->vdev, wq: &fnic->wq[i], index: i, |
245 | desc_count: fnic->config.wq_enet_desc_count, |
246 | desc_size: sizeof(struct wq_enet_desc)); |
247 | if (err) |
248 | goto err_out_cleanup; |
249 | } |
250 | |
251 | /* Allocate Copy WQs used for SCSI IOs */ |
252 | for (i = 0; i < fnic->wq_copy_count; i++) { |
253 | err = vnic_wq_copy_alloc(vdev: fnic->vdev, wq: &fnic->wq_copy[i], |
254 | index: (fnic->raw_wq_count + i), |
255 | desc_count: fnic->config.wq_copy_desc_count, |
256 | desc_size: sizeof(struct fcpio_host_req)); |
257 | if (err) |
258 | goto err_out_cleanup; |
259 | } |
260 | |
261 | /* RQ for receiving FCS frames */ |
262 | for (i = 0; i < fnic->rq_count; i++) { |
263 | err = vnic_rq_alloc(vdev: fnic->vdev, rq: &fnic->rq[i], index: i, |
264 | desc_count: fnic->config.rq_desc_count, |
265 | desc_size: sizeof(struct rq_enet_desc)); |
266 | if (err) |
267 | goto err_out_cleanup; |
268 | } |
269 | |
270 | /* CQ for each RQ */ |
271 | for (i = 0; i < fnic->rq_count; i++) { |
272 | cq_index = i; |
273 | err = vnic_cq_alloc(vdev: fnic->vdev, |
274 | cq: &fnic->cq[cq_index], index: cq_index, |
275 | desc_count: fnic->config.rq_desc_count, |
276 | desc_size: sizeof(struct cq_enet_rq_desc)); |
277 | if (err) |
278 | goto err_out_cleanup; |
279 | } |
280 | |
281 | /* CQ for each WQ */ |
282 | for (i = 0; i < fnic->raw_wq_count; i++) { |
283 | cq_index = fnic->rq_count + i; |
284 | err = vnic_cq_alloc(vdev: fnic->vdev, cq: &fnic->cq[cq_index], index: cq_index, |
285 | desc_count: fnic->config.wq_enet_desc_count, |
286 | desc_size: sizeof(struct cq_enet_wq_desc)); |
287 | if (err) |
288 | goto err_out_cleanup; |
289 | } |
290 | |
291 | /* CQ for each COPY WQ */ |
292 | wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3); |
293 | for (i = 0; i < fnic->wq_copy_count; i++) { |
294 | cq_index = fnic->raw_wq_count + fnic->rq_count + i; |
295 | err = vnic_cq_alloc(vdev: fnic->vdev, cq: &fnic->cq[cq_index], |
296 | index: cq_index, |
297 | desc_count: wq_copy_cq_desc_count, |
298 | desc_size: sizeof(struct fcpio_fw_req)); |
299 | if (err) |
300 | goto err_out_cleanup; |
301 | } |
302 | |
303 | for (i = 0; i < fnic->intr_count; i++) { |
304 | err = vnic_intr_alloc(vdev: fnic->vdev, intr: &fnic->intr[i], index: i); |
305 | if (err) |
306 | goto err_out_cleanup; |
307 | } |
308 | |
309 | fnic->legacy_pba = vnic_dev_get_res(vdev: fnic->vdev, |
310 | type: RES_TYPE_INTR_PBA_LEGACY, index: 0); |
311 | |
312 | if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) { |
313 | shost_printk(KERN_ERR, fnic->lport->host, |
314 | "Failed to hook legacy pba resource\n" ); |
315 | err = -ENODEV; |
316 | goto err_out_cleanup; |
317 | } |
318 | |
319 | /* |
320 | * Init RQ/WQ resources. |
321 | * |
322 | * RQ[0 to n-1] point to CQ[0 to n-1] |
323 | * WQ[0 to m-1] point to CQ[n to n+m-1] |
324 | * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1] |
325 | * |
326 | * Note for copy wq we always initialize with cq_index = 0 |
327 | * |
328 | * Error interrupt is not enabled for MSI. |
329 | */ |
330 | |
331 | switch (intr_mode) { |
332 | case VNIC_DEV_INTR_MODE_INTX: |
333 | case VNIC_DEV_INTR_MODE_MSIX: |
334 | error_interrupt_enable = 1; |
335 | error_interrupt_offset = fnic->err_intr_offset; |
336 | break; |
337 | default: |
338 | error_interrupt_enable = 0; |
339 | error_interrupt_offset = 0; |
340 | break; |
341 | } |
342 | |
343 | for (i = 0; i < fnic->rq_count; i++) { |
344 | cq_index = i; |
345 | vnic_rq_init(rq: &fnic->rq[i], |
346 | cq_index, |
347 | error_interrupt_enable, |
348 | error_interrupt_offset); |
349 | } |
350 | |
351 | for (i = 0; i < fnic->raw_wq_count; i++) { |
352 | cq_index = i + fnic->rq_count; |
353 | vnic_wq_init(wq: &fnic->wq[i], |
354 | cq_index, |
355 | error_interrupt_enable, |
356 | error_interrupt_offset); |
357 | } |
358 | |
359 | for (i = 0; i < fnic->wq_copy_count; i++) { |
360 | vnic_wq_copy_init(wq: &fnic->wq_copy[i], |
361 | cq_index: 0 /* cq_index 0 - always */, |
362 | error_interrupt_enable, |
363 | error_interrupt_offset); |
364 | } |
365 | |
366 | for (i = 0; i < fnic->cq_count; i++) { |
367 | |
368 | switch (intr_mode) { |
369 | case VNIC_DEV_INTR_MODE_MSIX: |
370 | interrupt_offset = i; |
371 | break; |
372 | default: |
373 | interrupt_offset = 0; |
374 | break; |
375 | } |
376 | |
377 | vnic_cq_init(cq: &fnic->cq[i], |
378 | flow_control_enable: 0 /* flow_control_enable */, |
379 | color_enable: 1 /* color_enable */, |
380 | cq_head: 0 /* cq_head */, |
381 | cq_tail: 0 /* cq_tail */, |
382 | cq_tail_color: 1 /* cq_tail_color */, |
383 | interrupt_enable: 1 /* interrupt_enable */, |
384 | cq_entry_enable: 1 /* cq_entry_enable */, |
385 | message_enable: 0 /* cq_message_enable */, |
386 | interrupt_offset, |
387 | message_addr: 0 /* cq_message_addr */); |
388 | } |
389 | |
390 | /* |
391 | * Init INTR resources |
392 | * |
393 | * mask_on_assertion is not used for INTx due to the level- |
394 | * triggered nature of INTx |
395 | */ |
396 | |
397 | switch (intr_mode) { |
398 | case VNIC_DEV_INTR_MODE_MSI: |
399 | case VNIC_DEV_INTR_MODE_MSIX: |
400 | mask_on_assertion = 1; |
401 | break; |
402 | default: |
403 | mask_on_assertion = 0; |
404 | break; |
405 | } |
406 | |
407 | for (i = 0; i < fnic->intr_count; i++) { |
408 | vnic_intr_init(intr: &fnic->intr[i], |
409 | coalescing_timer: fnic->config.intr_timer, |
410 | coalescing_type: fnic->config.intr_timer_type, |
411 | mask_on_assertion); |
412 | } |
413 | |
414 | /* init the stats memory by making the first call here */ |
415 | err = vnic_dev_stats_dump(vdev: fnic->vdev, stats: &fnic->stats); |
416 | if (err) { |
417 | shost_printk(KERN_ERR, fnic->lport->host, |
418 | "vnic_dev_stats_dump failed - x%x\n" , err); |
419 | goto err_out_cleanup; |
420 | } |
421 | |
422 | /* Clear LIF stats */ |
423 | vnic_dev_stats_clear(vdev: fnic->vdev); |
424 | |
425 | return 0; |
426 | |
427 | err_out_cleanup: |
428 | fnic_free_vnic_resources(fnic); |
429 | |
430 | return err; |
431 | } |
432 | |