qlcnic_ctx.c 33.2 KB
Newer Older
1
/*
S
Sritej Velaga 已提交
2 3
 * QLogic qlcnic NIC Driver
 * Copyright (c)  2009-2010 QLogic Corporation
4
 *
S
Sritej Velaga 已提交
5
 * See LICENSE.qlcnic for copyright and licensing details.
6 7 8 9
 */

#include "qlcnic.h"

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
	{QLCNIC_CMD_CREATE_RX_CTX, 4, 1},
	{QLCNIC_CMD_DESTROY_RX_CTX, 2, 1},
	{QLCNIC_CMD_CREATE_TX_CTX, 4, 1},
	{QLCNIC_CMD_DESTROY_TX_CTX, 2, 1},
	{QLCNIC_CMD_INTRPT_TEST, 4, 1},
	{QLCNIC_CMD_SET_MTU, 4, 1},
	{QLCNIC_CMD_READ_PHY, 4, 2},
	{QLCNIC_CMD_WRITE_PHY, 5, 1},
	{QLCNIC_CMD_READ_HW_REG, 4, 1},
	{QLCNIC_CMD_GET_FLOW_CTL, 4, 2},
	{QLCNIC_CMD_SET_FLOW_CTL, 4, 1},
	{QLCNIC_CMD_READ_MAX_MTU, 4, 2},
	{QLCNIC_CMD_READ_MAX_LRO, 4, 2},
	{QLCNIC_CMD_MAC_ADDRESS, 4, 3},
	{QLCNIC_CMD_GET_PCI_INFO, 4, 1},
	{QLCNIC_CMD_GET_NIC_INFO, 4, 1},
	{QLCNIC_CMD_SET_NIC_INFO, 4, 1},
	{QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3},
	{QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1},
	{QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3},
	{QLCNIC_CMD_SET_PORTMIRRORING, 4, 1},
	{QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1},
	{QLCNIC_CMD_GET_MAC_STATS, 4, 1},
	{QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3},
	{QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1},
	{QLCNIC_CMD_CONFIG_PORT, 4, 1},
	{QLCNIC_CMD_TEMP_SIZE, 4, 4},
	{QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
	{QLCNIC_CMD_SET_DRV_VER, 4, 1},
};

static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
{
	return (ahw->pci_func & 0xff) | ((ahw->fw_hal_version & 0xff) << 8) |
	       (0xcafe << 16);
}

/* Allocate mailbox registers */
int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
			       struct qlcnic_adapter *adapter, u32 type)
{
	int i, size;
	const struct qlcnic_mailbox_metadata *mbx_tbl;

	mbx_tbl = qlcnic_mbx_tbl;
	size = ARRAY_SIZE(qlcnic_mbx_tbl);
	for (i = 0; i < size; i++) {
		if (type == mbx_tbl[i].cmd) {
			mbx->req.num = mbx_tbl[i].in_args;
			mbx->rsp.num = mbx_tbl[i].out_args;
			mbx->req.arg = kcalloc(mbx->req.num,
					       sizeof(u32), GFP_ATOMIC);
			if (!mbx->req.arg)
				return -ENOMEM;
			mbx->rsp.arg = kcalloc(mbx->rsp.num,
					       sizeof(u32), GFP_ATOMIC);
			if (!mbx->rsp.arg) {
				kfree(mbx->req.arg);
				mbx->req.arg = NULL;
				return -ENOMEM;
			}
			memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
			memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
			mbx->req.arg[0] = type;
			break;
		}
	}
	return 0;
}

/* Free up mailbox registers */
void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)
{
	kfree(cmd->req.arg);
	cmd->req.arg = NULL;
	kfree(cmd->rsp.arg);
	cmd->rsp.arg = NULL;
}

90 91 92 93 94 95 96 97 98 99 100 101
static int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
{
	int i;

	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
		if (adapter->npars[i].pci_func == pci_func)
			return i;
	}

	return -1;
}

102 103 104 105 106 107 108 109
static u32
qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
{
	u32 rsp;
	int timeout = 0;

	do {
		/* give atleast 1ms for firmware to respond */
110
		mdelay(1);
111 112 113 114 115 116 117 118 119 120

		if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
			return QLCNIC_CDRP_RSP_TIMEOUT;

		rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
	} while (!QLCNIC_CDRP_IS_RSP(rsp));

	return rsp;
}

121 122
int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
			  struct qlcnic_cmd_args *cmd)
123
{
124
	int i;
125 126 127
	u32 rsp;
	u32 signature;
	struct pci_dev *pdev = adapter->pdev;
128
	struct qlcnic_hardware_context *ahw = adapter->ahw;
129

130
	signature = qlcnic_get_cmd_signature(ahw);
131 132

	/* Acquire semaphore before accessing CRB */
133
	if (qlcnic_api_lock(adapter)) {
134 135
		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
		return cmd->rsp.arg[0];
136
	}
137 138

	QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
139 140
	for (i = 1; i < QLCNIC_CDRP_MAX_ARGS; i++)
		QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]);
141
	QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
142
		QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0]));
143 144 145
	rsp = qlcnic_poll_rsp(adapter);

	if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
146 147
		dev_err(&pdev->dev, "card response timeout.\n");
		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
148
	} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
149 150 151 152 153 154 155 156
		cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
		dev_err(&pdev->dev, "failed card response code:0x%x\n",
			cmd->rsp.arg[0]);
	} else if (rsp == QLCNIC_CDRP_RSP_OK)
		cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;

	for (i = 1; i < cmd->rsp.num; i++)
		cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
157 158 159

	/* Release semaphore */
	qlcnic_api_unlock(adapter);
