1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * QLogic qlcnic NIC Driver |
4 | * Copyright (c) 2009-2013 QLogic Corporation |
5 | */ |
6 | |
7 | #include "qlcnic.h" |
8 | |
9 | static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = { |
10 | {QLCNIC_CMD_CREATE_RX_CTX, 4, 1}, |
11 | {QLCNIC_CMD_DESTROY_RX_CTX, 2, 1}, |
12 | {QLCNIC_CMD_CREATE_TX_CTX, 4, 1}, |
13 | {QLCNIC_CMD_DESTROY_TX_CTX, 3, 1}, |
14 | {QLCNIC_CMD_INTRPT_TEST, 4, 1}, |
15 | {QLCNIC_CMD_SET_MTU, 4, 1}, |
16 | {QLCNIC_CMD_READ_PHY, 4, 2}, |
17 | {QLCNIC_CMD_WRITE_PHY, 5, 1}, |
18 | {QLCNIC_CMD_READ_HW_REG, 4, 1}, |
19 | {QLCNIC_CMD_GET_FLOW_CTL, 4, 2}, |
20 | {QLCNIC_CMD_SET_FLOW_CTL, 4, 1}, |
21 | {QLCNIC_CMD_READ_MAX_MTU, 4, 2}, |
22 | {QLCNIC_CMD_READ_MAX_LRO, 4, 2}, |
23 | {QLCNIC_CMD_MAC_ADDRESS, 4, 3}, |
24 | {QLCNIC_CMD_GET_PCI_INFO, 4, 1}, |
25 | {QLCNIC_CMD_GET_NIC_INFO, 4, 1}, |
26 | {QLCNIC_CMD_SET_NIC_INFO, 4, 1}, |
27 | {QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3}, |
28 | {QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1}, |
29 | {QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3}, |
30 | {QLCNIC_CMD_SET_PORTMIRRORING, 4, 1}, |
31 | {QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1}, |
32 | {QLCNIC_CMD_GET_MAC_STATS, 4, 1}, |
33 | {QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3}, |
34 | {QLCNIC_CMD_GET_ESWITCH_STATS, 4, 1}, |
35 | {QLCNIC_CMD_CONFIG_PORT, 4, 1}, |
36 | {QLCNIC_CMD_TEMP_SIZE, 4, 4}, |
37 | {QLCNIC_CMD_GET_TEMP_HDR, 4, 1}, |
38 | {QLCNIC_CMD_82XX_SET_DRV_VER, 4, 1}, |
39 | {QLCNIC_CMD_GET_LED_STATUS, 4, 2}, |
40 | {QLCNIC_CMD_MQ_TX_CONFIG_INTR, 2, 3}, |
41 | {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, |
42 | {QLCNIC_CMD_DCB_QUERY_PARAM, 4, 1}, |
43 | }; |
44 | |
45 | static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw) |
46 | { |
47 | return (ahw->pci_func & 0xff) | ((ahw->fw_hal_version & 0xff) << 8) | |
48 | (0xcafe << 16); |
49 | } |
50 | |
51 | /* Allocate mailbox registers */ |
52 | int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, |
53 | struct qlcnic_adapter *adapter, u32 type) |
54 | { |
55 | int i, size; |
56 | const struct qlcnic_mailbox_metadata *mbx_tbl; |
57 | |
58 | mbx_tbl = qlcnic_mbx_tbl; |
59 | size = ARRAY_SIZE(qlcnic_mbx_tbl); |
60 | for (i = 0; i < size; i++) { |
61 | if (type == mbx_tbl[i].cmd) { |
62 | mbx->req.num = mbx_tbl[i].in_args; |
63 | mbx->rsp.num = mbx_tbl[i].out_args; |
64 | mbx->req.arg = kcalloc(n: mbx->req.num, |
65 | size: sizeof(u32), GFP_ATOMIC); |
66 | if (!mbx->req.arg) |
67 | return -ENOMEM; |
68 | mbx->rsp.arg = kcalloc(n: mbx->rsp.num, |
69 | size: sizeof(u32), GFP_ATOMIC); |
70 | if (!mbx->rsp.arg) { |
71 | kfree(objp: mbx->req.arg); |
72 | mbx->req.arg = NULL; |
73 | return -ENOMEM; |
74 | } |
75 | mbx->req.arg[0] = type; |
76 | break; |
77 | } |
78 | } |
79 | return 0; |
80 | } |
81 | |
82 | /* Free up mailbox registers */ |
83 | void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd) |
84 | { |
85 | kfree(objp: cmd->req.arg); |
86 | cmd->req.arg = NULL; |
87 | kfree(objp: cmd->rsp.arg); |
88 | cmd->rsp.arg = NULL; |
89 | } |
90 | |
91 | static u32 |
92 | qlcnic_poll_rsp(struct qlcnic_adapter *adapter) |
93 | { |
94 | u32 rsp; |
95 | int timeout = 0, err = 0; |
96 | |
97 | do { |
98 | /* give atleast 1ms for firmware to respond */ |
99 | mdelay(1); |
100 | |
101 | if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) |
102 | return QLCNIC_CDRP_RSP_TIMEOUT; |
103 | |
104 | rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err); |
105 | } while (!QLCNIC_CDRP_IS_RSP(rsp)); |
106 | |
107 | return rsp; |
108 | } |
109 | |
110 | int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, |
111 | struct qlcnic_cmd_args *cmd) |
112 | { |
113 | int i, err = 0; |
114 | u32 rsp; |
115 | u32 signature; |
116 | struct pci_dev *pdev = adapter->pdev; |
117 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
118 | const char *fmt; |
119 | |
120 | signature = qlcnic_get_cmd_signature(ahw); |
121 | |
122 | /* Acquire semaphore before accessing CRB */ |
123 | if (qlcnic_api_lock(adapter)) { |
124 | cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; |
125 | return cmd->rsp.arg[0]; |
126 | } |
127 | |
128 | QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature); |
129 | for (i = 1; i < cmd->req.num; i++) |
130 | QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]); |
131 | QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, |
132 | QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0])); |
133 | rsp = qlcnic_poll_rsp(adapter); |
134 | |
135 | if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) { |
136 | dev_err(&pdev->dev, "command timeout, response = 0x%x\n" , rsp); |
137 | cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; |
138 | } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { |
139 | cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err); |
140 | switch (cmd->rsp.arg[0]) { |
141 | case QLCNIC_RCODE_INVALID_ARGS: |
142 | fmt = "CDRP invalid args: [%d]\n" ; |
143 | break; |
144 | case QLCNIC_RCODE_NOT_SUPPORTED: |
145 | case QLCNIC_RCODE_NOT_IMPL: |
146 | fmt = "CDRP command not supported: [%d]\n" ; |
147 | break; |
148 | case QLCNIC_RCODE_NOT_PERMITTED: |
149 | fmt = "CDRP requested action not permitted: [%d]\n" ; |
150 | break; |
151 | case QLCNIC_RCODE_INVALID: |
152 | fmt = "CDRP invalid or unknown cmd received: [%d]\n" ; |
153 | break; |
154 | case QLCNIC_RCODE_TIMEOUT: |
155 | fmt = "CDRP command timeout: [%d]\n" ; |
156 | break; |
157 | default: |
158 | fmt = "CDRP command failed: [%d]\n" ; |
159 | break; |
160 | } |
161 | dev_err(&pdev->dev, fmt, cmd->rsp.arg[0]); |
162 | qlcnic_dump_mbx(adapter, cmd); |
163 | } else if (rsp == QLCNIC_CDRP_RSP_OK) |
164 | cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS; |
165 | |
166 | for (i = 1; i < cmd->rsp.num; i++) |
167 | cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err); |
168 | |
169 | /* Release semaphore */ |
170 | qlcnic_api_unlock(adapter); |
171 | return cmd->rsp.arg[0]; |
172 | } |
173 | |
174 | int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd) |
175 | { |
176 | struct qlcnic_cmd_args cmd; |
177 | u32 arg1, arg2, arg3; |
178 | char drv_string[12]; |
179 | int err = 0; |
180 | |
181 | memset(drv_string, 0, sizeof(drv_string)); |
182 | snprintf(buf: drv_string, size: sizeof(drv_string), fmt: "%d" "." "%d" "." "%d" , |
183 | _QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR, |
184 | _QLCNIC_LINUX_SUBVERSION); |
185 | |
186 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, arg: fw_cmd); |
187 | if (err) |
188 | return err; |
189 | |
190 | memcpy(&arg1, drv_string, sizeof(u32)); |
191 | memcpy(&arg2, drv_string + 4, sizeof(u32)); |
192 | memcpy(&arg3, drv_string + 8, sizeof(u32)); |
193 | |
194 | cmd.req.arg[1] = arg1; |
195 | cmd.req.arg[2] = arg2; |
196 | cmd.req.arg[3] = arg3; |
197 | |
198 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
199 | if (err) { |
200 | dev_info(&adapter->pdev->dev, |
201 | "Failed to set driver version in firmware\n" ); |
202 | err = -EIO; |
203 | } |
204 | qlcnic_free_mbx_args(cmd: &cmd); |
205 | return err; |
206 | } |
207 | |
208 | int |
209 | qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) |
210 | { |
211 | int err = 0; |
212 | struct qlcnic_cmd_args cmd; |
213 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; |
214 | |
215 | if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE) |
216 | return err; |
217 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_SET_MTU); |
218 | if (err) |
219 | return err; |
220 | |
221 | cmd.req.arg[1] = recv_ctx->context_id; |
222 | cmd.req.arg[2] = mtu; |
223 | |
224 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
225 | if (err) { |
226 | dev_err(&adapter->pdev->dev, "Failed to set mtu\n" ); |
227 | err = -EIO; |
228 | } |
229 | qlcnic_free_mbx_args(cmd: &cmd); |
230 | return err; |
231 | } |
232 | |
233 | int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) |
234 | { |
235 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; |
236 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
237 | dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; |
238 | struct net_device *netdev = adapter->netdev; |
239 | u32 temp_intr_crb_mode, temp_rds_crb_mode; |
240 | struct qlcnic_cardrsp_rds_ring *prsp_rds; |
241 | struct qlcnic_cardrsp_sds_ring *prsp_sds; |
242 | struct qlcnic_hostrq_rds_ring *prq_rds; |
243 | struct qlcnic_hostrq_sds_ring *prq_sds; |
244 | struct qlcnic_host_rds_ring *rds_ring; |
245 | struct qlcnic_host_sds_ring *sds_ring; |
246 | struct qlcnic_cardrsp_rx_ctx *prsp; |
247 | struct qlcnic_hostrq_rx_ctx *prq; |
248 | u8 i, nrds_rings, nsds_rings; |
249 | struct qlcnic_cmd_args cmd; |
250 | size_t rq_size, rsp_size; |
251 | u32 cap, reg, val, reg2; |
252 | u64 phys_addr; |
253 | u16 temp_u16; |
254 | void *addr; |
255 | int err; |
256 | |
257 | nrds_rings = adapter->max_rds_rings; |
258 | nsds_rings = adapter->drv_sds_rings; |
259 | |
260 | rq_size = SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings, |
261 | nsds_rings); |
262 | rsp_size = SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, |
263 | nsds_rings); |
264 | |
265 | addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: rq_size, |
266 | dma_handle: &hostrq_phys_addr, GFP_KERNEL); |
267 | if (addr == NULL) |
268 | return -ENOMEM; |
269 | prq = addr; |
270 | |
271 | addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: rsp_size, |
272 | dma_handle: &cardrsp_phys_addr, GFP_KERNEL); |
273 | if (addr == NULL) { |
274 | err = -ENOMEM; |
275 | goto out_free_rq; |
276 | } |
277 | prsp = addr; |
278 | |
279 | prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr); |
280 | |
281 | cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
282 | | QLCNIC_CAP0_VALIDOFF); |
283 | cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS); |
284 | |
285 | if (qlcnic_check_multi_tx(adapter) && |
286 | !adapter->ahw->diag_test) { |
287 | cap |= QLCNIC_CAP0_TX_MULTI; |
288 | } else { |
289 | temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler); |
290 | prq->valid_field_offset = cpu_to_le16(temp_u16); |
291 | prq->txrx_sds_binding = nsds_rings - 1; |
292 | temp_intr_crb_mode = QLCNIC_HOST_INT_CRB_MODE_SHARED; |
293 | prq->host_int_crb_mode = cpu_to_le32(temp_intr_crb_mode); |
294 | temp_rds_crb_mode = QLCNIC_HOST_RDS_CRB_MODE_UNIQUE; |
295 | prq->host_rds_crb_mode = cpu_to_le32(temp_rds_crb_mode); |
296 | } |
297 | |
298 | prq->capabilities[0] = cpu_to_le32(cap); |
299 | |
300 | prq->num_rds_rings = cpu_to_le16(nrds_rings); |
301 | prq->num_sds_rings = cpu_to_le16(nsds_rings); |
302 | prq->rds_ring_offset = 0; |
303 | |
304 | val = le32_to_cpu(prq->rds_ring_offset) + |
305 | (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); |
306 | prq->sds_ring_offset = cpu_to_le32(val); |
307 | |
308 | prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data + |
309 | le32_to_cpu(prq->rds_ring_offset)); |
310 | |
311 | for (i = 0; i < nrds_rings; i++) { |
312 | rds_ring = &recv_ctx->rds_rings[i]; |
313 | rds_ring->producer = 0; |
314 | prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr); |
315 | prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc); |
316 | prq_rds[i].ring_kind = cpu_to_le32(i); |
317 | prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size); |
318 | } |
319 | |
320 | prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data + |
321 | le32_to_cpu(prq->sds_ring_offset)); |
322 | |
323 | for (i = 0; i < nsds_rings; i++) { |
324 | sds_ring = &recv_ctx->sds_rings[i]; |
325 | sds_ring->consumer = 0; |
326 | memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring)); |
327 | prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr); |
328 | prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc); |
329 | if (qlcnic_check_multi_tx(adapter) && |
330 | !adapter->ahw->diag_test) |
331 | prq_sds[i].msi_index = cpu_to_le16(ahw->intr_tbl[i].id); |
332 | else |
333 | prq_sds[i].msi_index = cpu_to_le16(i); |
334 | } |
335 | |
336 | phys_addr = hostrq_phys_addr; |
337 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX); |
338 | if (err) |
339 | goto out_free_rsp; |
340 | |
341 | cmd.req.arg[1] = MSD(phys_addr); |
342 | cmd.req.arg[2] = LSD(phys_addr); |
343 | cmd.req.arg[3] = rq_size; |
344 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
345 | if (err) { |
346 | dev_err(&adapter->pdev->dev, |
347 | "Failed to create rx ctx in firmware%d\n" , err); |
348 | goto out_free_rsp; |
349 | } |
350 | |
351 | prsp_rds = ((struct qlcnic_cardrsp_rds_ring *) |
352 | &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]); |
353 | |
354 | for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) { |
355 | rds_ring = &recv_ctx->rds_rings[i]; |
356 | reg = le32_to_cpu(prsp_rds[i].host_producer_crb); |
357 | rds_ring->crb_rcv_producer = ahw->pci_base0 + reg; |
358 | } |
359 | |
360 | prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) |
361 | &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]); |
362 | |
363 | for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) { |
364 | sds_ring = &recv_ctx->sds_rings[i]; |
365 | reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); |
366 | if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) |
367 | reg2 = ahw->intr_tbl[i].src; |
368 | else |
369 | reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb); |
370 | |
371 | sds_ring->crb_intr_mask = ahw->pci_base0 + reg2; |
372 | sds_ring->crb_sts_consumer = ahw->pci_base0 + reg; |
373 | } |
374 | |
375 | recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); |
376 | recv_ctx->context_id = le16_to_cpu(prsp->context_id); |
377 | recv_ctx->virt_port = prsp->virt_port; |
378 | |
379 | netdev_info(dev: netdev, format: "Rx Context[%d] Created, state 0x%x\n" , |
380 | recv_ctx->context_id, recv_ctx->state); |
381 | qlcnic_free_mbx_args(cmd: &cmd); |
382 | |
383 | out_free_rsp: |
384 | dma_free_coherent(dev: &adapter->pdev->dev, size: rsp_size, cpu_addr: prsp, |
385 | dma_handle: cardrsp_phys_addr); |
386 | out_free_rq: |
387 | dma_free_coherent(dev: &adapter->pdev->dev, size: rq_size, cpu_addr: prq, dma_handle: hostrq_phys_addr); |
388 | |
389 | return err; |
390 | } |
391 | |
392 | void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter) |
393 | { |
394 | int err; |
395 | struct qlcnic_cmd_args cmd; |
396 | struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; |
397 | |
398 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX); |
399 | if (err) |
400 | return; |
401 | |
402 | cmd.req.arg[1] = recv_ctx->context_id; |
403 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
404 | if (err) |
405 | dev_err(&adapter->pdev->dev, |
406 | "Failed to destroy rx ctx in firmware\n" ); |
407 | |
408 | recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED; |
409 | qlcnic_free_mbx_args(cmd: &cmd); |
410 | } |
411 | |
412 | int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter, |
413 | struct qlcnic_host_tx_ring *tx_ring, |
414 | int ring) |
415 | { |
416 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
417 | struct net_device *netdev = adapter->netdev; |
418 | struct qlcnic_hostrq_tx_ctx *prq; |
419 | struct qlcnic_hostrq_cds_ring *prq_cds; |
420 | struct qlcnic_cardrsp_tx_ctx *prsp; |
421 | struct qlcnic_cmd_args cmd; |
422 | u32 temp, intr_mask, temp_int_crb_mode; |
423 | dma_addr_t rq_phys_addr, rsp_phys_addr; |
424 | int temp_nsds_rings, index, err; |
425 | void *rq_addr, *rsp_addr; |
426 | size_t rq_size, rsp_size; |
427 | u64 phys_addr; |
428 | u16 msix_id; |
429 | |
430 | /* reset host resources */ |
431 | tx_ring->producer = 0; |
432 | tx_ring->sw_consumer = 0; |
433 | *(tx_ring->hw_consumer) = 0; |
434 | |
435 | rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); |
436 | rq_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: rq_size, |
437 | dma_handle: &rq_phys_addr, GFP_KERNEL); |
438 | if (!rq_addr) |
439 | return -ENOMEM; |
440 | |
441 | rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); |
442 | rsp_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: rsp_size, |
443 | dma_handle: &rsp_phys_addr, GFP_KERNEL); |
444 | if (!rsp_addr) { |
445 | err = -ENOMEM; |
446 | goto out_free_rq; |
447 | } |
448 | |
449 | prq = rq_addr; |
450 | prsp = rsp_addr; |
451 | |
452 | prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr); |
453 | |
454 | temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN | |
455 | QLCNIC_CAP0_LSO); |
456 | if (qlcnic_check_multi_tx(adapter) && !adapter->ahw->diag_test) |
457 | temp |= QLCNIC_CAP0_TX_MULTI; |
458 | |
459 | prq->capabilities[0] = cpu_to_le32(temp); |
460 | |
461 | if (qlcnic_check_multi_tx(adapter) && |
462 | !adapter->ahw->diag_test) { |
463 | temp_nsds_rings = adapter->drv_sds_rings; |
464 | index = temp_nsds_rings + ring; |
465 | msix_id = ahw->intr_tbl[index].id; |
466 | prq->msi_index = cpu_to_le16(msix_id); |
467 | } else { |
468 | temp_int_crb_mode = QLCNIC_HOST_INT_CRB_MODE_SHARED; |
469 | prq->host_int_crb_mode = cpu_to_le32(temp_int_crb_mode); |
470 | prq->msi_index = 0; |
471 | } |
472 | |
473 | prq->interrupt_ctl = 0; |
474 | prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr); |
475 | |
476 | prq_cds = &prq->cds_ring; |
477 | |
478 | prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr); |
479 | prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc); |
480 | |
481 | phys_addr = rq_phys_addr; |
482 | |
483 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX); |
484 | if (err) |
485 | goto out_free_rsp; |
486 | |
487 | cmd.req.arg[1] = MSD(phys_addr); |
488 | cmd.req.arg[2] = LSD(phys_addr); |
489 | cmd.req.arg[3] = rq_size; |
490 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
491 | |
492 | if (err == QLCNIC_RCODE_SUCCESS) { |
493 | tx_ring->state = le32_to_cpu(prsp->host_ctx_state); |
494 | temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); |
495 | tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp; |
496 | tx_ring->ctx_id = le16_to_cpu(prsp->context_id); |
497 | if (qlcnic_check_multi_tx(adapter) && |
498 | !adapter->ahw->diag_test && |
499 | (adapter->flags & QLCNIC_MSIX_ENABLED)) { |
500 | index = adapter->drv_sds_rings + ring; |
501 | intr_mask = ahw->intr_tbl[index].src; |
502 | tx_ring->crb_intr_mask = ahw->pci_base0 + intr_mask; |
503 | } |
504 | |
505 | netdev_info(dev: netdev, format: "Tx Context[0x%x] Created, state 0x%x\n" , |
506 | tx_ring->ctx_id, tx_ring->state); |
507 | } else { |
508 | netdev_err(dev: netdev, format: "Failed to create tx ctx in firmware%d\n" , |
509 | err); |
510 | err = -EIO; |
511 | } |
512 | qlcnic_free_mbx_args(cmd: &cmd); |
513 | |
514 | out_free_rsp: |
515 | dma_free_coherent(dev: &adapter->pdev->dev, size: rsp_size, cpu_addr: rsp_addr, |
516 | dma_handle: rsp_phys_addr); |
517 | out_free_rq: |
518 | dma_free_coherent(dev: &adapter->pdev->dev, size: rq_size, cpu_addr: rq_addr, dma_handle: rq_phys_addr); |
519 | |
520 | return err; |
521 | } |
522 | |
523 | void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter, |
524 | struct qlcnic_host_tx_ring *tx_ring) |
525 | { |
526 | struct qlcnic_cmd_args cmd; |
527 | int ret; |
528 | |
529 | ret = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX); |
530 | if (ret) |
531 | return; |
532 | |
533 | cmd.req.arg[1] = tx_ring->ctx_id; |
534 | if (qlcnic_issue_cmd(adapter, cmd: &cmd)) |
535 | dev_err(&adapter->pdev->dev, |
536 | "Failed to destroy tx ctx in firmware\n" ); |
537 | qlcnic_free_mbx_args(cmd: &cmd); |
538 | } |
539 | |
540 | int |
541 | qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config) |
542 | { |
543 | int err; |
544 | struct qlcnic_cmd_args cmd; |
545 | |
546 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_CONFIG_PORT); |
547 | if (err) |
548 | return err; |
549 | |
550 | cmd.req.arg[1] = config; |
551 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
552 | qlcnic_free_mbx_args(cmd: &cmd); |
553 | return err; |
554 | } |
555 | |
556 | int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) |
557 | { |
558 | void *addr; |
559 | int err, ring; |
560 | struct qlcnic_recv_context *recv_ctx; |
561 | struct qlcnic_host_rds_ring *rds_ring; |
562 | struct qlcnic_host_sds_ring *sds_ring; |
563 | struct qlcnic_host_tx_ring *tx_ring; |
564 | __le32 *ptr; |
565 | |
566 | struct pci_dev *pdev = adapter->pdev; |
567 | |
568 | recv_ctx = adapter->recv_ctx; |
569 | |
570 | for (ring = 0; ring < adapter->drv_tx_rings; ring++) { |
571 | tx_ring = &adapter->tx_ring[ring]; |
572 | ptr = (__le32 *)dma_alloc_coherent(dev: &pdev->dev, size: sizeof(u32), |
573 | dma_handle: &tx_ring->hw_cons_phys_addr, |
574 | GFP_KERNEL); |
575 | if (ptr == NULL) { |
576 | err = -ENOMEM; |
577 | goto err_out_free; |
578 | } |
579 | |
580 | tx_ring->hw_consumer = ptr; |
581 | /* cmd desc ring */ |
582 | addr = dma_alloc_coherent(dev: &pdev->dev, TX_DESC_RINGSIZE(tx_ring), |
583 | dma_handle: &tx_ring->phys_addr, |
584 | GFP_KERNEL); |
585 | if (addr == NULL) { |
586 | err = -ENOMEM; |
587 | goto err_out_free; |
588 | } |
589 | |
590 | tx_ring->desc_head = addr; |
591 | } |
592 | |
593 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { |
594 | rds_ring = &recv_ctx->rds_rings[ring]; |
595 | addr = dma_alloc_coherent(dev: &adapter->pdev->dev, |
596 | RCV_DESC_RINGSIZE(rds_ring), |
597 | dma_handle: &rds_ring->phys_addr, GFP_KERNEL); |
598 | if (addr == NULL) { |
599 | err = -ENOMEM; |
600 | goto err_out_free; |
601 | } |
602 | rds_ring->desc_head = addr; |
603 | |
604 | } |
605 | |
606 | for (ring = 0; ring < adapter->drv_sds_rings; ring++) { |
607 | sds_ring = &recv_ctx->sds_rings[ring]; |
608 | |
609 | addr = dma_alloc_coherent(dev: &adapter->pdev->dev, |
610 | STATUS_DESC_RINGSIZE(sds_ring), |
611 | dma_handle: &sds_ring->phys_addr, GFP_KERNEL); |
612 | if (addr == NULL) { |
613 | err = -ENOMEM; |
614 | goto err_out_free; |
615 | } |
616 | sds_ring->desc_head = addr; |
617 | } |
618 | |
619 | return 0; |
620 | |
621 | err_out_free: |
622 | qlcnic_free_hw_resources(adapter); |
623 | return err; |
624 | } |
625 | |
626 | int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev) |
627 | { |
628 | int i, err, ring; |
629 | |
630 | if (dev->flags & QLCNIC_NEED_FLR) { |
631 | err = pci_reset_function(dev: dev->pdev); |
632 | if (err) { |
633 | dev_err(&dev->pdev->dev, |
634 | "Adapter reset failed (%d). Please reboot\n" , |
635 | err); |
636 | return err; |
637 | } |
638 | dev->flags &= ~QLCNIC_NEED_FLR; |
639 | } |
640 | |
641 | if (qlcnic_83xx_check(adapter: dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) { |
642 | if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST) { |
643 | err = qlcnic_83xx_config_intrpt(dev, 1); |
644 | if (err) |
645 | return err; |
646 | } |
647 | } |
648 | |
649 | if (qlcnic_82xx_check(adapter: dev) && (dev->flags & QLCNIC_MSIX_ENABLED) && |
650 | qlcnic_check_multi_tx(adapter: dev) && !dev->ahw->diag_test) { |
651 | err = qlcnic_82xx_mq_intrpt(dev, 1); |
652 | if (err) |
653 | return err; |
654 | } |
655 | |
656 | err = qlcnic_fw_cmd_create_rx_ctx(adapter: dev); |
657 | if (err) |
658 | goto err_out; |
659 | |
660 | for (ring = 0; ring < dev->drv_tx_rings; ring++) { |
661 | err = qlcnic_fw_cmd_create_tx_ctx(adapter: dev, |
662 | ptr: &dev->tx_ring[ring], |
663 | ring); |
664 | if (err) { |
665 | qlcnic_fw_cmd_del_rx_ctx(adapter: dev); |
666 | if (ring == 0) |
667 | goto err_out; |
668 | |
669 | for (i = 0; i < ring; i++) |
670 | qlcnic_fw_cmd_del_tx_ctx(adapter: dev, ptr: &dev->tx_ring[i]); |
671 | |
672 | goto err_out; |
673 | } |
674 | } |
675 | |
676 | set_bit(__QLCNIC_FW_ATTACHED, addr: &dev->state); |
677 | |
678 | return 0; |
679 | |
680 | err_out: |
681 | if (qlcnic_82xx_check(adapter: dev) && (dev->flags & QLCNIC_MSIX_ENABLED) && |
682 | qlcnic_check_multi_tx(adapter: dev) && !dev->ahw->diag_test) |
683 | qlcnic_82xx_config_intrpt(dev, 0); |
684 | |
685 | if (qlcnic_83xx_check(adapter: dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) { |
686 | if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST) |
687 | qlcnic_83xx_config_intrpt(dev, 0); |
688 | } |
689 | |
690 | return err; |
691 | } |
692 | |
693 | void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter) |
694 | { |
695 | int ring; |
696 | |
697 | if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, addr: &adapter->state)) { |
698 | qlcnic_fw_cmd_del_rx_ctx(adapter); |
699 | for (ring = 0; ring < adapter->drv_tx_rings; ring++) |
700 | qlcnic_fw_cmd_del_tx_ctx(adapter, |
701 | ptr: &adapter->tx_ring[ring]); |
702 | |
703 | if (qlcnic_82xx_check(adapter) && |
704 | (adapter->flags & QLCNIC_MSIX_ENABLED) && |
705 | qlcnic_check_multi_tx(adapter) && |
706 | !adapter->ahw->diag_test) |
707 | qlcnic_82xx_config_intrpt(adapter, 0); |
708 | |
709 | if (qlcnic_83xx_check(adapter) && |
710 | (adapter->flags & QLCNIC_MSIX_ENABLED)) { |
711 | if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) |
712 | qlcnic_83xx_config_intrpt(adapter, 0); |
713 | } |
714 | /* Allow dma queues to drain after context reset */ |
715 | mdelay(20); |
716 | } |
717 | } |
718 | |
719 | void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) |
720 | { |
721 | struct qlcnic_recv_context *recv_ctx; |
722 | struct qlcnic_host_rds_ring *rds_ring; |
723 | struct qlcnic_host_sds_ring *sds_ring; |
724 | struct qlcnic_host_tx_ring *tx_ring; |
725 | int ring; |
726 | |
727 | recv_ctx = adapter->recv_ctx; |
728 | |
729 | for (ring = 0; ring < adapter->drv_tx_rings; ring++) { |
730 | tx_ring = &adapter->tx_ring[ring]; |
731 | if (tx_ring->hw_consumer != NULL) { |
732 | dma_free_coherent(dev: &adapter->pdev->dev, size: sizeof(u32), |
733 | cpu_addr: tx_ring->hw_consumer, |
734 | dma_handle: tx_ring->hw_cons_phys_addr); |
735 | |
736 | tx_ring->hw_consumer = NULL; |
737 | } |
738 | |
739 | if (tx_ring->desc_head != NULL) { |
740 | dma_free_coherent(dev: &adapter->pdev->dev, |
741 | TX_DESC_RINGSIZE(tx_ring), |
742 | cpu_addr: tx_ring->desc_head, |
743 | dma_handle: tx_ring->phys_addr); |
744 | tx_ring->desc_head = NULL; |
745 | } |
746 | } |
747 | |
748 | for (ring = 0; ring < adapter->max_rds_rings; ring++) { |
749 | rds_ring = &recv_ctx->rds_rings[ring]; |
750 | |
751 | if (rds_ring->desc_head != NULL) { |
752 | dma_free_coherent(dev: &adapter->pdev->dev, |
753 | RCV_DESC_RINGSIZE(rds_ring), |
754 | cpu_addr: rds_ring->desc_head, |
755 | dma_handle: rds_ring->phys_addr); |
756 | rds_ring->desc_head = NULL; |
757 | } |
758 | } |
759 | |
760 | for (ring = 0; ring < adapter->drv_sds_rings; ring++) { |
761 | sds_ring = &recv_ctx->sds_rings[ring]; |
762 | |
763 | if (sds_ring->desc_head != NULL) { |
764 | dma_free_coherent(dev: &adapter->pdev->dev, |
765 | STATUS_DESC_RINGSIZE(sds_ring), |
766 | cpu_addr: sds_ring->desc_head, |
767 | dma_handle: sds_ring->phys_addr); |
768 | sds_ring->desc_head = NULL; |
769 | } |
770 | } |
771 | } |
772 | |
773 | int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type) |
774 | { |
775 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
776 | struct net_device *netdev = adapter->netdev; |
777 | struct qlcnic_cmd_args cmd; |
778 | u32 type, val; |
779 | int i, err = 0; |
780 | |
781 | for (i = 0; i < ahw->num_msix; i++) { |
782 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
783 | QLCNIC_CMD_MQ_TX_CONFIG_INTR); |
784 | if (err) |
785 | return err; |
786 | type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL; |
787 | val = type | (ahw->intr_tbl[i].type << 4); |
788 | if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX) |
789 | val |= (ahw->intr_tbl[i].id << 16); |
790 | cmd.req.arg[1] = val; |
791 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
792 | if (err) { |
793 | netdev_err(dev: netdev, format: "Failed to %s interrupts %d\n" , |
794 | op_type == QLCNIC_INTRPT_ADD ? "Add" : |
795 | "Delete" , err); |
796 | qlcnic_free_mbx_args(cmd: &cmd); |
797 | return err; |
798 | } |
799 | val = cmd.rsp.arg[1]; |
800 | if (LSB(val)) { |
801 | netdev_info(dev: netdev, |
802 | format: "failed to configure interrupt for %d\n" , |
803 | ahw->intr_tbl[i].id); |
804 | continue; |
805 | } |
806 | if (op_type) { |
807 | ahw->intr_tbl[i].id = MSW(val); |
808 | ahw->intr_tbl[i].enabled = 1; |
809 | ahw->intr_tbl[i].src = cmd.rsp.arg[2]; |
810 | } else { |
811 | ahw->intr_tbl[i].id = i; |
812 | ahw->intr_tbl[i].enabled = 0; |
813 | ahw->intr_tbl[i].src = 0; |
814 | } |
815 | qlcnic_free_mbx_args(cmd: &cmd); |
816 | } |
817 | |
818 | return err; |
819 | } |
820 | |
821 | int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac, |
822 | u8 function) |
823 | { |
824 | int err, i; |
825 | struct qlcnic_cmd_args cmd; |
826 | u32 mac_low, mac_high; |
827 | |
828 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_MAC_ADDRESS); |
829 | if (err) |
830 | return err; |
831 | |
832 | cmd.req.arg[1] = function | BIT_8; |
833 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
834 | |
835 | if (err == QLCNIC_RCODE_SUCCESS) { |
836 | mac_low = cmd.rsp.arg[1]; |
837 | mac_high = cmd.rsp.arg[2]; |
838 | |
839 | for (i = 0; i < 2; i++) |
840 | mac[i] = (u8) (mac_high >> ((1 - i) * 8)); |
841 | for (i = 2; i < 6; i++) |
842 | mac[i] = (u8) (mac_low >> ((5 - i) * 8)); |
843 | } else { |
844 | dev_err(&adapter->pdev->dev, |
845 | "Failed to get mac address%d\n" , err); |
846 | err = -EIO; |
847 | } |
848 | qlcnic_free_mbx_args(cmd: &cmd); |
849 | return err; |
850 | } |
851 | |
852 | /* Get info of a NIC partition */ |
853 | int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter, |
854 | struct qlcnic_info *npar_info, u8 func_id) |
855 | { |
856 | int err; |
857 | dma_addr_t nic_dma_t; |
858 | const struct qlcnic_info_le *nic_info; |
859 | void *nic_info_addr; |
860 | struct qlcnic_cmd_args cmd; |
861 | size_t nic_size = sizeof(struct qlcnic_info_le); |
862 | |
863 | nic_info_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: nic_size, |
864 | dma_handle: &nic_dma_t, GFP_KERNEL); |
865 | if (!nic_info_addr) |
866 | return -ENOMEM; |
867 | |
868 | nic_info = nic_info_addr; |
869 | |
870 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_GET_NIC_INFO); |
871 | if (err) |
872 | goto out_free_dma; |
873 | |
874 | cmd.req.arg[1] = MSD(nic_dma_t); |
875 | cmd.req.arg[2] = LSD(nic_dma_t); |
876 | cmd.req.arg[3] = (func_id << 16 | nic_size); |
877 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
878 | if (err != QLCNIC_RCODE_SUCCESS) { |
879 | dev_err(&adapter->pdev->dev, |
880 | "Failed to get nic info%d\n" , err); |
881 | err = -EIO; |
882 | } else { |
883 | npar_info->pci_func = le16_to_cpu(nic_info->pci_func); |
884 | npar_info->op_mode = le16_to_cpu(nic_info->op_mode); |
885 | npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw); |
886 | npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw); |
887 | npar_info->phys_port = le16_to_cpu(nic_info->phys_port); |
888 | npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode); |
889 | npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques); |
890 | npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques); |
891 | npar_info->capabilities = le32_to_cpu(nic_info->capabilities); |
892 | npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu); |
893 | } |
894 | |
895 | qlcnic_free_mbx_args(cmd: &cmd); |
896 | out_free_dma: |
897 | dma_free_coherent(dev: &adapter->pdev->dev, size: nic_size, cpu_addr: nic_info_addr, |
898 | dma_handle: nic_dma_t); |
899 | |
900 | return err; |
901 | } |
902 | |
903 | /* Configure a NIC partition */ |
904 | int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter, |
905 | struct qlcnic_info *nic) |
906 | { |
907 | int err = -EIO; |
908 | dma_addr_t nic_dma_t; |
909 | void *nic_info_addr; |
910 | struct qlcnic_cmd_args cmd; |
911 | struct qlcnic_info_le *nic_info; |
912 | size_t nic_size = sizeof(struct qlcnic_info_le); |
913 | |
914 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) |
915 | return err; |
916 | |
917 | nic_info_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: nic_size, |
918 | dma_handle: &nic_dma_t, GFP_KERNEL); |
919 | if (!nic_info_addr) |
920 | return -ENOMEM; |
921 | |
922 | nic_info = nic_info_addr; |
923 | |
924 | nic_info->pci_func = cpu_to_le16(nic->pci_func); |
925 | nic_info->op_mode = cpu_to_le16(nic->op_mode); |
926 | nic_info->phys_port = cpu_to_le16(nic->phys_port); |
927 | nic_info->switch_mode = cpu_to_le16(nic->switch_mode); |
928 | nic_info->capabilities = cpu_to_le32(nic->capabilities); |
929 | nic_info->max_mac_filters = nic->max_mac_filters; |
930 | nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques); |
931 | nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques); |
932 | nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw); |
933 | nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw); |
934 | |
935 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); |
936 | if (err) |
937 | goto out_free_dma; |
938 | |
939 | cmd.req.arg[1] = MSD(nic_dma_t); |
940 | cmd.req.arg[2] = LSD(nic_dma_t); |
941 | cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size); |
942 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
943 | |
944 | if (err != QLCNIC_RCODE_SUCCESS) { |
945 | dev_err(&adapter->pdev->dev, |
946 | "Failed to set nic info%d\n" , err); |
947 | err = -EIO; |
948 | } |
949 | |
950 | qlcnic_free_mbx_args(cmd: &cmd); |
951 | out_free_dma: |
952 | dma_free_coherent(dev: &adapter->pdev->dev, size: nic_size, cpu_addr: nic_info_addr, |
953 | dma_handle: nic_dma_t); |
954 | |
955 | return err; |
956 | } |
957 | |
958 | /* Get PCI Info of a partition */ |
959 | int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, |
960 | struct qlcnic_pci_info *pci_info) |
961 | { |
962 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
963 | size_t npar_size = sizeof(struct qlcnic_pci_info_le); |
964 | size_t pci_size = npar_size * ahw->max_vnic_func; |
965 | u16 nic = 0, fcoe = 0, iscsi = 0; |
966 | struct qlcnic_pci_info_le *npar; |
967 | struct qlcnic_cmd_args cmd; |
968 | dma_addr_t pci_info_dma_t; |
969 | void *pci_info_addr; |
970 | int err = 0, i; |
971 | |
972 | pci_info_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: pci_size, |
973 | dma_handle: &pci_info_dma_t, GFP_KERNEL); |
974 | if (!pci_info_addr) |
975 | return -ENOMEM; |
976 | |
977 | npar = pci_info_addr; |
978 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_GET_PCI_INFO); |
979 | if (err) |
980 | goto out_free_dma; |
981 | |
982 | cmd.req.arg[1] = MSD(pci_info_dma_t); |
983 | cmd.req.arg[2] = LSD(pci_info_dma_t); |
984 | cmd.req.arg[3] = pci_size; |
985 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
986 | |
987 | ahw->total_nic_func = 0; |
988 | if (err == QLCNIC_RCODE_SUCCESS) { |
989 | for (i = 0; i < ahw->max_vnic_func; i++, npar++, pci_info++) { |
990 | pci_info->id = le16_to_cpu(npar->id); |
991 | pci_info->active = le16_to_cpu(npar->active); |
992 | if (!pci_info->active) |
993 | continue; |
994 | pci_info->type = le16_to_cpu(npar->type); |
995 | err = qlcnic_get_pci_func_type(adapter, pci_info->type, |
996 | &nic, &fcoe, &iscsi); |
997 | pci_info->default_port = |
998 | le16_to_cpu(npar->default_port); |
999 | pci_info->tx_min_bw = |
1000 | le16_to_cpu(npar->tx_min_bw); |
1001 | pci_info->tx_max_bw = |
1002 | le16_to_cpu(npar->tx_max_bw); |
1003 | memcpy(pci_info->mac, npar->mac, ETH_ALEN); |
1004 | } |
1005 | } else { |
1006 | dev_err(&adapter->pdev->dev, |
1007 | "Failed to get PCI Info%d\n" , err); |
1008 | err = -EIO; |
1009 | } |
1010 | |
1011 | ahw->total_nic_func = nic; |
1012 | ahw->total_pci_func = nic + fcoe + iscsi; |
1013 | if (ahw->total_nic_func == 0 || ahw->total_pci_func == 0) { |
1014 | dev_err(&adapter->pdev->dev, |
1015 | "%s: Invalid function count: total nic func[%x], total pci func[%x]\n" , |
1016 | __func__, ahw->total_nic_func, ahw->total_pci_func); |
1017 | err = -EIO; |
1018 | } |
1019 | qlcnic_free_mbx_args(cmd: &cmd); |
1020 | out_free_dma: |
1021 | dma_free_coherent(dev: &adapter->pdev->dev, size: pci_size, cpu_addr: pci_info_addr, |
1022 | dma_handle: pci_info_dma_t); |
1023 | |
1024 | return err; |
1025 | } |
1026 | |
1027 | /* Configure eSwitch for port mirroring */ |
1028 | int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id, |
1029 | u8 enable_mirroring, u8 pci_func) |
1030 | { |
1031 | struct device *dev = &adapter->pdev->dev; |
1032 | struct qlcnic_cmd_args cmd; |
1033 | int err = -EIO; |
1034 | u32 arg1; |
1035 | |
1036 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC || |
1037 | !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) { |
1038 | dev_err(&adapter->pdev->dev, "%s: Not a management function\n" , |
1039 | __func__); |
1040 | return err; |
1041 | } |
1042 | |
1043 | arg1 = id | (enable_mirroring ? BIT_4 : 0); |
1044 | arg1 |= pci_func << 8; |
1045 | |
1046 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1047 | QLCNIC_CMD_SET_PORTMIRRORING); |
1048 | if (err) |
1049 | return err; |
1050 | |
1051 | cmd.req.arg[1] = arg1; |
1052 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1053 | |
1054 | if (err != QLCNIC_RCODE_SUCCESS) |
1055 | dev_err(dev, "Failed to configure port mirroring for vNIC function %d on eSwitch %d\n" , |
1056 | pci_func, id); |
1057 | else |
1058 | dev_info(dev, "Configured port mirroring for vNIC function %d on eSwitch %d\n" , |
1059 | pci_func, id); |
1060 | qlcnic_free_mbx_args(cmd: &cmd); |
1061 | |
1062 | return err; |
1063 | } |
1064 | |
1065 | int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, |
1066 | const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { |
1067 | |
1068 | size_t stats_size = sizeof(struct qlcnic_esw_stats_le); |
1069 | struct qlcnic_esw_stats_le *stats; |
1070 | dma_addr_t stats_dma_t; |
1071 | void *stats_addr; |
1072 | u32 arg1; |
1073 | struct qlcnic_cmd_args cmd; |
1074 | int err; |
1075 | |
1076 | if (esw_stats == NULL) |
1077 | return -ENOMEM; |
1078 | |
1079 | if ((adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) && |
1080 | (func != adapter->ahw->pci_func)) { |
1081 | dev_err(&adapter->pdev->dev, |
1082 | "Not privilege to query stats for func=%d" , func); |
1083 | return -EIO; |
1084 | } |
1085 | |
1086 | stats_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: stats_size, |
1087 | dma_handle: &stats_dma_t, GFP_KERNEL); |
1088 | if (!stats_addr) |
1089 | return -ENOMEM; |
1090 | |
1091 | arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12; |
1092 | arg1 |= rx_tx << 15 | stats_size << 16; |
1093 | |
1094 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1095 | QLCNIC_CMD_GET_ESWITCH_STATS); |
1096 | if (err) |
1097 | goto out_free_dma; |
1098 | |
1099 | cmd.req.arg[1] = arg1; |
1100 | cmd.req.arg[2] = MSD(stats_dma_t); |
1101 | cmd.req.arg[3] = LSD(stats_dma_t); |
1102 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1103 | |
1104 | if (!err) { |
1105 | stats = stats_addr; |
1106 | esw_stats->context_id = le16_to_cpu(stats->context_id); |
1107 | esw_stats->version = le16_to_cpu(stats->version); |
1108 | esw_stats->size = le16_to_cpu(stats->size); |
1109 | esw_stats->multicast_frames = |
1110 | le64_to_cpu(stats->multicast_frames); |
1111 | esw_stats->broadcast_frames = |
1112 | le64_to_cpu(stats->broadcast_frames); |
1113 | esw_stats->unicast_frames = le64_to_cpu(stats->unicast_frames); |
1114 | esw_stats->dropped_frames = le64_to_cpu(stats->dropped_frames); |
1115 | esw_stats->local_frames = le64_to_cpu(stats->local_frames); |
1116 | esw_stats->errors = le64_to_cpu(stats->errors); |
1117 | esw_stats->numbytes = le64_to_cpu(stats->numbytes); |
1118 | } |
1119 | |
1120 | qlcnic_free_mbx_args(cmd: &cmd); |
1121 | out_free_dma: |
1122 | dma_free_coherent(dev: &adapter->pdev->dev, size: stats_size, cpu_addr: stats_addr, |
1123 | dma_handle: stats_dma_t); |
1124 | |
1125 | return err; |
1126 | } |
1127 | |
1128 | /* This routine will retrieve the MAC statistics from firmware */ |
1129 | int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter, |
1130 | struct qlcnic_mac_statistics *mac_stats) |
1131 | { |
1132 | struct qlcnic_mac_statistics_le *stats; |
1133 | struct qlcnic_cmd_args cmd; |
1134 | size_t stats_size = sizeof(struct qlcnic_mac_statistics_le); |
1135 | dma_addr_t stats_dma_t; |
1136 | void *stats_addr; |
1137 | int err; |
1138 | |
1139 | if (mac_stats == NULL) |
1140 | return -ENOMEM; |
1141 | |
1142 | stats_addr = dma_alloc_coherent(dev: &adapter->pdev->dev, size: stats_size, |
1143 | dma_handle: &stats_dma_t, GFP_KERNEL); |
1144 | if (!stats_addr) |
1145 | return -ENOMEM; |
1146 | |
1147 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, QLCNIC_CMD_GET_MAC_STATS); |
1148 | if (err) |
1149 | goto out_free_dma; |
1150 | |
1151 | cmd.req.arg[1] = stats_size << 16; |
1152 | cmd.req.arg[2] = MSD(stats_dma_t); |
1153 | cmd.req.arg[3] = LSD(stats_dma_t); |
1154 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1155 | if (!err) { |
1156 | stats = stats_addr; |
1157 | mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames); |
1158 | mac_stats->mac_tx_bytes = le64_to_cpu(stats->mac_tx_bytes); |
1159 | mac_stats->mac_tx_mcast_pkts = |
1160 | le64_to_cpu(stats->mac_tx_mcast_pkts); |
1161 | mac_stats->mac_tx_bcast_pkts = |
1162 | le64_to_cpu(stats->mac_tx_bcast_pkts); |
1163 | mac_stats->mac_rx_frames = le64_to_cpu(stats->mac_rx_frames); |
1164 | mac_stats->mac_rx_bytes = le64_to_cpu(stats->mac_rx_bytes); |
1165 | mac_stats->mac_rx_mcast_pkts = |
1166 | le64_to_cpu(stats->mac_rx_mcast_pkts); |
1167 | mac_stats->mac_rx_length_error = |
1168 | le64_to_cpu(stats->mac_rx_length_error); |
1169 | mac_stats->mac_rx_length_small = |
1170 | le64_to_cpu(stats->mac_rx_length_small); |
1171 | mac_stats->mac_rx_length_large = |
1172 | le64_to_cpu(stats->mac_rx_length_large); |
1173 | mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber); |
1174 | mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped); |
1175 | mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error); |
1176 | } else { |
1177 | dev_err(&adapter->pdev->dev, |
1178 | "%s: Get mac stats failed, err=%d.\n" , __func__, err); |
1179 | } |
1180 | |
1181 | qlcnic_free_mbx_args(cmd: &cmd); |
1182 | |
1183 | out_free_dma: |
1184 | dma_free_coherent(dev: &adapter->pdev->dev, size: stats_size, cpu_addr: stats_addr, |
1185 | dma_handle: stats_dma_t); |
1186 | |
1187 | return err; |
1188 | } |
1189 | |
1190 | int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, |
1191 | const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { |
1192 | |
1193 | struct __qlcnic_esw_statistics port_stats; |
1194 | u8 i; |
1195 | int ret = -EIO; |
1196 | |
1197 | if (esw_stats == NULL) |
1198 | return -ENOMEM; |
1199 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) |
1200 | return -EIO; |
1201 | if (adapter->npars == NULL) |
1202 | return -EIO; |
1203 | |
1204 | memset(esw_stats, 0, sizeof(u64)); |
1205 | esw_stats->unicast_frames = QLCNIC_STATS_NOT_AVAIL; |
1206 | esw_stats->multicast_frames = QLCNIC_STATS_NOT_AVAIL; |
1207 | esw_stats->broadcast_frames = QLCNIC_STATS_NOT_AVAIL; |
1208 | esw_stats->dropped_frames = QLCNIC_STATS_NOT_AVAIL; |
1209 | esw_stats->errors = QLCNIC_STATS_NOT_AVAIL; |
1210 | esw_stats->local_frames = QLCNIC_STATS_NOT_AVAIL; |
1211 | esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL; |
1212 | esw_stats->context_id = eswitch; |
1213 | |
1214 | for (i = 0; i < adapter->ahw->total_nic_func; i++) { |
1215 | if (adapter->npars[i].phy_port != eswitch) |
1216 | continue; |
1217 | |
1218 | memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics)); |
1219 | if (qlcnic_get_port_stats(adapter, func: adapter->npars[i].pci_func, |
1220 | rx_tx, esw_stats: &port_stats)) |
1221 | continue; |
1222 | |
1223 | esw_stats->size = port_stats.size; |
1224 | esw_stats->version = port_stats.version; |
1225 | QLCNIC_ADD_ESW_STATS(esw_stats->unicast_frames, |
1226 | port_stats.unicast_frames); |
1227 | QLCNIC_ADD_ESW_STATS(esw_stats->multicast_frames, |
1228 | port_stats.multicast_frames); |
1229 | QLCNIC_ADD_ESW_STATS(esw_stats->broadcast_frames, |
1230 | port_stats.broadcast_frames); |
1231 | QLCNIC_ADD_ESW_STATS(esw_stats->dropped_frames, |
1232 | port_stats.dropped_frames); |
1233 | QLCNIC_ADD_ESW_STATS(esw_stats->errors, |
1234 | port_stats.errors); |
1235 | QLCNIC_ADD_ESW_STATS(esw_stats->local_frames, |
1236 | port_stats.local_frames); |
1237 | QLCNIC_ADD_ESW_STATS(esw_stats->numbytes, |
1238 | port_stats.numbytes); |
1239 | ret = 0; |
1240 | } |
1241 | return ret; |
1242 | } |
1243 | |
1244 | int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, |
1245 | const u8 port, const u8 rx_tx) |
1246 | { |
1247 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
1248 | struct qlcnic_cmd_args cmd; |
1249 | int err; |
1250 | u32 arg1; |
1251 | |
1252 | if (ahw->op_mode != QLCNIC_MGMT_FUNC) |
1253 | return -EIO; |
1254 | |
1255 | if (func_esw == QLCNIC_STATS_PORT) { |
1256 | if (port >= ahw->max_vnic_func) |
1257 | goto err_ret; |
1258 | } else if (func_esw == QLCNIC_STATS_ESWITCH) { |
1259 | if (port >= QLCNIC_NIU_MAX_XG_PORTS) |
1260 | goto err_ret; |
1261 | } else { |
1262 | goto err_ret; |
1263 | } |
1264 | |
1265 | if (rx_tx > QLCNIC_QUERY_TX_COUNTER) |
1266 | goto err_ret; |
1267 | |
1268 | arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12; |
1269 | arg1 |= BIT_14 | rx_tx << 15; |
1270 | |
1271 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1272 | QLCNIC_CMD_GET_ESWITCH_STATS); |
1273 | if (err) |
1274 | return err; |
1275 | |
1276 | cmd.req.arg[1] = arg1; |
1277 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1278 | qlcnic_free_mbx_args(cmd: &cmd); |
1279 | return err; |
1280 | |
1281 | err_ret: |
1282 | dev_err(&adapter->pdev->dev, |
1283 | "Invalid args func_esw %d port %d rx_ctx %d\n" , |
1284 | func_esw, port, rx_tx); |
1285 | return -EIO; |
1286 | } |
1287 | |
1288 | static int __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter, |
1289 | u32 *arg1, u32 *arg2) |
1290 | { |
1291 | struct device *dev = &adapter->pdev->dev; |
1292 | struct qlcnic_cmd_args cmd; |
1293 | u8 pci_func = *arg1 >> 8; |
1294 | int err; |
1295 | |
1296 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1297 | QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG); |
1298 | if (err) |
1299 | return err; |
1300 | |
1301 | cmd.req.arg[1] = *arg1; |
1302 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1303 | *arg1 = cmd.rsp.arg[1]; |
1304 | *arg2 = cmd.rsp.arg[2]; |
1305 | qlcnic_free_mbx_args(cmd: &cmd); |
1306 | |
1307 | if (err == QLCNIC_RCODE_SUCCESS) |
1308 | dev_info(dev, "Get eSwitch port config for vNIC function %d\n" , |
1309 | pci_func); |
1310 | else |
1311 | dev_err(dev, "Failed to get eswitch port config for vNIC function %d\n" , |
1312 | pci_func); |
1313 | return err; |
1314 | } |
1315 | /* Configure eSwitch port |
1316 | op_mode = 0 for setting default port behavior |
1317 | op_mode = 1 for setting vlan id |
1318 | op_mode = 2 for deleting vlan id |
1319 | op_type = 0 for vlan_id |
1320 | op_type = 1 for port vlan_id |
1321 | */ |
1322 | int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, |
1323 | struct qlcnic_esw_func_cfg *esw_cfg) |
1324 | { |
1325 | struct device *dev = &adapter->pdev->dev; |
1326 | struct qlcnic_cmd_args cmd; |
1327 | int err = -EIO, index; |
1328 | u32 arg1, arg2 = 0; |
1329 | u8 pci_func; |
1330 | |
1331 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) { |
1332 | dev_err(&adapter->pdev->dev, "%s: Not a management function\n" , |
1333 | __func__); |
1334 | return err; |
1335 | } |
1336 | |
1337 | pci_func = esw_cfg->pci_func; |
1338 | index = qlcnic_is_valid_nic_func(adapter, pci_func); |
1339 | if (index < 0) |
1340 | return err; |
1341 | arg1 = (adapter->npars[index].phy_port & BIT_0); |
1342 | arg1 |= (pci_func << 8); |
1343 | |
1344 | if (__qlcnic_get_eswitch_port_config(adapter, arg1: &arg1, arg2: &arg2)) |
1345 | return err; |
1346 | arg1 &= ~(0x0ff << 8); |
1347 | arg1 |= (pci_func << 8); |
1348 | arg1 &= ~(BIT_2 | BIT_3); |
1349 | switch (esw_cfg->op_mode) { |
1350 | case QLCNIC_PORT_DEFAULTS: |
1351 | arg1 |= (BIT_4 | BIT_6 | BIT_7); |
1352 | arg2 |= (BIT_0 | BIT_1); |
1353 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) |
1354 | arg2 |= (BIT_2 | BIT_3); |
1355 | if (!(esw_cfg->discard_tagged)) |
1356 | arg1 &= ~BIT_4; |
1357 | if (!(esw_cfg->promisc_mode)) |
1358 | arg1 &= ~BIT_6; |
1359 | if (!(esw_cfg->mac_override)) |
1360 | arg1 &= ~BIT_7; |
1361 | if (!(esw_cfg->mac_anti_spoof)) |
1362 | arg2 &= ~BIT_0; |
1363 | if (!(esw_cfg->offload_flags & BIT_0)) |
1364 | arg2 &= ~(BIT_1 | BIT_2 | BIT_3); |
1365 | if (!(esw_cfg->offload_flags & BIT_1)) |
1366 | arg2 &= ~BIT_2; |
1367 | if (!(esw_cfg->offload_flags & BIT_2)) |
1368 | arg2 &= ~BIT_3; |
1369 | break; |
1370 | case QLCNIC_ADD_VLAN: |
1371 | arg1 &= ~(0x0ffff << 16); |
1372 | arg1 |= (BIT_2 | BIT_5); |
1373 | arg1 |= (esw_cfg->vlan_id << 16); |
1374 | break; |
1375 | case QLCNIC_DEL_VLAN: |
1376 | arg1 |= (BIT_3 | BIT_5); |
1377 | arg1 &= ~(0x0ffff << 16); |
1378 | break; |
1379 | default: |
1380 | dev_err(&adapter->pdev->dev, "%s: Invalid opmode 0x%x\n" , |
1381 | __func__, esw_cfg->op_mode); |
1382 | return err; |
1383 | } |
1384 | |
1385 | err = qlcnic_alloc_mbx_args(mbx: &cmd, adapter, |
1386 | QLCNIC_CMD_CONFIGURE_ESWITCH); |
1387 | if (err) |
1388 | return err; |
1389 | |
1390 | cmd.req.arg[1] = arg1; |
1391 | cmd.req.arg[2] = arg2; |
1392 | err = qlcnic_issue_cmd(adapter, cmd: &cmd); |
1393 | qlcnic_free_mbx_args(cmd: &cmd); |
1394 | |
1395 | if (err != QLCNIC_RCODE_SUCCESS) |
1396 | dev_err(dev, "Failed to configure eswitch for vNIC function %d\n" , |
1397 | pci_func); |
1398 | else |
1399 | dev_info(dev, "Configured eSwitch for vNIC function %d\n" , |
1400 | pci_func); |
1401 | |
1402 | return err; |
1403 | } |
1404 | |
1405 | int |
1406 | qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter, |
1407 | struct qlcnic_esw_func_cfg *esw_cfg) |
1408 | { |
1409 | u32 arg1, arg2; |
1410 | int index; |
1411 | u8 phy_port; |
1412 | |
1413 | if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) { |
1414 | index = qlcnic_is_valid_nic_func(adapter, esw_cfg->pci_func); |
1415 | if (index < 0) |
1416 | return -EIO; |
1417 | phy_port = adapter->npars[index].phy_port; |
1418 | } else { |
1419 | phy_port = adapter->ahw->physical_port; |
1420 | } |
1421 | arg1 = phy_port; |
1422 | arg1 |= (esw_cfg->pci_func << 8); |
1423 | if (__qlcnic_get_eswitch_port_config(adapter, arg1: &arg1, arg2: &arg2)) |
1424 | return -EIO; |
1425 | |
1426 | esw_cfg->discard_tagged = !!(arg1 & BIT_4); |
1427 | esw_cfg->host_vlan_tag = !!(arg1 & BIT_5); |
1428 | esw_cfg->promisc_mode = !!(arg1 & BIT_6); |
1429 | esw_cfg->mac_override = !!(arg1 & BIT_7); |
1430 | esw_cfg->vlan_id = LSW(arg1 >> 16); |
1431 | esw_cfg->mac_anti_spoof = (arg2 & 0x1); |
1432 | esw_cfg->offload_flags = ((arg2 >> 1) & 0x7); |
1433 | |
1434 | return 0; |
1435 | } |
1436 | |