diff options
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 193 |
1 files changed, 190 insertions, 3 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index f99e17e0a31..7e3738112c4 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -50,6 +50,10 @@ | |||
50 | #include <linux/log2.h> | 50 | #include <linux/log2.h> |
51 | #include <linux/list.h> | 51 | #include <linux/list.h> |
52 | 52 | ||
53 | #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) | ||
54 | #define BCM_CNIC 1 | ||
55 | #include "cnic_if.h" | ||
56 | #endif | ||
53 | #include "bnx2.h" | 57 | #include "bnx2.h" |
54 | #include "bnx2_fw.h" | 58 | #include "bnx2_fw.h" |
55 | 59 | ||
@@ -316,6 +320,158 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) | |||
316 | spin_unlock_bh(&bp->indirect_lock); | 320 | spin_unlock_bh(&bp->indirect_lock); |
317 | } | 321 | } |
318 | 322 | ||
323 | #ifdef BCM_CNIC | ||
324 | static int | ||
325 | bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info) | ||
326 | { | ||
327 | struct bnx2 *bp = netdev_priv(dev); | ||
328 | struct drv_ctl_io *io = &info->data.io; | ||
329 | |||
330 | switch (info->cmd) { | ||
331 | case DRV_CTL_IO_WR_CMD: | ||
332 | bnx2_reg_wr_ind(bp, io->offset, io->data); | ||
333 | break; | ||
334 | case DRV_CTL_IO_RD_CMD: | ||
335 | io->data = bnx2_reg_rd_ind(bp, io->offset); | ||
336 | break; | ||
337 | case DRV_CTL_CTX_WR_CMD: | ||
338 | bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data); | ||
339 | break; | ||
340 | default: | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void bnx2_setup_cnic_irq_info(struct bnx2 *bp) | ||
347 | { | ||
348 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
349 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
350 | int sb_id; | ||
351 | |||
352 | if (bp->flags & BNX2_FLAG_USING_MSIX) { | ||
353 | cp->drv_state |= CNIC_DRV_STATE_USING_MSIX; | ||
354 | bnapi->cnic_present = 0; | ||
355 | sb_id = bp->irq_nvecs; | ||
356 | cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX; | ||
357 | } else { | ||
358 | cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX; | ||
359 | bnapi->cnic_tag = bnapi->last_status_idx; | ||
360 | bnapi->cnic_present = 1; | ||
361 | sb_id = 0; | ||
362 | cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX; | ||
363 | } | ||
364 | |||
365 | cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector; | ||
366 | cp->irq_arr[0].status_blk = (void *) | ||
367 | ((unsigned long) bnapi->status_blk.msi + | ||
368 | (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id)); | ||
369 | cp->irq_arr[0].status_blk_num = sb_id; | ||
370 | cp->num_irq = 1; | ||
371 | } | ||
372 | |||
373 | static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops, | ||
374 | void *data) | ||
375 | { | ||
376 | struct bnx2 *bp = netdev_priv(dev); | ||
377 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
378 | |||
379 | if (ops == NULL) | ||
380 | return -EINVAL; | ||
381 | |||
382 | if (cp->drv_state & CNIC_DRV_STATE_REGD) | ||
383 | return -EBUSY; | ||
384 | |||
385 | bp->cnic_data = data; | ||
386 | rcu_assign_pointer(bp->cnic_ops, ops); | ||
387 | |||
388 | cp->num_irq = 0; | ||
389 | cp->drv_state = CNIC_DRV_STATE_REGD; | ||
390 | |||
391 | bnx2_setup_cnic_irq_info(bp); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int bnx2_unregister_cnic(struct net_device *dev) | ||
397 | { | ||
398 | struct bnx2 *bp = netdev_priv(dev); | ||
399 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
400 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
401 | |||
402 | cp->drv_state = 0; | ||
403 | bnapi->cnic_present = 0; | ||
404 | rcu_assign_pointer(bp->cnic_ops, NULL); | ||
405 | synchronize_rcu(); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev) | ||
410 | { | ||
411 | struct bnx2 *bp = netdev_priv(dev); | ||
412 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
413 | |||
414 | cp->drv_owner = THIS_MODULE; | ||
415 | cp->chip_id = bp->chip_id; | ||
416 | cp->pdev = bp->pdev; | ||
417 | cp->io_base = bp->regview; | ||
418 | cp->drv_ctl = bnx2_drv_ctl; | ||
419 | cp->drv_register_cnic = bnx2_register_cnic; | ||
420 | cp->drv_unregister_cnic = bnx2_unregister_cnic; | ||
421 | |||
422 | return cp; | ||
423 | } | ||
424 | EXPORT_SYMBOL(bnx2_cnic_probe); | ||
425 | |||
426 | static void | ||
427 | bnx2_cnic_stop(struct bnx2 *bp) | ||
428 | { | ||
429 | struct cnic_ops *c_ops; | ||
430 | struct cnic_ctl_info info; | ||
431 | |||
432 | rcu_read_lock(); | ||
433 | c_ops = rcu_dereference(bp->cnic_ops); | ||
434 | if (c_ops) { | ||
435 | info.cmd = CNIC_CTL_STOP_CMD; | ||
436 | c_ops->cnic_ctl(bp->cnic_data, &info); | ||
437 | } | ||
438 | rcu_read_unlock(); | ||
439 | } | ||
440 | |||
441 | static void | ||
442 | bnx2_cnic_start(struct bnx2 *bp) | ||
443 | { | ||
444 | struct cnic_ops *c_ops; | ||
445 | struct cnic_ctl_info info; | ||
446 | |||
447 | rcu_read_lock(); | ||
448 | c_ops = rcu_dereference(bp->cnic_ops); | ||
449 | if (c_ops) { | ||
450 | if (!(bp->flags & BNX2_FLAG_USING_MSIX)) { | ||
451 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
452 | |||
453 | bnapi->cnic_tag = bnapi->last_status_idx; | ||
454 | } | ||
455 | info.cmd = CNIC_CTL_START_CMD; | ||
456 | c_ops->cnic_ctl(bp->cnic_data, &info); | ||
457 | } | ||
458 | rcu_read_unlock(); | ||
459 | } | ||
460 | |||
461 | #else | ||
462 | |||
463 | static void | ||
464 | bnx2_cnic_stop(struct bnx2 *bp) | ||
465 | { | ||
466 | } | ||
467 | |||
468 | static void | ||
469 | bnx2_cnic_start(struct bnx2 *bp) | ||
470 | { | ||
471 | } | ||
472 | |||
473 | #endif | ||
474 | |||
319 | static int | 475 | static int |
320 | bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) | 476 | bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) |
321 | { | 477 | { |
@@ -489,6 +645,7 @@ bnx2_napi_enable(struct bnx2 *bp) | |||
489 | static void | 645 | static void |
490 | bnx2_netif_stop(struct bnx2 *bp) | 646 | bnx2_netif_stop(struct bnx2 *bp) |
491 | { | 647 | { |
648 | bnx2_cnic_stop(bp); | ||
492 | bnx2_disable_int_sync(bp); | 649 | bnx2_disable_int_sync(bp); |
493 | if (netif_running(bp->dev)) { | 650 | if (netif_running(bp->dev)) { |
494 | bnx2_napi_disable(bp); | 651 | bnx2_napi_disable(bp); |
@@ -505,6 +662,7 @@ bnx2_netif_start(struct bnx2 *bp) | |||
505 | netif_tx_wake_all_queues(bp->dev); | 662 | netif_tx_wake_all_queues(bp->dev); |
506 | bnx2_napi_enable(bp); | 663 | bnx2_napi_enable(bp); |
507 | bnx2_enable_int(bp); | 664 | bnx2_enable_int(bp); |
665 | bnx2_cnic_start(bp); | ||
508 | } | 666 | } |
509 | } | 667 | } |
510 | } | 668 | } |
@@ -3165,6 +3323,11 @@ bnx2_has_work(struct bnx2_napi *bnapi) | |||
3165 | if (bnx2_has_fast_work(bnapi)) | 3323 | if (bnx2_has_fast_work(bnapi)) |
3166 | return 1; | 3324 | return 1; |
3167 | 3325 | ||
3326 | #ifdef BCM_CNIC | ||
3327 | if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx)) | ||
3328 | return 1; | ||
3329 | #endif | ||
3330 | |||
3168 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != | 3331 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != |
3169 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) | 3332 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) |
3170 | return 1; | 3333 | return 1; |
@@ -3194,6 +3357,23 @@ bnx2_chk_missed_msi(struct bnx2 *bp) | |||
3194 | bp->idle_chk_status_idx = bnapi->last_status_idx; | 3357 | bp->idle_chk_status_idx = bnapi->last_status_idx; |
3195 | } | 3358 | } |
3196 | 3359 | ||
3360 | #ifdef BCM_CNIC | ||
3361 | static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi) | ||
3362 | { | ||
3363 | struct cnic_ops *c_ops; | ||
3364 | |||
3365 | if (!bnapi->cnic_present) | ||
3366 | return; | ||
3367 | |||
3368 | rcu_read_lock(); | ||
3369 | c_ops = rcu_dereference(bp->cnic_ops); | ||
3370 | if (c_ops) | ||
3371 | bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data, | ||
3372 | bnapi->status_blk.msi); | ||
3373 | rcu_read_unlock(); | ||
3374 | } | ||
3375 | #endif | ||
3376 | |||
3197 | static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) | 3377 | static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) |
3198 | { | 3378 | { |
3199 | struct status_block *sblk = bnapi->status_blk.msi; | 3379 | struct status_block *sblk = bnapi->status_blk.msi; |
@@ -3268,6 +3448,10 @@ static int bnx2_poll(struct napi_struct *napi, int budget) | |||
3268 | 3448 | ||
3269 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); | 3449 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); |
3270 | 3450 | ||
3451 | #ifdef BCM_CNIC | ||
3452 | bnx2_poll_cnic(bp, bnapi); | ||
3453 | #endif | ||
3454 | |||
3271 | /* bnapi->last_status_idx is used below to tell the hw how | 3455 | /* bnapi->last_status_idx is used below to tell the hw how |
3272 | * much work has been processed, so we must read it before | 3456 | * much work has been processed, so we must read it before |
3273 | * checking for more work. | 3457 | * checking for more work. |
@@ -4631,8 +4815,11 @@ bnx2_init_chip(struct bnx2 *bp) | |||
4631 | val = REG_RD(bp, BNX2_MQ_CONFIG); | 4815 | val = REG_RD(bp, BNX2_MQ_CONFIG); |
4632 | val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; | 4816 | val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; |
4633 | val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; | 4817 | val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; |
4634 | if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1) | 4818 | if (CHIP_NUM(bp) == CHIP_NUM_5709) { |
4635 | val |= BNX2_MQ_CONFIG_HALT_DIS; | 4819 | val |= BNX2_MQ_CONFIG_BIN_MQ_MODE; |
4820 | if (CHIP_REV(bp) == CHIP_REV_Ax) | ||
4821 | val |= BNX2_MQ_CONFIG_HALT_DIS; | ||
4822 | } | ||
4636 | 4823 | ||
4637 | REG_WR(bp, BNX2_MQ_CONFIG, val); | 4824 | REG_WR(bp, BNX2_MQ_CONFIG, val); |
4638 | 4825 | ||
@@ -7471,7 +7658,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) | |||
7471 | INIT_WORK(&bp->reset_task, bnx2_reset_task); | 7658 | INIT_WORK(&bp->reset_task, bnx2_reset_task); |
7472 | 7659 | ||
7473 | dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); | 7660 | dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); |
7474 | mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS); | 7661 | mem_len = MB_GET_CID_ADDR(TX_TSS_CID + TX_MAX_TSS_RINGS + 1); |
7475 | dev->mem_end = dev->mem_start + mem_len; | 7662 | dev->mem_end = dev->mem_start + mem_len; |
7476 | dev->irq = pdev->irq; | 7663 | dev->irq = pdev->irq; |
7477 | 7664 | ||