160
	return cmd->rsp.arg[0];
A
Anirban Chakraborty 已提交
161 162 163 164
}

int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
{
165
	int err = 0;
A
Anirban Chakraborty 已提交
166
	void *tmp_addr;
167
	struct qlcnic_cmd_args cmd;
A
Anirban Chakraborty 已提交
168 169
	dma_addr_t tmp_addr_t = 0;

170 171
	tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, 0x1000,
				      &tmp_addr_t, GFP_KERNEL);
A
Anirban Chakraborty 已提交
172 173 174 175 176 177
	if (!tmp_addr) {
		dev_err(&adapter->pdev->dev,
			"Can't get memory for FW dump template\n");
		return -ENOMEM;
	}

178 179 180
	if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
		err = -ENOMEM;
		goto free_mem;
181 182
	}

183 184 185 186 187 188 189 190 191 192 193
	cmd.req.arg[1] = LSD(tmp_addr_t);
	cmd.req.arg[2] = MSD(tmp_addr_t);
	cmd.req.arg[3] = 0x1000;
	err = qlcnic_issue_cmd(adapter, &cmd);


	qlcnic_free_mbx_args(&cmd);

free_mem:
	dma_free_coherent(&adapter->pdev->dev, 0x1000, tmp_addr, tmp_addr_t);

A
Anirban Chakraborty 已提交
194 195 196
	return err;
}

197 198 199
int
qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
{
200
	int err = 0;
201
	struct qlcnic_cmd_args cmd;
A
Anirban Chakraborty 已提交
202
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
203

204 205 206 207 208
	if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
		return err;
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_MTU);
	cmd.req.arg[1] = recv_ctx->context_id;
	cmd.req.arg[2] = mtu;
209

210 211 212 213 214 215 216
	err = qlcnic_issue_cmd(adapter, &cmd);
	if (err) {
		dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
		err = -EIO;
	}
	qlcnic_free_mbx_args(&cmd);
	return err;
217 218
}

219
int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
220 221 222 223 224 225 226 227 228 229
{
	void *addr;
	struct qlcnic_hostrq_rx_ctx *prq;
	struct qlcnic_cardrsp_rx_ctx *prsp;
	struct qlcnic_hostrq_rds_ring *prq_rds;
	struct qlcnic_hostrq_sds_ring *prq_sds;
	struct qlcnic_cardrsp_rds_ring *prsp_rds;
	struct qlcnic_cardrsp_sds_ring *prsp_sds;
	struct qlcnic_host_rds_ring *rds_ring;
	struct qlcnic_host_sds_ring *sds_ring;
230
	struct qlcnic_cmd_args cmd;
231 232 233 234

	dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
	u64 phys_addr;

A
Anirban Chakraborty 已提交
235
	u8 i, nrds_rings, nsds_rings;
236
	u16 temp_u16;
237
	size_t rq_size, rsp_size;
238
	u32 cap, reg, val, reg2;
239 240
	int err;

A
Anirban Chakraborty 已提交
241
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
242 243 244 245 246 247 248 249 250 251 252

	nrds_rings = adapter->max_rds_rings;
	nsds_rings = adapter->max_sds_rings;

	rq_size =
		SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,
						nsds_rings);
	rsp_size =
		SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
						nsds_rings);

A
Anirban Chakraborty 已提交
253 254
	addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
			&hostrq_phys_addr, GFP_KERNEL);
255 256
	if (addr == NULL)
		return -ENOMEM;
257
	prq = addr;
258

A
Anirban Chakraborty 已提交
259 260
	addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size,
			&cardrsp_phys_addr, GFP_KERNEL);
261 262 263 264
	if (addr == NULL) {
		err = -ENOMEM;
		goto out_free_rq;
	}
265
	prsp = addr;
266 267 268

	prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);

S
schacko 已提交
269 270
	cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN
						| QLCNIC_CAP0_VALIDOFF);
271 272
	cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);

273 274
	temp_u16 = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler);
	prq->valid_field_offset = cpu_to_le16(temp_u16);
S
schacko 已提交
275 276
	prq->txrx_sds_binding = nsds_rings - 1;

277 278 279 280 281 282 283 284
	prq->capabilities[0] = cpu_to_le32(cap);
	prq->host_int_crb_mode =
		cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
	prq->host_rds_crb_mode =
		cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE);

	prq->num_rds_rings = cpu_to_le16(nrds_rings);
	prq->num_sds_rings = cpu_to_le16(nsds_rings);
A
Anirban Chakraborty 已提交
285
	prq->rds_ring_offset = 0;
286 287 288 289 290 291 292 293 294 295 296

	val = le32_to_cpu(prq->rds_ring_offset) +
		(sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings);
	prq->sds_ring_offset = cpu_to_le32(val);

	prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data +
			le32_to_cpu(prq->rds_ring_offset));

	for (i = 0; i < nrds_rings; i++) {

		rds_ring = &recv_ctx->rds_rings[i];
297
		rds_ring->producer = 0;
298 299 300 301 302 303 304 305 306 307 308 309 310

		prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
		prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
		prq_rds[i].ring_kind = cpu_to_le32(i);
		prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
	}

	prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data +
			le32_to_cpu(prq->sds_ring_offset));

	for (i = 0; i < nsds_rings; i++) {

		sds_ring = &recv_ctx->sds_rings[i];
311 312
		sds_ring->consumer = 0;
		memset(sds_ring->desc_head, 0, STATUS_DESC_RINGSIZE(sds_ring));
313 314 315 316 317 318 319

		prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
		prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
		prq_sds[i].msi_index = cpu_to_le16(i);
	}

	phys_addr = hostrq_phys_addr;
