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