diff options
author | Michael Chan <mchan@broadcom.com> | 2009-06-08 21:14:42 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-06-09 11:22:38 -0400 |
commit | 4edd473f208cff77ce1f7ef26d5a41f31fa198e0 (patch) | |
tree | 3ae81d17069288b068d91ba9f2e329c1e5872fea /drivers/net | |
parent | 43514774ff40c4fbe0cbbd3d8293a359f1a9fe71 (diff) |
[SCSI] bnx2: Add support for CNIC driver.
Add interface and functions to support a new CNIC driver to drive
the Broadcom bnx2 hardware for iSCSI offload.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bnx2.c | 193 | ||||
-rw-r--r-- | drivers/net/bnx2.h | 18 |
2 files changed, 208 insertions, 3 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b0cb29d4cc01..3f5fcb0156a1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -49,6 +49,10 @@ | |||
49 | #include <linux/firmware.h> | 49 | #include <linux/firmware.h> |
50 | #include <linux/log2.h> | 50 | #include <linux/log2.h> |
51 | 51 | ||
52 | #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) | ||
53 | #define BCM_CNIC 1 | ||
54 | #include "cnic_if.h" | ||
55 | #endif | ||
52 | #include "bnx2.h" | 56 | #include "bnx2.h" |
53 | #include "bnx2_fw.h" | 57 | #include "bnx2_fw.h" |
54 | 58 | ||
@@ -315,6 +319,158 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) | |||
315 | spin_unlock_bh(&bp->indirect_lock); | 319 | spin_unlock_bh(&bp->indirect_lock); |
316 | } | 320 | } |
317 | 321 | ||
322 | #ifdef BCM_CNIC | ||
323 | static int | ||
324 | bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info) | ||
325 | { | ||
326 | struct bnx2 *bp = netdev_priv(dev); | ||
327 | struct drv_ctl_io *io = &info->data.io; | ||
328 | |||
329 | switch (info->cmd) { | ||
330 | case DRV_CTL_IO_WR_CMD: | ||
331 | bnx2_reg_wr_ind(bp, io->offset, io->data); | ||
332 | break; | ||
333 | case DRV_CTL_IO_RD_CMD: | ||
334 | io->data = bnx2_reg_rd_ind(bp, io->offset); | ||
335 | break; | ||
336 | case DRV_CTL_CTX_WR_CMD: | ||
337 | bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data); | ||
338 | break; | ||
339 | default: | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static void bnx2_setup_cnic_irq_info(struct bnx2 *bp) | ||
346 | { | ||
347 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
348 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
349 | int sb_id; | ||
350 | |||
351 | if (bp->flags & BNX2_FLAG_USING_MSIX) { | ||
352 | cp->drv_state |= CNIC_DRV_STATE_USING_MSIX; | ||
353 | bnapi->cnic_present = 0; | ||
354 | sb_id = bp->irq_nvecs; | ||
355 | cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX; | ||
356 | } else { | ||
357 | cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX; | ||
358 | bnapi->cnic_tag = bnapi->last_status_idx; | ||
359 | bnapi->cnic_present = 1; | ||
360 | sb_id = 0; | ||
361 | cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX; | ||
362 | } | ||
363 | |||
364 | cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector; | ||
365 | cp->irq_arr[0].status_blk = (void *) | ||
366 | ((unsigned long) bnapi->status_blk.msi + | ||
367 | (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id)); | ||
368 | cp->irq_arr[0].status_blk_num = sb_id; | ||
369 | cp->num_irq = 1; | ||
370 | } | ||
371 | |||
372 | static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops, | ||
373 | void *data) | ||
374 | { | ||
375 | struct bnx2 *bp = netdev_priv(dev); | ||
376 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
377 | |||
378 | if (ops == NULL) | ||
379 | return -EINVAL; | ||
380 | |||
381 | if (cp->drv_state & CNIC_DRV_STATE_REGD) | ||
382 | return -EBUSY; | ||
383 | |||
384 | bp->cnic_data = data; | ||
385 | rcu_assign_pointer(bp->cnic_ops, ops); | ||
386 | |||
387 | cp->num_irq = 0; | ||
388 | cp->drv_state = CNIC_DRV_STATE_REGD; | ||
389 | |||
390 | bnx2_setup_cnic_irq_info(bp); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int bnx2_unregister_cnic(struct net_device *dev) | ||
396 | { | ||
397 | struct bnx2 *bp = netdev_priv(dev); | ||
398 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
399 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
400 | |||
401 | cp->drv_state = 0; | ||
402 | bnapi->cnic_present = 0; | ||
403 | rcu_assign_pointer(bp->cnic_ops, NULL); | ||
404 | synchronize_rcu(); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev) | ||
409 | { | ||
410 | struct bnx2 *bp = netdev_priv(dev); | ||
411 | struct cnic_eth_dev *cp = &bp->cnic_eth_dev; | ||
412 | |||
413 | cp->drv_owner = THIS_MODULE; | ||
414 | cp->chip_id = bp->chip_id; | ||
415 | cp->pdev = bp->pdev; | ||
416 | cp->io_base = bp->regview; | ||
417 | cp->drv_ctl = bnx2_drv_ctl; | ||
418 | cp->drv_register_cnic = bnx2_register_cnic; | ||
419 | cp->drv_unregister_cnic = bnx2_unregister_cnic; | ||
420 | |||
421 | return cp; | ||
422 | } | ||
423 | EXPORT_SYMBOL(bnx2_cnic_probe); | ||
424 | |||
425 | static void | ||
426 | bnx2_cnic_stop(struct bnx2 *bp) | ||
427 | { | ||
428 | struct cnic_ops *c_ops; | ||
429 | struct cnic_ctl_info info; | ||
430 | |||
431 | rcu_read_lock(); | ||
432 | c_ops = rcu_dereference(bp->cnic_ops); | ||
433 | if (c_ops) { | ||
434 | info.cmd = CNIC_CTL_STOP_CMD; | ||
435 | c_ops->cnic_ctl(bp->cnic_data, &info); | ||
436 | } | ||
437 | rcu_read_unlock(); | ||
438 | } | ||
439 | |||
440 | static void | ||
441 | bnx2_cnic_start(struct bnx2 *bp) | ||
442 | { | ||
443 | struct cnic_ops *c_ops; | ||
444 | struct cnic_ctl_info info; | ||
445 | |||
446 | rcu_read_lock(); | ||
447 | c_ops = rcu_dereference(bp->cnic_ops); | ||
448 | if (c_ops) { | ||
449 | if (!(bp->flags & BNX2_FLAG_USING_MSIX)) { | ||
450 | struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; | ||
451 | |||
452 | bnapi->cnic_tag = bnapi->last_status_idx; | ||
453 | } | ||
454 | info.cmd = CNIC_CTL_START_CMD; | ||
455 | c_ops->cnic_ctl(bp->cnic_data, &info); | ||
456 | } | ||
457 | rcu_read_unlock(); | ||
458 | } | ||
459 | |||
460 | #else | ||
461 | |||
462 | static void | ||
463 | bnx2_cnic_stop(struct bnx2 *bp) | ||
464 | { | ||
465 | } | ||
466 | |||
467 | static void | ||
468 | bnx2_cnic_start(struct bnx2 *bp) | ||
469 | { | ||
470 | } | ||
471 | |||
472 | #endif | ||
473 | |||
318 | static int | 474 | static int |
319 | bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) | 475 | bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) |
320 | { | 476 | { |
@@ -488,6 +644,7 @@ bnx2_napi_enable(struct bnx2 *bp) | |||
488 | static void | 644 | static void |
489 | bnx2_netif_stop(struct bnx2 *bp) | 645 | bnx2_netif_stop(struct bnx2 *bp) |
490 | { | 646 | { |
647 | bnx2_cnic_stop(bp); | ||
491 | bnx2_disable_int_sync(bp); | 648 | bnx2_disable_int_sync(bp); |
492 | if (netif_running(bp->dev)) { | 649 | if (netif_running(bp->dev)) { |
493 | bnx2_napi_disable(bp); | 650 | bnx2_napi_disable(bp); |
@@ -504,6 +661,7 @@ bnx2_netif_start(struct bnx2 *bp) | |||
504 | netif_tx_wake_all_queues(bp->dev); | 661 | netif_tx_wake_all_queues(bp->dev); |
505 | bnx2_napi_enable(bp); | 662 | bnx2_napi_enable(bp); |
506 | bnx2_enable_int(bp); | 663 | bnx2_enable_int(bp); |
664 | bnx2_cnic_start(bp); | ||
507 | } | 665 | } |
508 | } | 666 | } |
509 | } | 667 | } |
@@ -3164,6 +3322,11 @@ bnx2_has_work(struct bnx2_napi *bnapi) | |||
3164 | if (bnx2_has_fast_work(bnapi)) | 3322 | if (bnx2_has_fast_work(bnapi)) |
3165 | return 1; | 3323 | return 1; |
3166 | 3324 | ||
3325 | #ifdef BCM_CNIC | ||
3326 | if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx)) | ||
3327 | return 1; | ||
3328 | #endif | ||
3329 | |||
3167 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != | 3330 | if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != |
3168 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) | 3331 | (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) |
3169 | return 1; | 3332 | return 1; |
@@ -3193,6 +3356,23 @@ bnx2_chk_missed_msi(struct bnx2 *bp) | |||
3193 | bp->idle_chk_status_idx = bnapi->last_status_idx; | 3356 | bp->idle_chk_status_idx = bnapi->last_status_idx; |
3194 | } | 3357 | } |
3195 | 3358 | ||
3359 | #ifdef BCM_CNIC | ||
3360 | static void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi) | ||
3361 | { | ||
3362 | struct cnic_ops *c_ops; | ||
3363 | |||
3364 | if (!bnapi->cnic_present) | ||
3365 | return; | ||
3366 | |||
3367 | rcu_read_lock(); | ||
3368 | c_ops = rcu_dereference(bp->cnic_ops); | ||
3369 | if (c_ops) | ||
3370 | bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data, | ||
3371 | bnapi->status_blk.msi); | ||
3372 | rcu_read_unlock(); | ||
3373 | } | ||
3374 | #endif | ||
3375 | |||
3196 | static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) | 3376 | static void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) |
3197 | { | 3377 | { |
3198 | struct status_block *sblk = bnapi->status_blk.msi; | 3378 | struct status_block *sblk = bnapi->status_blk.msi; |
@@ -3267,6 +3447,10 @@ static int bnx2_poll(struct napi_struct *napi, int budget) | |||
3267 | 3447 | ||
3268 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); | 3448 | work_done = bnx2_poll_work(bp, bnapi, work_done, budget); |
3269 | 3449 | ||
3450 | #ifdef BCM_CNIC | ||
3451 | bnx2_poll_cnic(bp, bnapi); | ||
3452 | #endif | ||
3453 | |||
3270 | /* bnapi->last_status_idx is used below to tell the hw how | 3454 | /* bnapi->last_status_idx is used below to tell the hw how |
3271 | * much work has been processed, so we must read it before | 3455 | * much work has been processed, so we must read it before |
3272 | * checking for more work. | 3456 | * checking for more work. |
@@ -4632,8 +4816,11 @@ bnx2_init_chip(struct bnx2 *bp) | |||
4632 | val = REG_RD(bp, BNX2_MQ_CONFIG); | 4816 | val = REG_RD(bp, BNX2_MQ_CONFIG); |
4633 | val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; | 4817 | val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; |
4634 | val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; | 4818 | val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; |
4635 | if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1) | 4819 | if (CHIP_NUM(bp) == CHIP_NUM_5709) { |
4636 | val |= BNX2_MQ_CONFIG_HALT_DIS; | 4820 | val |= BNX2_MQ_CONFIG_BIN_MQ_MODE; |
4821 | if (CHIP_REV(bp) == CHIP_REV_Ax) | ||
4822 | val |= BNX2_MQ_CONFIG_HALT_DIS; | ||
4823 | } | ||
4637 | 4824 | ||
4638 | REG_WR(bp, BNX2_MQ_CONFIG, val); | 4825 | REG_WR(bp, BNX2_MQ_CONFIG, val); |
4639 | 4826 | ||
@@ -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 | ||
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 5b570e17c839..a1ff739bc9b5 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h | |||
@@ -361,6 +361,9 @@ struct l2_fhdr { | |||
361 | #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE (1<<28) | 361 | #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE (1<<28) |
362 | 362 | ||
363 | #define BNX2_L2CTX_HOST_BDIDX 0x00000004 | 363 | #define BNX2_L2CTX_HOST_BDIDX 0x00000004 |
364 | #define BNX2_L2CTX_STATUSB_NUM_SHIFT 16 | ||
365 | #define BNX2_L2CTX_STATUSB_NUM(sb_id) \ | ||
366 | (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0) | ||
364 | #define BNX2_L2CTX_HOST_BSEQ 0x00000008 | 367 | #define BNX2_L2CTX_HOST_BSEQ 0x00000008 |
365 | #define BNX2_L2CTX_NX_BSEQ 0x0000000c | 368 | #define BNX2_L2CTX_NX_BSEQ 0x0000000c |
366 | #define BNX2_L2CTX_NX_BDHADDR_HI 0x00000010 | 369 | #define BNX2_L2CTX_NX_BDHADDR_HI 0x00000010 |
@@ -5900,6 +5903,7 @@ struct l2_fhdr { | |||
5900 | #define BNX2_RXP_FTQ_CTL_CUR_DEPTH (0x3ffL<<22) | 5903 | #define BNX2_RXP_FTQ_CTL_CUR_DEPTH (0x3ffL<<22) |
5901 | 5904 | ||
5902 | #define BNX2_RXP_SCRATCH 0x000e0000 | 5905 | #define BNX2_RXP_SCRATCH 0x000e0000 |
5906 | #define BNX2_RXP_SCRATCH_RXP_FLOOD 0x000e0024 | ||
5903 | #define BNX2_RXP_SCRATCH_RSS_TBL_SZ 0x000e0038 | 5907 | #define BNX2_RXP_SCRATCH_RSS_TBL_SZ 0x000e0038 |
5904 | #define BNX2_RXP_SCRATCH_RSS_TBL 0x000e003c | 5908 | #define BNX2_RXP_SCRATCH_RSS_TBL 0x000e003c |
5905 | #define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES 128 | 5909 | #define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES 128 |
@@ -6678,6 +6682,11 @@ struct bnx2_napi { | |||
6678 | u32 last_status_idx; | 6682 | u32 last_status_idx; |
6679 | u32 int_num; | 6683 | u32 int_num; |
6680 | 6684 | ||
6685 | #ifdef BCM_CNIC | ||
6686 | u32 cnic_tag; | ||
6687 | int cnic_present; | ||
6688 | #endif | ||
6689 | |||
6681 | struct bnx2_rx_ring_info rx_ring; | 6690 | struct bnx2_rx_ring_info rx_ring; |
6682 | struct bnx2_tx_ring_info tx_ring; | 6691 | struct bnx2_tx_ring_info tx_ring; |
6683 | }; | 6692 | }; |
@@ -6727,6 +6736,11 @@ struct bnx2 { | |||
6727 | int tx_ring_size; | 6736 | int tx_ring_size; |
6728 | u32 tx_wake_thresh; | 6737 | u32 tx_wake_thresh; |
6729 | 6738 | ||
6739 | #ifdef BCM_CNIC | ||
6740 | struct cnic_ops *cnic_ops; | ||
6741 | void *cnic_data; | ||
6742 | #endif | ||
6743 | |||
6730 | /* End of fields used in the performance code paths. */ | 6744 | /* End of fields used in the performance code paths. */ |
6731 | 6745 | ||
6732 | unsigned int current_interval; | 6746 | unsigned int current_interval; |
@@ -6885,6 +6899,10 @@ struct bnx2 { | |||
6885 | 6899 | ||
6886 | u32 idle_chk_status_idx; | 6900 | u32 idle_chk_status_idx; |
6887 | 6901 | ||
6902 | #ifdef BCM_CNIC | ||
6903 | struct cnic_eth_dev cnic_eth_dev; | ||
6904 | #endif | ||
6905 | |||
6888 | const struct firmware *mips_firmware; | 6906 | const struct firmware *mips_firmware; |
6889 | const struct firmware *rv2p_firmware; | 6907 | const struct firmware *rv2p_firmware; |
6890 | }; | 6908 | }; |