320 321 322 323 324
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX);
	cmd.req.arg[1] = MSD(phys_addr);
	cmd.req.arg[2] = LSD(phys_addr);
	cmd.req.arg[3] = rq_size;
	err = qlcnic_issue_cmd(adapter, &cmd);
325 326 327 328 329 330 331 332 333 334 335 336 337
	if (err) {
		dev_err(&adapter->pdev->dev,
			"Failed to create rx ctx in firmware%d\n", err);
		goto out_free_rsp;
	}

	prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
			 &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);

	for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
		rds_ring = &recv_ctx->rds_rings[i];

		reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
A
Anirban Chakraborty 已提交
338
		rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg;
339 340 341 342 343 344 345 346 347
	}

	prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
			&prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);

	for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
		sds_ring = &recv_ctx->sds_rings[i];

		reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
348
		reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
349

A
Anirban Chakraborty 已提交
350 351
		sds_ring->crb_sts_consumer = adapter->ahw->pci_base0 + reg;
		sds_ring->crb_intr_mask = adapter->ahw->pci_base0 + reg2;
352 353 354 355 356 357 358
	}

	recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
	recv_ctx->context_id = le16_to_cpu(prsp->context_id);
	recv_ctx->virt_port = prsp->virt_port;

out_free_rsp:
A
Anirban Chakraborty 已提交
359 360
	dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
		cardrsp_phys_addr);
361
	qlcnic_free_mbx_args(&cmd);
362
out_free_rq:
A
Anirban Chakraborty 已提交
363
	dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
364 365 366 367 368 369
	return err;
}

static void
qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
{
370
	int err;
371
	struct qlcnic_cmd_args cmd;
A
Anirban Chakraborty 已提交
372
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
373

374 375 376 377
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX);
	cmd.req.arg[1] = recv_ctx->context_id;
	err = qlcnic_issue_cmd(adapter, &cmd);
	if (err)
378 379
		dev_err(&adapter->pdev->dev,
			"Failed to destroy rx ctx in firmware\n");
380 381

	recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
382
	qlcnic_free_mbx_args(&cmd);
383 384
}

385 386 387
int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
				     struct qlcnic_host_tx_ring *tx_ring,
				     int ring)
388 389 390 391 392 393 394
{
	struct qlcnic_hostrq_tx_ctx	*prq;
	struct qlcnic_hostrq_cds_ring	*prq_cds;
	struct qlcnic_cardrsp_tx_ctx	*prsp;
	void	*rq_addr, *rsp_addr;
	size_t	rq_size, rsp_size;
	u32	temp;
395
	struct qlcnic_cmd_args cmd;
396 397 398 399
	int	err;
	u64	phys_addr;
	dma_addr_t	rq_phys_addr, rsp_phys_addr;

400 401 402 403 404
	/* reset host resources */
	tx_ring->producer = 0;
	tx_ring->sw_consumer = 0;
	*(tx_ring->hw_consumer) = 0;

405
	rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
A
Anirban Chakraborty 已提交
406 407
	rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
			&rq_phys_addr, GFP_KERNEL);
408 409 410 411
	if (!rq_addr)
		return -ENOMEM;

	rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx);
A
Anirban Chakraborty 已提交
412 413
	rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size,
			&rsp_phys_addr, GFP_KERNEL);
414 415 416 417 418 419
	if (!rsp_addr) {
		err = -ENOMEM;
		goto out_free_rq;
	}

	memset(rq_addr, 0, rq_size);
420
	prq = rq_addr;
421 422

	memset(rsp_addr, 0, rsp_size);
423
	prsp = rsp_addr;
424 425 426 427 428 429 430 431 432

	prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);

	temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
					QLCNIC_CAP0_LSO);
	prq->capabilities[0] = cpu_to_le32(temp);

	prq->host_int_crb_mode =
		cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
433
	prq->msi_index = 0;
434 435 436 437 438 439 440 441 442 443

	prq->interrupt_ctl = 0;
	prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);

	prq_cds = &prq->cds_ring;

	prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr);
	prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);

	phys_addr = rq_phys_addr;
444 445 446 447 448 449

	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
	cmd.req.arg[1] = MSD(phys_addr);
	cmd.req.arg[2] = LSD(phys_addr);
	cmd.req.arg[3] = rq_size;
	err = qlcnic_issue_cmd(adapter, &cmd);
450 451 452

	if (err == QLCNIC_RCODE_SUCCESS) {
		temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
A
Anirban Chakraborty 已提交
453
		tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
454
		tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
455 456 457 458 459 460
	} else {
		dev_err(&adapter->pdev->dev,
			"Failed to create tx ctx in firmware%d\n", err);
		err = -EIO;
	}

A
Anirban Chakraborty 已提交
461
	dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
462
			  rsp_phys_addr);
463 464

out_free_rq:
A
Anirban Chakraborty 已提交
465
	dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
466
	qlcnic_free_mbx_args(&cmd);
467 468 469 470 471

	return err;
}

static void
472 473
qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
			     struct qlcnic_host_tx_ring *tx_ring)
474
{
475 476
	struct qlcnic_cmd_args cmd;

477 478 479
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
	cmd.req.arg[1] = tx_ring->ctx_id;
	if (qlcnic_issue_cmd(adapter, &cmd))
480 481
		dev_err(&adapter->pdev->dev,
			"Failed to destroy tx ctx in firmware\n");
482
	qlcnic_free_mbx_args(&cmd);
483 484 485
}

int
486
qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
487
{
488
	int err;
489 490
	struct qlcnic_cmd_args cmd;

491 492 493 494 495
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_PORT);
	cmd.req.arg[1] = config;
	err = qlcnic_issue_cmd(adapter, &cmd);
	qlcnic_free_mbx_args(&cmd);
	return err;
496 497 498 499 500 501 502 503 504 505 506 507 508 509
}

int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
{
	void *addr;
	int err;
	int ring;
	struct qlcnic_recv_context *recv_ctx;
	struct qlcnic_host_rds_ring *rds_ring;
	struct qlcnic_host_sds_ring *sds_ring;
	struct qlcnic_host_tx_ring *tx_ring;

	struct pci_dev *pdev = adapter->pdev;

A
Anirban Chakraborty 已提交
510
	recv_ctx = adapter->recv_ctx;
511 512
	tx_ring = adapter->tx_ring;

A
Anirban Chakraborty 已提交
513 514
	tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
		sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
515 516 517 518 519 520
	if (tx_ring->hw_consumer == NULL) {
		dev_err(&pdev->dev, "failed to allocate tx consumer\n");
		return -ENOMEM;
	}

	/* cmd desc ring */
A
Anirban Chakraborty 已提交
521 522
	addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
			&tx_ring->phys_addr, GFP_KERNEL);
523 524 525

	if (addr == NULL) {
		dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
A
Anirban Chakraborty 已提交
526 527
		err = -ENOMEM;
		goto err_out_free;
528 529
	}

530
	tx_ring->desc_head = addr;
531 532 533

	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
		rds_ring = &recv_ctx->rds_rings[ring];
A
Anirban Chakraborty 已提交
534
		addr = dma_alloc_coherent(&adapter->pdev->dev,
535
				RCV_DESC_RINGSIZE(rds_ring),
A
Anirban Chakraborty 已提交
536
				&rds_ring->phys_addr, GFP_KERNEL);
537 538 539 540 541 542
		if (addr == NULL) {
			dev_err(&pdev->dev,
				"failed to allocate rds ring [%d]\n", ring);
			err = -ENOMEM;
			goto err_out_free;
		}
543
		rds_ring->desc_head = addr;
544 545 546 547 548 549

	}

	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
		sds_ring = &recv_ctx->sds_rings[ring];

A
Anirban Chakraborty 已提交
550
		addr = dma_alloc_coherent(&adapter->pdev->dev,
551
				STATUS_DESC_RINGSIZE(sds_ring),
A
Anirban Chakraborty 已提交
552
				&sds_ring->phys_addr, GFP_KERNEL);
553 554 555 556 557 558
		if (addr == NULL) {
			dev_err(&pdev->dev,
				"failed to allocate sds ring [%d]\n", ring);
			err = -ENOMEM;
			goto err_out_free;
		}
559
		sds_ring->desc_head = addr;
560 561 562 563 564 565 566 567 568
	}

	return 0;

err_out_free:
	qlcnic_free_hw_resources(adapter);
	return err;
}

569
int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
570
{
571
	int i, err, ring;
572

573 574 575
	if (dev->flags & QLCNIC_NEED_FLR) {
		pci_reset_function(dev->pdev);
		dev->flags &= ~QLCNIC_NEED_FLR;
576
	}
R
Rajesh Borundia 已提交
577

578
	err = qlcnic_fw_cmd_create_rx_ctx(dev);
579 580 581
	if (err)
		return err;

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
	for (ring = 0; ring < dev->max_drv_tx_rings; ring++) {
		err = qlcnic_fw_cmd_create_tx_ctx(dev,
						  &dev->tx_ring[ring],
						  ring);
		if (err) {
			qlcnic_fw_cmd_destroy_rx_ctx(dev);
			if (ring == 0)
				return err;

			for (i = 0; i < ring; i++)
				qlcnic_fw_cmd_destroy_tx_ctx(dev,
							     &dev->tx_ring[i]);

			return err;
		}
597
	}
598

599
	set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
600 601
	return 0;
}
602

603 604
void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
{
605 606
	int ring;

607 608
	if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
		qlcnic_fw_cmd_destroy_rx_ctx(adapter);
609 610 611
		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
			qlcnic_fw_cmd_destroy_tx_ctx(adapter,
						     &adapter->tx_ring[ring]);
612
		/* Allow dma queues to drain after context reset */
613
		mdelay(20);
614
	}
615 616 617 618 619 620 621 622 623
}

void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
{
	struct qlcnic_recv_context *recv_ctx;
	struct qlcnic_host_rds_ring *rds_ring;
	struct qlcnic_host_sds_ring *sds_ring;
	struct qlcnic_host_tx_ring *tx_ring;
	int ring;
624

A
Anirban Chakraborty 已提交
625
	recv_ctx = adapter->recv_ctx;
626 627 628

	tx_ring = adapter->tx_ring;
	if (tx_ring->hw_consumer != NULL) {
A
Anirban Chakraborty 已提交
629
		dma_free_coherent(&adapter->pdev->dev,
630 631 632 633 634 635 636
				sizeof(u32),
				tx_ring->hw_consumer,
				tx_ring->hw_cons_phys_addr);
		tx_ring->hw_consumer = NULL;
	}

	if (tx_ring->desc_head != NULL) {
A
Anirban Chakraborty 已提交
637
		dma_free_coherent(&adapter->pdev->dev,
638 639 640 641 642 643 644 645 646
				TX_DESC_RINGSIZE(tx_ring),
				tx_ring->desc_head, tx_ring->phys_addr);
		tx_ring->desc_head = NULL;
	}

	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
		rds_ring = &recv_ctx->rds_rings[ring];

		if (rds_ring->desc_head != NULL) {
A
Anirban Chakraborty 已提交
647
			dma_free_coherent(&adapter->pdev->dev,
648 649 650 651 652 653 654 655 656 657 658
					RCV_DESC_RINGSIZE(rds_ring),
					rds_ring->desc_head,
					rds_ring->phys_addr);
			rds_ring->desc_head = NULL;
		}
	}

	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
		sds_ring = &recv_ctx->sds_rings[ring];

		if (sds_ring->desc_head != NULL) {
A
Anirban Chakraborty 已提交
659
			dma_free_coherent(&adapter->pdev->dev,
660 661 662 663 664 665 666 667
				STATUS_DESC_RINGSIZE(sds_ring),
				sds_ring->desc_head,
				sds_ring->phys_addr);
			sds_ring->desc_head = NULL;
		}
	}
}

668

669
int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
670
{
671
	int err, i;
672
	struct qlcnic_cmd_args cmd;
673
	u32 mac_low, mac_high;
674

675 676 677
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_MAC_ADDRESS);
	cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
	err = qlcnic_issue_cmd(adapter, &cmd);
678

679 680 681 682 683 684 685 686 687
	if (err == QLCNIC_RCODE_SUCCESS) {
		mac_low = cmd.rsp.arg[1];
		mac_high = cmd.rsp.arg[2];

		for (i = 0; i < 2; i++)
			mac[i] = (u8) (mac_high >> ((1 - i) * 8));
		for (i = 2; i < 6; i++)
			mac[i] = (u8) (mac_low >> ((5 - i) * 8));
	} else {
688 689 690 691
		dev_err(&adapter->pdev->dev,
			"Failed to get mac address%d\n", err);
		err = -EIO;
	}
692
	qlcnic_free_mbx_args(&cmd);
693 694 695 696
	return err;
}

/* Get info of a NIC partition */
697 698
int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
			     struct qlcnic_info *npar_info, u8 func_id)
699 700 701
{
	int	err;
	dma_addr_t nic_dma_t;
702
	const struct qlcnic_info_le *nic_info;
703
	void *nic_info_addr;
704
	struct qlcnic_cmd_args cmd;
705
	size_t  nic_size = sizeof(struct qlcnic_info_le);
706

A
Anirban Chakraborty 已提交
707 708
	nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
				&nic_dma_t, GFP_KERNEL);
709 710 711 712
	if (!nic_info_addr)
		return -ENOMEM;
	memset(nic_info_addr, 0, nic_size);

713
	nic_info = nic_info_addr;
714

715 716 717 718 719 720 721 722 723 724
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
	cmd.req.arg[1] = MSD(nic_dma_t);
	cmd.req.arg[2] = LSD(nic_dma_t);
	cmd.req.arg[3] = (func_id << 16 | nic_size);
	err = qlcnic_issue_cmd(adapter, &cmd);
	if (err != QLCNIC_RCODE_SUCCESS) {
		dev_err(&adapter->pdev->dev,
			"Failed to get nic info%d\n", err);
		err = -EIO;
	} else {
725 726
		npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
		npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
727 728
		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
729 730 731 732 733 734
		npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
		npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
		npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
		npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
		npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
		npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
735 736
	}

A
Anirban Chakraborty 已提交
737
	dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
738 739 740
			  nic_dma_t);
	qlcnic_free_mbx_args(&cmd);

741 742 743 744
	return err;
}

/* Configure a NIC partition */
745 746
int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
			     struct qlcnic_info *nic)
747 748 749 750
{
	int err = -EIO;
	dma_addr_t nic_dma_t;
	void *nic_info_addr;
751
	struct qlcnic_cmd_args cmd;
752 753
	struct qlcnic_info_le *nic_info;
	size_t nic_size = sizeof(struct qlcnic_info_le);
754

755
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
756 757
		return err;

A
Anirban Chakraborty 已提交
758 759
	nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
			&nic_dma_t, GFP_KERNEL);
760 761 762 763
	if (!nic_info_addr)
		return -ENOMEM;

	memset(nic_info_addr, 0, nic_size);
764
	nic_info = nic_info_addr;
765 766 767 768 769 770 771 772 773 774 775 776

	nic_info->pci_func = cpu_to_le16(nic->pci_func);
	nic_info->op_mode = cpu_to_le16(nic->op_mode);
	nic_info->phys_port = cpu_to_le16(nic->phys_port);
	nic_info->switch_mode = cpu_to_le16(nic->switch_mode);
	nic_info->capabilities = cpu_to_le32(nic->capabilities);
	nic_info->max_mac_filters = nic->max_mac_filters;
	nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques);
	nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques);
	nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
	nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);

777 778 779 780 781
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
	cmd.req.arg[1] = MSD(nic_dma_t);
	cmd.req.arg[2] = LSD(nic_dma_t);
	cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
	err = qlcnic_issue_cmd(adapter, &cmd);
782 783 784 785 786 787 788

	if (err != QLCNIC_RCODE_SUCCESS) {
		dev_err(&adapter->pdev->dev,
			"Failed to set nic info%d\n", err);
		err = -EIO;
	}

A
Anirban Chakraborty 已提交
789 790
	dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
		nic_dma_t);
791 792
	qlcnic_free_mbx_args(&cmd);

793 794 795 796
	return err;
}

/* Get PCI Info of a partition */
797 798
int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
			     struct qlcnic_pci_info *pci_info)
799 800
{
	int err = 0, i;
801
	struct qlcnic_cmd_args cmd;
802
	dma_addr_t pci_info_dma_t;
803
	struct qlcnic_pci_info_le *npar;
804
	void *pci_info_addr;
805
	size_t npar_size = sizeof(struct qlcnic_pci_info_le);
806 807
	size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;

A
Anirban Chakraborty 已提交
808 809
	pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size,
			&pci_info_dma_t, GFP_KERNEL);
810 811 812 813
	if (!pci_info_addr)
		return -ENOMEM;
	memset(pci_info_addr, 0, pci_size);

814
	npar = pci_info_addr;
815 816 817 818 819
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
	cmd.req.arg[1] = MSD(pci_info_dma_t);
	cmd.req.arg[2] = LSD(pci_info_dma_t);
	cmd.req.arg[3] = pci_size;
	err = qlcnic_issue_cmd(adapter, &cmd);
820

821
	adapter->ahw->act_pci_func = 0;
822
	if (err == QLCNIC_RCODE_SUCCESS) {
823
		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
S
Sucheta Chakraborty 已提交
824 825 826
			pci_info->id = le16_to_cpu(npar->id);
			pci_info->active = le16_to_cpu(npar->active);
			pci_info->type = le16_to_cpu(npar->type);
827 828
			if (pci_info->type == QLCNIC_TYPE_NIC)
				adapter->ahw->act_pci_func++;
829
			pci_info->default_port =
S
Sucheta Chakraborty 已提交
830
				le16_to_cpu(npar->default_port);
831
			pci_info->tx_min_bw =
S
Sucheta Chakraborty 已提交
832
				le16_to_cpu(npar->tx_min_bw);
833
			pci_info->tx_max_bw =
S
Sucheta Chakraborty 已提交
834
				le16_to_cpu(npar->tx_max_bw);
835
			memcpy(pci_info->mac, npar->mac, ETH_ALEN);
836 837 838 839 840 841 842
		}
	} else {
		dev_err(&adapter->pdev->dev,
			"Failed to get PCI Info%d\n", err);
		err = -EIO;
	}

A
Anirban Chakraborty 已提交
843
	dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
844
		pci_info_dma_t);
845 846
	qlcnic_free_mbx_args(&cmd);

847 848 849 850 851 852 853 854 855
	return err;
}

/* Configure eSwitch for port mirroring */
int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
				u8 enable_mirroring, u8 pci_func)
{
	int err = -EIO;
	u32 arg1;
856
	struct qlcnic_cmd_args cmd;
857

858 859
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
	    !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
860 861 862 863 864
		return err;

	arg1 = id | (enable_mirroring ? BIT_4 : 0);
	arg1 |= pci_func << 8;

865 866 867
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_PORTMIRRORING);
	cmd.req.arg[1] = arg1;
	err = qlcnic_issue_cmd(adapter, &cmd);
868

869
	if (err != QLCNIC_RCODE_SUCCESS)
870 871 872
		dev_err(&adapter->pdev->dev,
			"Failed to configure port mirroring%d on eswitch:%d\n",
			pci_func, id);
873
	else
874 875 876
		dev_info(&adapter->pdev->dev,
			"Configured eSwitch %d for port mirroring:%d\n",
			id, pci_func);
877
	qlcnic_free_mbx_args(&cmd);
878 879 880 881

	return err;
}

882 883 884
int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
		const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {

885 886
	size_t stats_size = sizeof(struct qlcnic_esw_stats_le);
	struct qlcnic_esw_stats_le *stats;
887 888 889
	dma_addr_t stats_dma_t;
	void *stats_addr;
	u32 arg1;
890
	struct qlcnic_cmd_args cmd;
891 892 893 894 895
	int err;

	if (esw_stats == NULL)
		return -ENOMEM;

896 897
	if ((adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) &&
	    (func != adapter->ahw->pci_func)) {
898 899 900 901 902
		dev_err(&adapter->pdev->dev,
			"Not privilege to query stats for func=%d", func);
		return -EIO;
	}

A
Anirban Chakraborty 已提交
903 904
	stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
			&stats_dma_t, GFP_KERNEL);
905 906 907 908 909 910 911 912 913
	if (!stats_addr) {
		dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
		return -ENOMEM;
	}
	memset(stats_addr, 0, stats_size);

	arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
	arg1 |= rx_tx << 15 | stats_size << 16;

914 915 916 917 918
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
	cmd.req.arg[1] = arg1;
	cmd.req.arg[2] = MSD(stats_dma_t);
	cmd.req.arg[3] = LSD(stats_dma_t);
	err = qlcnic_issue_cmd(adapter, &cmd);
919

920
	if (!err) {
921
		stats = stats_addr;
922 923 924 925 926 927 928 929 930 931 932 933 934
		esw_stats->context_id = le16_to_cpu(stats->context_id);
		esw_stats->version = le16_to_cpu(stats->version);
		esw_stats->size = le16_to_cpu(stats->size);
		esw_stats->multicast_frames =
				le64_to_cpu(stats->multicast_frames);
		esw_stats->broadcast_frames =
				le64_to_cpu(stats->broadcast_frames);
		esw_stats->unicast_frames = le64_to_cpu(stats->unicast_frames);
		esw_stats->dropped_frames = le64_to_cpu(stats->dropped_frames);
		esw_stats->local_frames = le64_to_cpu(stats->local_frames);
		esw_stats->errors = le64_to_cpu(stats->errors);
		esw_stats->numbytes = le64_to_cpu(stats->numbytes);
	}
935

A
Anirban Chakraborty 已提交
936
	dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
937
		stats_dma_t);
938 939
	qlcnic_free_mbx_args(&cmd);

940 941 942
	return err;
}

943 944 945 946
/* This routine will retrieve the MAC statistics from firmware */
int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
		struct qlcnic_mac_statistics *mac_stats)
{
947
	struct qlcnic_mac_statistics_le *stats;
948
	struct qlcnic_cmd_args cmd;
949
	size_t stats_size = sizeof(struct qlcnic_mac_statistics_le);
950 951 952 953
	dma_addr_t stats_dma_t;
	void *stats_addr;
	int err;

954 955 956
	if (mac_stats == NULL)
		return -ENOMEM;

957 958 959 960 961 962 963 964
	stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
			&stats_dma_t, GFP_KERNEL);
	if (!stats_addr) {
		dev_err(&adapter->pdev->dev,
			"%s: Unable to allocate memory.\n", __func__);
		return -ENOMEM;
	}
	memset(stats_addr, 0, stats_size);
965 966 967 968 969
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
	cmd.req.arg[1] = stats_size << 16;
	cmd.req.arg[2] = MSD(stats_dma_t);
	cmd.req.arg[3] = LSD(stats_dma_t);
	err = qlcnic_issue_cmd(adapter, &cmd);
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
	if (!err) {
		stats = stats_addr;
		mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
		mac_stats->mac_tx_bytes = le64_to_cpu(stats->mac_tx_bytes);
		mac_stats->mac_tx_mcast_pkts =
					le64_to_cpu(stats->mac_tx_mcast_pkts);
		mac_stats->mac_tx_bcast_pkts =
					le64_to_cpu(stats->mac_tx_bcast_pkts);
		mac_stats->mac_rx_frames = le64_to_cpu(stats->mac_rx_frames);
		mac_stats->mac_rx_bytes = le64_to_cpu(stats->mac_rx_bytes);
		mac_stats->mac_rx_mcast_pkts =
					le64_to_cpu(stats->mac_rx_mcast_pkts);
		mac_stats->mac_rx_length_error =
				le64_to_cpu(stats->mac_rx_length_error);
		mac_stats->mac_rx_length_small =
				le64_to_cpu(stats->mac_rx_length_small);
		mac_stats->mac_rx_length_large =
				le64_to_cpu(stats->mac_rx_length_large);
		mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
		mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
		mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
991 992 993
	} else {
		dev_err(&adapter->pdev->dev,
			"%s: Get mac stats failed, err=%d.\n", __func__, err);
994 995 996 997
	}

	dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
		stats_dma_t);
998 999 1000

	qlcnic_free_mbx_args(&cmd);

1001 1002 1003
	return err;
}

1004 1005 1006 1007 1008 1009 1010 1011 1012
int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
		const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {

	struct __qlcnic_esw_statistics port_stats;
	u8 i;
	int ret = -EIO;

	if (esw_stats == NULL)
		return -ENOMEM;
1013
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
1014 1015 1016 1017
		return -EIO;
	if (adapter->npars == NULL)
		return -EIO;

A
Amit Kumar Salecha 已提交
1018
	memset(esw_stats, 0, sizeof(u64));
1019 1020 1021 1022 1023 1024 1025
	esw_stats->unicast_frames = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->multicast_frames = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->broadcast_frames = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->dropped_frames = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->errors = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->local_frames = QLCNIC_STATS_NOT_AVAIL;
	esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL;
1026 1027
	esw_stats->context_id = eswitch;

1028
	for (i = 0; i < adapter->ahw->act_pci_func; i++) {
1029 1030 1031 1032
		if (adapter->npars[i].phy_port != eswitch)
			continue;

		memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics));
1033 1034
		if (qlcnic_get_port_stats(adapter, adapter->npars[i].pci_func,
					  rx_tx, &port_stats))
1035 1036 1037 1038
			continue;

		esw_stats->size = port_stats.size;
		esw_stats->version = port_stats.version;
A
Amit Kumar Salecha 已提交
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
		QLCNIC_ADD_ESW_STATS(esw_stats->unicast_frames,
						port_stats.unicast_frames);
		QLCNIC_ADD_ESW_STATS(esw_stats->multicast_frames,
						port_stats.multicast_frames);
		QLCNIC_ADD_ESW_STATS(esw_stats->broadcast_frames,
						port_stats.broadcast_frames);
		QLCNIC_ADD_ESW_STATS(esw_stats->dropped_frames,
						port_stats.dropped_frames);
		QLCNIC_ADD_ESW_STATS(esw_stats->errors,
						port_stats.errors);
		QLCNIC_ADD_ESW_STATS(esw_stats->local_frames,
						port_stats.local_frames);
		QLCNIC_ADD_ESW_STATS(esw_stats->numbytes,
						port_stats.numbytes);
1053 1054 1055 1056 1057 1058 1059 1060
		ret = 0;
	}
	return ret;
}

int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
		const u8 port, const u8 rx_tx)
{
1061
	int err;
1062
	u32 arg1;
1063
	struct qlcnic_cmd_args cmd;
1064

1065
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
		return -EIO;

	if (func_esw == QLCNIC_STATS_PORT) {
		if (port >= QLCNIC_MAX_PCI_FUNC)
			goto err_ret;
	} else if (func_esw == QLCNIC_STATS_ESWITCH) {
		if (port >= QLCNIC_NIU_MAX_XG_PORTS)
			goto err_ret;
	} else {
		goto err_ret;
	}

	if (rx_tx > QLCNIC_QUERY_TX_COUNTER)
		goto err_ret;

	arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
	arg1 |= BIT_14 | rx_tx << 15;

1084 1085 1086 1087 1088
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_ESWITCH_STATS);
	cmd.req.arg[1] = arg1;
	err = qlcnic_issue_cmd(adapter, &cmd);
	qlcnic_free_mbx_args(&cmd);
	return err;
1089 1090

err_ret:
1091 1092 1093
	dev_err(&adapter->pdev->dev,
		"Invalid args func_esw %d port %d rx_ctx %d\n",
		func_esw, port, rx_tx);
1094 1095
	return -EIO;
}
1096 1097 1098 1099 1100 1101

static int
__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
					u32 *arg1, u32 *arg2)
{
	int err = -EIO;
1102
	struct qlcnic_cmd_args cmd;
1103 1104
	u8 pci_func;
	pci_func = (*arg1 >> 8);
1105

1106 1107 1108 1109 1110 1111 1112
	qlcnic_alloc_mbx_args(&cmd, adapter,
			      QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
	cmd.req.arg[1] = *arg1;
	err = qlcnic_issue_cmd(adapter, &cmd);
	*arg1 = cmd.rsp.arg[1];
	*arg2 = cmd.rsp.arg[2];
	qlcnic_free_mbx_args(&cmd);
1113

1114
	if (err == QLCNIC_RCODE_SUCCESS)
1115
		dev_info(&adapter->pdev->dev,
1116 1117
			 "eSwitch port config for pci func %d\n", pci_func);
	else
1118
		dev_err(&adapter->pdev->dev,
1119 1120
			"Failed to get eswitch port config for pci func %d\n",
								pci_func);
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
	return err;
}
/* Configure eSwitch port
op_mode = 0 for setting default port behavior
op_mode = 1 for setting  vlan id
op_mode = 2 for deleting vlan id
op_type = 0 for vlan_id
op_type = 1 for port vlan_id
*/
int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
		struct qlcnic_esw_func_cfg *esw_cfg)
{
1133
	int err = -EIO, index;
1134
	u32 arg1, arg2 = 0;
1135
	struct qlcnic_cmd_args cmd;
1136 1137
	u8 pci_func;

1138
	if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
1139 1140
		return err;
	pci_func = esw_cfg->pci_func;
1141 1142 1143 1144
	index = qlcnic_is_valid_nic_func(adapter, pci_func);
	if (index < 0)
		return err;
	arg1 = (adapter->npars[index].phy_port & BIT_0);
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	arg1 |= (pci_func << 8);

	if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
		return err;
	arg1 &= ~(0x0ff << 8);
	arg1 |= (pci_func << 8);
	arg1 &= ~(BIT_2 | BIT_3);
	switch (esw_cfg->op_mode) {
	case QLCNIC_PORT_DEFAULTS:
		arg1 |= (BIT_4 | BIT_6 | BIT_7);
		arg2 |= (BIT_0 | BIT_1);
1156
		if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
1157 1158 1159 1160 1161
			arg2 |= (BIT_2 | BIT_3);
		if (!(esw_cfg->discard_tagged))
			arg1 &= ~BIT_4;
		if (!(esw_cfg->promisc_mode))
			arg1 &= ~BIT_6;
1162
		if (!(esw_cfg->mac_override))
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
			arg1 &= ~BIT_7;
		if (!(esw_cfg->mac_anti_spoof))
			arg2 &= ~BIT_0;
		if (!(esw_cfg->offload_flags & BIT_0))
			arg2 &= ~(BIT_1 | BIT_2 | BIT_3);
		if (!(esw_cfg->offload_flags & BIT_1))
			arg2 &= ~BIT_2;
		if (!(esw_cfg->offload_flags & BIT_2))
			arg2 &= ~BIT_3;
		break;
	case QLCNIC_ADD_VLAN:
			arg1 |= (BIT_2 | BIT_5);
			arg1 |= (esw_cfg->vlan_id << 16);
			break;
	case QLCNIC_DEL_VLAN:
			arg1 |= (BIT_3 | BIT_5);
			arg1 &= ~(0x0ffff << 16);
R
Rajesh Borundia 已提交
1180
			break;
1181 1182 1183 1184
	default:
		return err;
	}

1185 1186 1187 1188 1189
	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_ESWITCH);
	cmd.req.arg[1] = arg1;
	cmd.req.arg[2] = arg2;
	err = qlcnic_issue_cmd(adapter, &cmd);
	qlcnic_free_mbx_args(&cmd);
1190

1191
	if (err != QLCNIC_RCODE_SUCCESS)
1192
		dev_err(&adapter->pdev->dev,
1193
			"Failed to configure eswitch pci func %d\n", pci_func);
1194
	else
1195
		dev_info(&adapter->pdev->dev,
1196
			 "Configured eSwitch for pci func %d\n", pci_func);
1197 1198 1199 1200 1201 1202 1203 1204 1205

	return err;
}

int
qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
			struct qlcnic_esw_func_cfg *esw_cfg)
{
	u32 arg1, arg2;
1206
	int index;
1207
	u8 phy_port;
1208 1209 1210 1211 1212 1213 1214

	if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
		index = qlcnic_is_valid_nic_func(adapter, esw_cfg->pci_func);
		if (index < 0)
			return -EIO;
		phy_port = adapter->npars[index].phy_port;
	} else {
1215
		phy_port = adapter->ahw->physical_port;
1216
	}
1217 1218 1219 1220 1221 1222 1223 1224
	arg1 = phy_port;
	arg1 |= (esw_cfg->pci_func << 8);
	if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
		return -EIO;

	esw_cfg->discard_tagged = !!(arg1 & BIT_4);
	esw_cfg->host_vlan_tag = !!(arg1 & BIT_5);
	esw_cfg->promisc_mode = !!(arg1 & BIT_6);
1225
	esw_cfg->mac_override = !!(arg1 & BIT_7);
1226 1227 1228 1229 1230 1231
	esw_cfg->vlan_id = LSW(arg1 >> 16);
	esw_cfg->mac_anti_spoof = (arg2 & 0x1);
	esw_cfg->offload_flags = ((arg2 >> 1) & 0x7);

	return 0;
}