/drivers/net/ethernet/broadcom/bnx2.c
http://github.com/mirrors/linux · C · 8845 lines · 6903 code · 1592 blank · 350 comment · 1328 complexity · 08a381652f80ecee18c3449f12095e97 MD5 · raw file
Large files are truncated click here to view the full file
- /* bnx2.c: QLogic bnx2 network driver.
- *
- * Copyright (c) 2004-2014 Broadcom Corporation
- * Copyright (c) 2014-2015 QLogic Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
- *
- * Written by: Michael Chan (mchan@broadcom.com)
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/stringify.h>
- #include <linux/kernel.h>
- #include <linux/timer.h>
- #include <linux/errno.h>
- #include <linux/ioport.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
- #include <linux/interrupt.h>
- #include <linux/pci.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
- #include <linux/dma-mapping.h>
- #include <linux/bitops.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <linux/delay.h>
- #include <asm/byteorder.h>
- #include <asm/page.h>
- #include <linux/time.h>
- #include <linux/ethtool.h>
- #include <linux/mii.h>
- #include <linux/if.h>
- #include <linux/if_vlan.h>
- #include <net/ip.h>
- #include <net/tcp.h>
- #include <net/checksum.h>
- #include <linux/workqueue.h>
- #include <linux/crc32.h>
- #include <linux/prefetch.h>
- #include <linux/cache.h>
- #include <linux/firmware.h>
- #include <linux/log2.h>
- #include <linux/aer.h>
- #include <linux/crash_dump.h>
- #if IS_ENABLED(CONFIG_CNIC)
- #define BCM_CNIC 1
- #include "cnic_if.h"
- #endif
- #include "bnx2.h"
- #include "bnx2_fw.h"
- #define DRV_MODULE_NAME "bnx2"
- #define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw"
- #define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw"
- #define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw"
- #define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw"
- #define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw"
- #define RUN_AT(x) (jiffies + (x))
- /* Time in jiffies before concluding the transmitter is hung. */
- #define TX_TIMEOUT (5*HZ)
- MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
- MODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver");
- MODULE_LICENSE("GPL");
- MODULE_FIRMWARE(FW_MIPS_FILE_06);
- MODULE_FIRMWARE(FW_RV2P_FILE_06);
- MODULE_FIRMWARE(FW_MIPS_FILE_09);
- MODULE_FIRMWARE(FW_RV2P_FILE_09);
- MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
- static int disable_msi = 0;
- module_param(disable_msi, int, 0444);
- MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
- typedef enum {
- BCM5706 = 0,
- NC370T,
- NC370I,
- BCM5706S,
- NC370F,
- BCM5708,
- BCM5708S,
- BCM5709,
- BCM5709S,
- BCM5716,
- BCM5716S,
- } board_t;
- /* indexed by board_t, above */
- static struct {
- char *name;
- } board_info[] = {
- { "Broadcom NetXtreme II BCM5706 1000Base-T" },
- { "HP NC370T Multifunction Gigabit Server Adapter" },
- { "HP NC370i Multifunction Gigabit Server Adapter" },
- { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
- { "HP NC370F Multifunction Gigabit Server Adapter" },
- { "Broadcom NetXtreme II BCM5708 1000Base-T" },
- { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
- { "Broadcom NetXtreme II BCM5709 1000Base-T" },
- { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
- { "Broadcom NetXtreme II BCM5716 1000Base-T" },
- { "Broadcom NetXtreme II BCM5716 1000Base-SX" },
- };
- static const struct pci_device_id bnx2_pci_tbl[] = {
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
- PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
- PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
- PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
- { PCI_VENDOR_ID_BROADCOM, 0x163b,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 },
- { PCI_VENDOR_ID_BROADCOM, 0x163c,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S },
- { 0, }
- };
- static const struct flash_spec flash_table[] =
- {
- #define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
- #define NONBUFFERED_FLAGS (BNX2_NV_WREN)
- /* Slow EEPROM */
- {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
- BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
- SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
- "EEPROM - slow"},
- /* Expansion entry 0001 */
- {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 0001"},
- /* Saifun SA25F010 (non-buffered flash) */
- /* strap, cfg1, & write1 need updates */
- {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
- "Non-buffered flash (128kB)"},
- /* Saifun SA25F020 (non-buffered flash) */
- /* strap, cfg1, & write1 need updates */
- {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
- "Non-buffered flash (256kB)"},
- /* Expansion entry 0100 */
- {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 0100"},
- /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
- {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
- ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
- "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
- /* Entry 0110: ST M45PE20 (non-buffered flash)*/
- {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
- ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
- "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
- /* Saifun SA25F005 (non-buffered flash) */
- /* strap, cfg1, & write1 need updates */
- {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
- "Non-buffered flash (64kB)"},
- /* Fast EEPROM */
- {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
- BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
- SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
- "EEPROM - fast"},
- /* Expansion entry 1001 */
- {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 1001"},
- /* Expansion entry 1010 */
- {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 1010"},
- /* ATMEL AT45DB011B (buffered flash) */
- {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
- BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
- BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
- "Buffered flash (128kB)"},
- /* Expansion entry 1100 */
- {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 1100"},
- /* Expansion entry 1101 */
- {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
- NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
- SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 1101"},
- /* Ateml Expansion entry 1110 */
- {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
- BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
- BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
- "Entry 1110 (Atmel)"},
- /* ATMEL AT45DB021B (buffered flash) */
- {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
- BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
- BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
- "Buffered flash (256kB)"},
- };
- static const struct flash_spec flash_5709 = {
- .flags = BNX2_NV_BUFFERED,
- .page_bits = BCM5709_FLASH_PAGE_BITS,
- .page_size = BCM5709_FLASH_PAGE_SIZE,
- .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
- .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
- .name = "5709 Buffered flash (256kB)",
- };
- MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
- static void bnx2_init_napi(struct bnx2 *bp);
- static void bnx2_del_napi(struct bnx2 *bp);
- static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
- {
- u32 diff;
- /* The ring uses 256 indices for 255 entries, one of them
- * needs to be skipped.
- */
- diff = READ_ONCE(txr->tx_prod) - READ_ONCE(txr->tx_cons);
- if (unlikely(diff >= BNX2_TX_DESC_CNT)) {
- diff &= 0xffff;
- if (diff == BNX2_TX_DESC_CNT)
- diff = BNX2_MAX_TX_DESC_CNT;
- }
- return bp->tx_ring_size - diff;
- }
- static u32
- bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
- {
- unsigned long flags;
- u32 val;
- spin_lock_irqsave(&bp->indirect_lock, flags);
- BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
- val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW);
- spin_unlock_irqrestore(&bp->indirect_lock, flags);
- return val;
- }
- static void
- bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
- {
- unsigned long flags;
- spin_lock_irqsave(&bp->indirect_lock, flags);
- BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
- BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
- spin_unlock_irqrestore(&bp->indirect_lock, flags);
- }
- static void
- bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
- {
- bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
- }
- static u32
- bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
- {
- return bnx2_reg_rd_ind(bp, bp->shmem_base + offset);
- }
- static void
- bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
- {
- unsigned long flags;
- offset += cid_addr;
- spin_lock_irqsave(&bp->indirect_lock, flags);
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
- int i;
- BNX2_WR(bp, BNX2_CTX_CTX_DATA, val);
- BNX2_WR(bp, BNX2_CTX_CTX_CTRL,
- offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
- for (i = 0; i < 5; i++) {
- val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL);
- if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
- break;
- udelay(5);
- }
- } else {
- BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset);
- BNX2_WR(bp, BNX2_CTX_DATA, val);
- }
- spin_unlock_irqrestore(&bp->indirect_lock, flags);
- }
- #ifdef BCM_CNIC
- static int
- bnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info)
- {
- struct bnx2 *bp = netdev_priv(dev);
- struct drv_ctl_io *io = &info->data.io;
- switch (info->cmd) {
- case DRV_CTL_IO_WR_CMD:
- bnx2_reg_wr_ind(bp, io->offset, io->data);
- break;
- case DRV_CTL_IO_RD_CMD:
- io->data = bnx2_reg_rd_ind(bp, io->offset);
- break;
- case DRV_CTL_CTX_WR_CMD:
- bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data);
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
- {
- struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
- struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
- int sb_id;
- if (bp->flags & BNX2_FLAG_USING_MSIX) {
- cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
- bnapi->cnic_present = 0;
- sb_id = bp->irq_nvecs;
- cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
- } else {
- cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
- bnapi->cnic_tag = bnapi->last_status_idx;
- bnapi->cnic_present = 1;
- sb_id = 0;
- cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
- }
- cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector;
- cp->irq_arr[0].status_blk = (void *)
- ((unsigned long) bnapi->status_blk.msi +
- (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
- cp->irq_arr[0].status_blk_num = sb_id;
- cp->num_irq = 1;
- }
- static int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops,
- void *data)
- {
- struct bnx2 *bp = netdev_priv(dev);
- struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
- if (!ops)
- return -EINVAL;
- if (cp->drv_state & CNIC_DRV_STATE_REGD)
- return -EBUSY;
- if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN))
- return -ENODEV;
- bp->cnic_data = data;
- rcu_assign_pointer(bp->cnic_ops, ops);
- cp->num_irq = 0;
- cp->drv_state = CNIC_DRV_STATE_REGD;
- bnx2_setup_cnic_irq_info(bp);
- return 0;
- }
- static int bnx2_unregister_cnic(struct net_device *dev)
- {
- struct bnx2 *bp = netdev_priv(dev);
- struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
- struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
- mutex_lock(&bp->cnic_lock);
- cp->drv_state = 0;
- bnapi->cnic_present = 0;
- RCU_INIT_POINTER(bp->cnic_ops, NULL);
- mutex_unlock(&bp->cnic_lock);
- synchronize_rcu();
- return 0;
- }
- static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
- {
- struct bnx2 *bp = netdev_priv(dev);
- struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
- if (!cp->max_iscsi_conn)
- return NULL;
- cp->drv_owner = THIS_MODULE;
- cp->chip_id = bp->chip_id;
- cp->pdev = bp->pdev;
- cp->io_base = bp->regview;
- cp->drv_ctl = bnx2_drv_ctl;
- cp->drv_register_cnic = bnx2_register_cnic;
- cp->drv_unregister_cnic = bnx2_unregister_cnic;
- return cp;
- }
- static void
- bnx2_cnic_stop(struct bnx2 *bp)
- {
- struct cnic_ops *c_ops;
- struct cnic_ctl_info info;
- mutex_lock(&bp->cnic_lock);
- c_ops = rcu_dereference_protected(bp->cnic_ops,
- lockdep_is_held(&bp->cnic_lock));
- if (c_ops) {
- info.cmd = CNIC_CTL_STOP_CMD;
- c_ops->cnic_ctl(bp->cnic_data, &info);
- }
- mutex_unlock(&bp->cnic_lock);
- }
- static void
- bnx2_cnic_start(struct bnx2 *bp)
- {
- struct cnic_ops *c_ops;
- struct cnic_ctl_info info;
- mutex_lock(&bp->cnic_lock);
- c_ops = rcu_dereference_protected(bp->cnic_ops,
- lockdep_is_held(&bp->cnic_lock));
- if (c_ops) {
- if (!(bp->flags & BNX2_FLAG_USING_MSIX)) {
- struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
- bnapi->cnic_tag = bnapi->last_status_idx;
- }
- info.cmd = CNIC_CTL_START_CMD;
- c_ops->cnic_ctl(bp->cnic_data, &info);
- }
- mutex_unlock(&bp->cnic_lock);
- }
- #else
- static void
- bnx2_cnic_stop(struct bnx2 *bp)
- {
- }
- static void
- bnx2_cnic_start(struct bnx2 *bp)
- {
- }
- #endif
- static int
- bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
- {
- u32 val1;
- int i, ret;
- if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
- BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
- BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- udelay(40);
- }
- val1 = (bp->phy_addr << 21) | (reg << 16) |
- BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
- BNX2_EMAC_MDIO_COMM_START_BUSY;
- BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
- for (i = 0; i < 50; i++) {
- udelay(10);
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
- if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
- udelay(5);
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
- val1 &= BNX2_EMAC_MDIO_COMM_DATA;
- break;
- }
- }
- if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
- *val = 0x0;
- ret = -EBUSY;
- }
- else {
- *val = val1;
- ret = 0;
- }
- if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
- BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
- BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- udelay(40);
- }
- return ret;
- }
- static int
- bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
- {
- u32 val1;
- int i, ret;
- if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
- BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
- BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- udelay(40);
- }
- val1 = (bp->phy_addr << 21) | (reg << 16) | val |
- BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
- BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
- BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
- for (i = 0; i < 50; i++) {
- udelay(10);
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM);
- if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
- udelay(5);
- break;
- }
- }
- if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
- ret = -EBUSY;
- else
- ret = 0;
- if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
- val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
- BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
- BNX2_RD(bp, BNX2_EMAC_MDIO_MODE);
- udelay(40);
- }
- return ret;
- }
- static void
- bnx2_disable_int(struct bnx2 *bp)
- {
- int i;
- struct bnx2_napi *bnapi;
- for (i = 0; i < bp->irq_nvecs; i++) {
- bnapi = &bp->bnx2_napi[i];
- BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
- BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
- }
- BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
- }
- static void
- bnx2_enable_int(struct bnx2 *bp)
- {
- int i;
- struct bnx2_napi *bnapi;
- for (i = 0; i < bp->irq_nvecs; i++) {
- bnapi = &bp->bnx2_napi[i];
- BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
- bnapi->last_status_idx);
- BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- bnapi->last_status_idx);
- }
- BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
- }
- static void
- bnx2_disable_int_sync(struct bnx2 *bp)
- {
- int i;
- atomic_inc(&bp->intr_sem);
- if (!netif_running(bp->dev))
- return;
- bnx2_disable_int(bp);
- for (i = 0; i < bp->irq_nvecs; i++)
- synchronize_irq(bp->irq_tbl[i].vector);
- }
- static void
- bnx2_napi_disable(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->irq_nvecs; i++)
- napi_disable(&bp->bnx2_napi[i].napi);
- }
- static void
- bnx2_napi_enable(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->irq_nvecs; i++)
- napi_enable(&bp->bnx2_napi[i].napi);
- }
- static void
- bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
- {
- if (stop_cnic)
- bnx2_cnic_stop(bp);
- if (netif_running(bp->dev)) {
- bnx2_napi_disable(bp);
- netif_tx_disable(bp->dev);
- }
- bnx2_disable_int_sync(bp);
- netif_carrier_off(bp->dev); /* prevent tx timeout */
- }
- static void
- bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
- {
- if (atomic_dec_and_test(&bp->intr_sem)) {
- if (netif_running(bp->dev)) {
- netif_tx_wake_all_queues(bp->dev);
- spin_lock_bh(&bp->phy_lock);
- if (bp->link_up)
- netif_carrier_on(bp->dev);
- spin_unlock_bh(&bp->phy_lock);
- bnx2_napi_enable(bp);
- bnx2_enable_int(bp);
- if (start_cnic)
- bnx2_cnic_start(bp);
- }
- }
- }
- static void
- bnx2_free_tx_mem(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->num_tx_rings; i++) {
- struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
- struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
- if (txr->tx_desc_ring) {
- dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
- txr->tx_desc_ring,
- txr->tx_desc_mapping);
- txr->tx_desc_ring = NULL;
- }
- kfree(txr->tx_buf_ring);
- txr->tx_buf_ring = NULL;
- }
- }
- static void
- bnx2_free_rx_mem(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->num_rx_rings; i++) {
- struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
- struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
- int j;
- for (j = 0; j < bp->rx_max_ring; j++) {
- if (rxr->rx_desc_ring[j])
- dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
- rxr->rx_desc_ring[j],
- rxr->rx_desc_mapping[j]);
- rxr->rx_desc_ring[j] = NULL;
- }
- vfree(rxr->rx_buf_ring);
- rxr->rx_buf_ring = NULL;
- for (j = 0; j < bp->rx_max_pg_ring; j++) {
- if (rxr->rx_pg_desc_ring[j])
- dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE,
- rxr->rx_pg_desc_ring[j],
- rxr->rx_pg_desc_mapping[j]);
- rxr->rx_pg_desc_ring[j] = NULL;
- }
- vfree(rxr->rx_pg_ring);
- rxr->rx_pg_ring = NULL;
- }
- }
- static int
- bnx2_alloc_tx_mem(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->num_tx_rings; i++) {
- struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
- struct bnx2_tx_ring_info *txr = &bnapi->tx_ring;
- txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
- if (!txr->tx_buf_ring)
- return -ENOMEM;
- txr->tx_desc_ring =
- dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE,
- &txr->tx_desc_mapping, GFP_KERNEL);
- if (!txr->tx_desc_ring)
- return -ENOMEM;
- }
- return 0;
- }
- static int
- bnx2_alloc_rx_mem(struct bnx2 *bp)
- {
- int i;
- for (i = 0; i < bp->num_rx_rings; i++) {
- struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
- struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring;
- int j;
- rxr->rx_buf_ring =
- vzalloc(array_size(SW_RXBD_RING_SIZE, bp->rx_max_ring));
- if (!rxr->rx_buf_ring)
- return -ENOMEM;
- for (j = 0; j < bp->rx_max_ring; j++) {
- rxr->rx_desc_ring[j] =
- dma_alloc_coherent(&bp->pdev->dev,
- RXBD_RING_SIZE,
- &rxr->rx_desc_mapping[j],
- GFP_KERNEL);
- if (!rxr->rx_desc_ring[j])
- return -ENOMEM;
- }
- if (bp->rx_pg_ring_size) {
- rxr->rx_pg_ring =
- vzalloc(array_size(SW_RXPG_RING_SIZE,
- bp->rx_max_pg_ring));
- if (!rxr->rx_pg_ring)
- return -ENOMEM;
- }
- for (j = 0; j < bp->rx_max_pg_ring; j++) {
- rxr->rx_pg_desc_ring[j] =
- dma_alloc_coherent(&bp->pdev->dev,
- RXBD_RING_SIZE,
- &rxr->rx_pg_desc_mapping[j],
- GFP_KERNEL);
- if (!rxr->rx_pg_desc_ring[j])
- return -ENOMEM;
- }
- }
- return 0;
- }
- static void
- bnx2_free_stats_blk(struct net_device *dev)
- {
- struct bnx2 *bp = netdev_priv(dev);
- if (bp->status_blk) {
- dma_free_coherent(&bp->pdev->dev, bp->status_stats_size,
- bp->status_blk,
- bp->status_blk_mapping);
- bp->status_blk = NULL;
- bp->stats_blk = NULL;
- }
- }
- static int
- bnx2_alloc_stats_blk(struct net_device *dev)
- {
- int status_blk_size;
- void *status_blk;
- struct bnx2 *bp = netdev_priv(dev);
- /* Combine status and statistics blocks into one allocation. */
- status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
- if (bp->flags & BNX2_FLAG_MSIX_CAP)
- status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
- BNX2_SBLK_MSIX_ALIGN_SIZE);
- bp->status_stats_size = status_blk_size +
- sizeof(struct statistics_block);
- status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size,
- &bp->status_blk_mapping, GFP_KERNEL);
- if (!status_blk)
- return -ENOMEM;
- bp->status_blk = status_blk;
- bp->stats_blk = status_blk + status_blk_size;
- bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
- return 0;
- }
- static void
- bnx2_free_mem(struct bnx2 *bp)
- {
- int i;
- struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
- bnx2_free_tx_mem(bp);
- bnx2_free_rx_mem(bp);
- for (i = 0; i < bp->ctx_pages; i++) {
- if (bp->ctx_blk[i]) {
- dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE,
- bp->ctx_blk[i],
- bp->ctx_blk_mapping[i]);
- bp->ctx_blk[i] = NULL;
- }
- }
- if (bnapi->status_blk.msi)
- bnapi->status_blk.msi = NULL;
- }
- static int
- bnx2_alloc_mem(struct bnx2 *bp)
- {
- int i, err;
- struct bnx2_napi *bnapi;
- bnapi = &bp->bnx2_napi[0];
- bnapi->status_blk.msi = bp->status_blk;
- bnapi->hw_tx_cons_ptr =
- &bnapi->status_blk.msi->status_tx_quick_consumer_index0;
- bnapi->hw_rx_cons_ptr =
- &bnapi->status_blk.msi->status_rx_quick_consumer_index0;
- if (bp->flags & BNX2_FLAG_MSIX_CAP) {
- for (i = 1; i < bp->irq_nvecs; i++) {
- struct status_block_msix *sblk;
- bnapi = &bp->bnx2_napi[i];
- sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i);
- bnapi->status_blk.msix = sblk;
- bnapi->hw_tx_cons_ptr =
- &sblk->status_tx_quick_consumer_index;
- bnapi->hw_rx_cons_ptr =
- &sblk->status_rx_quick_consumer_index;
- bnapi->int_num = i << 24;
- }
- }
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
- bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE;
- if (bp->ctx_pages == 0)
- bp->ctx_pages = 1;
- for (i = 0; i < bp->ctx_pages; i++) {
- bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev,
- BNX2_PAGE_SIZE,
- &bp->ctx_blk_mapping[i],
- GFP_KERNEL);
- if (!bp->ctx_blk[i])
- goto alloc_mem_err;
- }
- }
- err = bnx2_alloc_rx_mem(bp);
- if (err)
- goto alloc_mem_err;
- err = bnx2_alloc_tx_mem(bp);
- if (err)
- goto alloc_mem_err;
- return 0;
- alloc_mem_err:
- bnx2_free_mem(bp);
- return -ENOMEM;
- }
- static void
- bnx2_report_fw_link(struct bnx2 *bp)
- {
- u32 fw_link_status = 0;
- if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
- return;
- if (bp->link_up) {
- u32 bmsr;
- switch (bp->line_speed) {
- case SPEED_10:
- if (bp->duplex == DUPLEX_HALF)
- fw_link_status = BNX2_LINK_STATUS_10HALF;
- else
- fw_link_status = BNX2_LINK_STATUS_10FULL;
- break;
- case SPEED_100:
- if (bp->duplex == DUPLEX_HALF)
- fw_link_status = BNX2_LINK_STATUS_100HALF;
- else
- fw_link_status = BNX2_LINK_STATUS_100FULL;
- break;
- case SPEED_1000:
- if (bp->duplex == DUPLEX_HALF)
- fw_link_status = BNX2_LINK_STATUS_1000HALF;
- else
- fw_link_status = BNX2_LINK_STATUS_1000FULL;
- break;
- case SPEED_2500:
- if (bp->duplex == DUPLEX_HALF)
- fw_link_status = BNX2_LINK_STATUS_2500HALF;
- else
- fw_link_status = BNX2_LINK_STATUS_2500FULL;
- break;
- }
- fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
- if (bp->autoneg) {
- fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
- bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
- if (!(bmsr & BMSR_ANEGCOMPLETE) ||
- bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
- fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
- else
- fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
- }
- }
- else
- fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
- bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
- }
- static char *
- bnx2_xceiver_str(struct bnx2 *bp)
- {
- return (bp->phy_port == PORT_FIBRE) ? "SerDes" :
- ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
- "Copper");
- }
- static void
- bnx2_report_link(struct bnx2 *bp)
- {
- if (bp->link_up) {
- netif_carrier_on(bp->dev);
- netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex",
- bnx2_xceiver_str(bp),
- bp->line_speed,
- bp->duplex == DUPLEX_FULL ? "full" : "half");
- if (bp->flow_ctrl) {
- if (bp->flow_ctrl & FLOW_CTRL_RX) {
- pr_cont(", receive ");
- if (bp->flow_ctrl & FLOW_CTRL_TX)
- pr_cont("& transmit ");
- }
- else {
- pr_cont(", transmit ");
- }
- pr_cont("flow control ON");
- }
- pr_cont("\n");
- } else {
- netif_carrier_off(bp->dev);
- netdev_err(bp->dev, "NIC %s Link is Down\n",
- bnx2_xceiver_str(bp));
- }
- bnx2_report_fw_link(bp);
- }
- static void
- bnx2_resolve_flow_ctrl(struct bnx2 *bp)
- {
- u32 local_adv, remote_adv;
- bp->flow_ctrl = 0;
- if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
- (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
- if (bp->duplex == DUPLEX_FULL) {
- bp->flow_ctrl = bp->req_flow_ctrl;
- }
- return;
- }
- if (bp->duplex != DUPLEX_FULL) {
- return;
- }
- if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
- (BNX2_CHIP(bp) == BNX2_CHIP_5708)) {
- u32 val;
- bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
- if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
- bp->flow_ctrl |= FLOW_CTRL_TX;
- if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
- bp->flow_ctrl |= FLOW_CTRL_RX;
- return;
- }
- bnx2_read_phy(bp, bp->mii_adv, &local_adv);
- bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- u32 new_local_adv = 0;
- u32 new_remote_adv = 0;
- if (local_adv & ADVERTISE_1000XPAUSE)
- new_local_adv |= ADVERTISE_PAUSE_CAP;
- if (local_adv & ADVERTISE_1000XPSE_ASYM)
- new_local_adv |= ADVERTISE_PAUSE_ASYM;
- if (remote_adv & ADVERTISE_1000XPAUSE)
- new_remote_adv |= ADVERTISE_PAUSE_CAP;
- if (remote_adv & ADVERTISE_1000XPSE_ASYM)
- new_remote_adv |= ADVERTISE_PAUSE_ASYM;
- local_adv = new_local_adv;
- remote_adv = new_remote_adv;
- }
- /* See Table 28B-3 of 802.3ab-1999 spec. */
- if (local_adv & ADVERTISE_PAUSE_CAP) {
- if(local_adv & ADVERTISE_PAUSE_ASYM) {
- if (remote_adv & ADVERTISE_PAUSE_CAP) {
- bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
- }
- else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
- bp->flow_ctrl = FLOW_CTRL_RX;
- }
- }
- else {
- if (remote_adv & ADVERTISE_PAUSE_CAP) {
- bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
- }
- }
- }
- else if (local_adv & ADVERTISE_PAUSE_ASYM) {
- if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
- (remote_adv & ADVERTISE_PAUSE_ASYM)) {
- bp->flow_ctrl = FLOW_CTRL_TX;
- }
- }
- }
- static int
- bnx2_5709s_linkup(struct bnx2 *bp)
- {
- u32 val, speed;
- bp->link_up = 1;
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
- bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- if ((bp->autoneg & AUTONEG_SPEED) == 0) {
- bp->line_speed = bp->req_line_speed;
- bp->duplex = bp->req_duplex;
- return 0;
- }
- speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
- switch (speed) {
- case MII_BNX2_GP_TOP_AN_SPEED_10:
- bp->line_speed = SPEED_10;
- break;
- case MII_BNX2_GP_TOP_AN_SPEED_100:
- bp->line_speed = SPEED_100;
- break;
- case MII_BNX2_GP_TOP_AN_SPEED_1G:
- case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
- bp->line_speed = SPEED_1000;
- break;
- case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
- bp->line_speed = SPEED_2500;
- break;
- }
- if (val & MII_BNX2_GP_TOP_AN_FD)
- bp->duplex = DUPLEX_FULL;
- else
- bp->duplex = DUPLEX_HALF;
- return 0;
- }
- static int
- bnx2_5708s_linkup(struct bnx2 *bp)
- {
- u32 val;
- bp->link_up = 1;
- bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
- switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
- case BCM5708S_1000X_STAT1_SPEED_10:
- bp->line_speed = SPEED_10;
- break;
- case BCM5708S_1000X_STAT1_SPEED_100:
- bp->line_speed = SPEED_100;
- break;
- case BCM5708S_1000X_STAT1_SPEED_1G:
- bp->line_speed = SPEED_1000;
- break;
- case BCM5708S_1000X_STAT1_SPEED_2G5:
- bp->line_speed = SPEED_2500;
- break;
- }
- if (val & BCM5708S_1000X_STAT1_FD)
- bp->duplex = DUPLEX_FULL;
- else
- bp->duplex = DUPLEX_HALF;
- return 0;
- }
- static int
- bnx2_5706s_linkup(struct bnx2 *bp)
- {
- u32 bmcr, local_adv, remote_adv, common;
- bp->link_up = 1;
- bp->line_speed = SPEED_1000;
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- if (bmcr & BMCR_FULLDPLX) {
- bp->duplex = DUPLEX_FULL;
- }
- else {
- bp->duplex = DUPLEX_HALF;
- }
- if (!(bmcr & BMCR_ANENABLE)) {
- return 0;
- }
- bnx2_read_phy(bp, bp->mii_adv, &local_adv);
- bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
- common = local_adv & remote_adv;
- if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
- if (common & ADVERTISE_1000XFULL) {
- bp->duplex = DUPLEX_FULL;
- }
- else {
- bp->duplex = DUPLEX_HALF;
- }
- }
- return 0;
- }
- static int
- bnx2_copper_linkup(struct bnx2 *bp)
- {
- u32 bmcr;
- bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX;
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- if (bmcr & BMCR_ANENABLE) {
- u32 local_adv, remote_adv, common;
- bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
- bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
- common = local_adv & (remote_adv >> 2);
- if (common & ADVERTISE_1000FULL) {
- bp->line_speed = SPEED_1000;
- bp->duplex = DUPLEX_FULL;
- }
- else if (common & ADVERTISE_1000HALF) {
- bp->line_speed = SPEED_1000;
- bp->duplex = DUPLEX_HALF;
- }
- else {
- bnx2_read_phy(bp, bp->mii_adv, &local_adv);
- bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
- common = local_adv & remote_adv;
- if (common & ADVERTISE_100FULL) {
- bp->line_speed = SPEED_100;
- bp->duplex = DUPLEX_FULL;
- }
- else if (common & ADVERTISE_100HALF) {
- bp->line_speed = SPEED_100;
- bp->duplex = DUPLEX_HALF;
- }
- else if (common & ADVERTISE_10FULL) {
- bp->line_speed = SPEED_10;
- bp->duplex = DUPLEX_FULL;
- }
- else if (common & ADVERTISE_10HALF) {
- bp->line_speed = SPEED_10;
- bp->duplex = DUPLEX_HALF;
- }
- else {
- bp->line_speed = 0;
- bp->link_up = 0;
- }
- }
- }
- else {
- if (bmcr & BMCR_SPEED100) {
- bp->line_speed = SPEED_100;
- }
- else {
- bp->line_speed = SPEED_10;
- }
- if (bmcr & BMCR_FULLDPLX) {
- bp->duplex = DUPLEX_FULL;
- }
- else {
- bp->duplex = DUPLEX_HALF;
- }
- }
- if (bp->link_up) {
- u32 ext_status;
- bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status);
- if (ext_status & EXT_STATUS_MDIX)
- bp->phy_flags |= BNX2_PHY_FLAG_MDIX;
- }
- return 0;
- }
- static void
- bnx2_init_rx_context(struct bnx2 *bp, u32 cid)
- {
- u32 val, rx_cid_addr = GET_CID_ADDR(cid);
- val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
- val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
- val |= 0x02 << 8;
- if (bp->flow_ctrl & FLOW_CTRL_TX)
- val |= BNX2_L2CTX_FLOW_CTRL_ENABLE;
- bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
- }
- static void
- bnx2_init_all_rx_contexts(struct bnx2 *bp)
- {
- int i;
- u32 cid;
- for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) {
- if (i == 1)
- cid = RX_RSS_CID;
- bnx2_init_rx_context(bp, cid);
- }
- }
- static void
- bnx2_set_mac_link(struct bnx2 *bp)
- {
- u32 val;
- BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
- if (bp->link_up && (bp->line_speed == SPEED_1000) &&
- (bp->duplex == DUPLEX_HALF)) {
- BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
- }
- /* Configure the EMAC mode register. */
- val = BNX2_RD(bp, BNX2_EMAC_MODE);
- val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
- BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
- BNX2_EMAC_MODE_25G_MODE);
- if (bp->link_up) {
- switch (bp->line_speed) {
- case SPEED_10:
- if (BNX2_CHIP(bp) != BNX2_CHIP_5706) {
- val |= BNX2_EMAC_MODE_PORT_MII_10M;
- break;
- }
- /* fall through */
- case SPEED_100:
- val |= BNX2_EMAC_MODE_PORT_MII;
- break;
- case SPEED_2500:
- val |= BNX2_EMAC_MODE_25G_MODE;
- /* fall through */
- case SPEED_1000:
- val |= BNX2_EMAC_MODE_PORT_GMII;
- break;
- }
- }
- else {
- val |= BNX2_EMAC_MODE_PORT_GMII;
- }
- /* Set the MAC to operate in the appropriate duplex mode. */
- if (bp->duplex == DUPLEX_HALF)
- val |= BNX2_EMAC_MODE_HALF_DUPLEX;
- BNX2_WR(bp, BNX2_EMAC_MODE, val);
- /* Enable/disable rx PAUSE. */
- bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
- if (bp->flow_ctrl & FLOW_CTRL_RX)
- bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
- BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
- /* Enable/disable tx PAUSE. */
- val = BNX2_RD(bp, BNX2_EMAC_TX_MODE);
- val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
- if (bp->flow_ctrl & FLOW_CTRL_TX)
- val |= BNX2_EMAC_TX_MODE_FLOW_EN;
- BNX2_WR(bp, BNX2_EMAC_TX_MODE, val);
- /* Acknowledge the interrupt. */
- BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
- bnx2_init_all_rx_contexts(bp);
- }
- static void
- bnx2_enable_bmsr1(struct bnx2 *bp)
- {
- if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
- (BNX2_CHIP(bp) == BNX2_CHIP_5709))
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_GP_STATUS);
- }
- static void
- bnx2_disable_bmsr1(struct bnx2 *bp)
- {
- if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
- (BNX2_CHIP(bp) == BNX2_CHIP_5709))
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- }
- static int
- bnx2_test_and_enable_2g5(struct bnx2 *bp)
- {
- u32 up1;
- int ret = 1;
- if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
- return 0;
- if (bp->autoneg & AUTONEG_SPEED)
- bp->advertising |= ADVERTISED_2500baseX_Full;
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
- bnx2_read_phy(bp, bp->mii_up1, &up1);
- if (!(up1 & BCM5708S_UP1_2G5)) {
- up1 |= BCM5708S_UP1_2G5;
- bnx2_write_phy(bp, bp->mii_up1, up1);
- ret = 0;
- }
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- return ret;
- }
- static int
- bnx2_test_and_disable_2g5(struct bnx2 *bp)
- {
- u32 up1;
- int ret = 0;
- if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
- return 0;
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
- bnx2_read_phy(bp, bp->mii_up1, &up1);
- if (up1 & BCM5708S_UP1_2G5) {
- up1 &= ~BCM5708S_UP1_2G5;
- bnx2_write_phy(bp, bp->mii_up1, up1);
- ret = 1;
- }
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- return ret;
- }
- static void
- bnx2_enable_forced_2g5(struct bnx2 *bp)
- {
- u32 uninitialized_var(bmcr);
- int err;
- if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
- return;
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
- u32 val;
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_SERDES_DIG);
- if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
- val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
- val |= MII_BNX2_SD_MISC1_FORCE |
- MII_BNX2_SD_MISC1_FORCE_2_5G;
- bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
- }
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
- err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- if (!err)
- bmcr |= BCM5708S_BMCR_FORCE_2500;
- } else {
- return;
- }
- if (err)
- return;
- if (bp->autoneg & AUTONEG_SPEED) {
- bmcr &= ~BMCR_ANENABLE;
- if (bp->req_duplex == DUPLEX_FULL)
- bmcr |= BMCR_FULLDPLX;
- }
- bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
- }
- static void
- bnx2_disable_forced_2g5(struct bnx2 *bp)
- {
- u32 uninitialized_var(bmcr);
- int err;
- if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
- return;
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
- u32 val;
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_SERDES_DIG);
- if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) {
- val &= ~MII_BNX2_SD_MISC1_FORCE;
- bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
- }
- bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
- MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
- err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- if (!err)
- bmcr &= ~BCM5708S_BMCR_FORCE_2500;
- } else {
- return;
- }
- if (err)
- return;
- if (bp->autoneg & AUTONEG_SPEED)
- bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
- bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
- }
- static void
- bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
- {
- u32 val;
- bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
- bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
- if (start)
- bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
- else
- bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
- }
- static int
- bnx2_set_link(struct bnx2 *bp)
- {
- u32 bmsr;
- u8 link_up;
- if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
- bp->link_up = 1;
- return 0;
- }
- if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
- return 0;
- link_up = bp->link_up;
- bnx2_enable_bmsr1(bp);
- bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
- bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
- bnx2_disable_bmsr1(bp);
- if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
- (BNX2_CHIP(bp) == BNX2_CHIP_5706)) {
- u32 val, an_dbg;
- if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
- bnx2_5706s_force_link_dn(bp, 0);
- bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
- }
- val = BNX2_RD(bp, BNX2_EMAC_STATUS);
- bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
- bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
- bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
- if ((val & BNX2_EMAC_STATUS_LINK) &&
- !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
- bmsr |= BMSR_LSTATUS;
- else
- bmsr &= ~BMSR_LSTATUS;
- }
- if (bmsr & BMSR_LSTATUS) {
- bp->link_up = 1;
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- if (BNX2_CHIP(bp) == BNX2_CHIP_5706)
- bnx2_5706s_linkup(bp);
- else if (BNX2_CHIP(bp) == BNX2_CHIP_5708)
- bnx2_5708s_linkup(bp);
- else if (BNX2_CHIP(bp) == BNX2_CHIP_5709)
- bnx2_5709s_linkup(bp);
- }
- else {
- bnx2_copper_linkup(bp);
- }
- bnx2_resolve_flow_ctrl(bp);
- }
- else {
- if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
- (bp->autoneg & AUTONEG_SPEED))
- bnx2_disable_forced_2g5(bp);
- if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
- u32 bmcr;
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- bmcr |= BMCR_ANENABLE;
- bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
- bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
- }
- bp->link_up = 0;
- }
- if (bp->link_up != link_up) {
- bnx2_report_link(bp);
- }
- bnx2_set_mac_link(bp);
- return 0;
- }
- static int
- bnx2_reset_phy(struct bnx2 *bp)
- {
- int i;
- u32 reg;
- bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
- #define PHY_RESET_MAX_WAIT 100
- for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
- udelay(10);
- bnx2_read_phy(bp, bp->mii_bmcr, ®);
- if (!(reg & BMCR_RESET)) {
- udelay(20);
- break;
- }
- }
- if (i == PHY_RESET_MAX_WAIT) {
- return -EBUSY;
- }
- return 0;
- }
- static u32
- bnx2_phy_get_pause_adv(struct bnx2 *bp)
- {
- u32 adv = 0;
- if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
- (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- adv = ADVERTISE_1000XPAUSE;
- }
- else {
- adv = ADVERTISE_PAUSE_CAP;
- }
- }
- else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- adv = ADVERTISE_1000XPSE_ASYM;
- }
- else {
- adv = ADVERTISE_PAUSE_ASYM;
- }
- }
- else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
- }
- else {
- adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- }
- }
- return adv;
- }
- static int bnx2_fw_sync(struct bnx2 *, u32, int, int);
- static int
- bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
- __releases(&bp->phy_lock)
- __acquires(&bp->phy_lock)
- {
- u32 speed_arg = 0, pause_adv;
- pause_adv = bnx2_phy_get_pause_adv(bp);
- if (bp->autoneg & AUTONEG_SPEED) {
- speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
- if (bp->advertising & ADVERTISED_10baseT_Half)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
- if (bp->advertising & ADVERTISED_10baseT_Full)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
- if (bp->advertising & ADVERTISED_100baseT_Half)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
- if (bp->advertising & ADVERTISED_100baseT_Full)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
- if (bp->advertising & ADVERTISED_1000baseT_Full)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
- if (bp->advertising & ADVERTISED_2500baseX_Full)
- speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
- } else {
- if (bp->req_line_speed == SPEED_2500)
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
- else if (bp->req_line_speed == SPEED_1000)
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
- else if (bp->req_line_speed == SPEED_100) {
- if (bp->req_duplex == DUPLEX_FULL)
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
- else
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
- } else if (bp->req_line_speed == SPEED_10) {
- if (bp->req_duplex == DUPLEX_FULL)
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
- else
- speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
- }
- }
- if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
- speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
- if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
- speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
- if (port == PORT_TP)
- speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
- BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
- bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
- spin_unlock_bh(&bp->phy_lock);
- bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0);
- spin_lock_bh(&bp->phy_lock);
- return 0;
- }
- static int
- bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
- __releases(&bp->phy_lock)
- __acquires(&bp->phy_lock)
- {
- u32 adv, bmcr;
- u32 new_adv = 0;
- if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
- return bnx2_setup_remote_phy(bp, port);
- if (!(bp->autoneg & AUTONEG_SPEED)) {
- u32 new_bmcr;
- int force_link_down = 0;
- if (bp->req_line_speed == SPEED_2500) {
- if (!bnx2_test_and_enable_2g5(bp))
- force_link_down = 1;
- } else if (bp->req_line_speed == SPEED_1000) {
- if (bnx2_test_and_disable_2g5(bp))
- force_link_down = 1;
- }
- bnx2_read_phy(bp, bp->mii_adv, &adv);
- adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- new_bmcr = bmcr & ~BMCR_ANENABLE;
- new_bmcr |= BMCR_SPEED1000;
- if (BNX2_CHIP(bp) == BNX2_CHIP_5709) {
- if (bp->req_line_speed == SPEED_2500)
- bnx2_enable_forced_2g5(bp);
- else if (bp->req_line_speed == SPEED_1000) {
- bnx2_disable_forced_2g5(bp);
- new_bmcr &= ~0x2000;
- }
- } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) {
- if (bp->req_line_speed == SPEED_2500)
- new_bmcr |= BCM5708S_BMCR_FORCE_2500;
- else
- new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
- }
- if (bp->req_duplex == DUPLEX_FULL) {
- adv |= ADVERTISE_1000XFULL;
- new_bmcr |= BMCR_FULLDPLX;
- }
- else {
- adv |= ADVERTISE_1000XHALF;
- new_bmcr &= ~BMCR_FULLDPLX;
- }
- if ((new_bmcr != bmcr) || (force_link_down)) {
- /* Force a link down visible on the other side */
- if (bp->link_up) {
- bnx2_write_phy(bp, bp->mii_adv, adv &
- ~(ADVERTISE_1000XFULL |
- ADVERTISE_1000XHALF));
- bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
- BMCR_ANRESTART | BMCR_ANENABLE);
- bp->link_up = 0;
- netif_carrier_off(bp->dev);
- bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
- bnx2_report_link(bp);
- }
- bnx2_write_phy(bp, bp->mii_adv, adv);
- bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
- } else {
- bnx2_resolve_flow_ctrl(bp);
- bnx2_set_mac_link(bp);
- }
- return 0;
- }
- bnx2_test_and_enable_2g5(bp);
- if (bp->advertising & ADVERTISED_1000baseT_Full)
- new_adv |= ADVERTISE_1000XFULL;
- new_adv |= bnx2_phy_get_pause_adv(bp);
- bnx2_read_phy(bp, bp->mii_adv, &adv);
- bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
- bp->serdes_an_pending = 0;
- if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
- /* Force a link down visible on the other side */
- if (bp->link_up) {
- bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
- spin_unlock_bh(&bp->phy_lock);
- msleep(20);
- spin_lock_bh(&bp->phy_lock);
- }
- bnx2_write_phy(bp, bp->mii_adv, new_adv);
- bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
- BMCR_ANENABLE);
- /* Speed up link-up time when the link partner
- * does not autonegotiate which is very common
- * in blade servers. Some blade servers use
- * IPMI for kerboard input and it's important
- * to minimize link disruptions. Autoneg. involves
- * exchanging base pages plus 3 next pages and
- * normally completes in about 120 msec.
- */
- bp->current_interval = BNX2_SERDES_AN_TIMEOUT;
- bp->serdes_an_pending = 1;
- mod_timer(&bp->timer, jiffies + bp->current_interval);
- } else {
- bnx2_resolve_flow_ctrl(bp);
- bnx2_set_mac_link(bp);
- }
- return 0;
- }
- #define ETHTOOL_ALL_FIBRE_SPEED \
- (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \
- (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
- (ADVERTISED_1000baseT_Full)
- #define ETHTOOL_ALL_COPPER_SPEED \
- (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
- ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
- ADVERTISED_1000baseT_Full)
- #define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
- ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
- #define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
- static void
- bnx2_set_default_remote_link(struct bnx2 *bp)
- {
- u32 link;
- if (bp->phy_port == PORT_TP)
- link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
- else
- link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
- if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
- bp->req_line_speed = 0;
- bp->autoneg |= AUTONEG_SPEED;
- bp->advertising = ADVERTISED_Autoneg;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
- bp->advertising |= ADVERTISED_10baseT_Half;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
- bp->advertising |= ADVERTISED_10baseT_Full;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
- bp->advertising |= ADVERTISED_100baseT_Half;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
- bp->advertising |= ADVERTISED_100baseT_Full;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
- bp->advertising |= ADVERTISED_1000baseT_Full;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
- bp->advertising |= ADVERTISED_2500baseX_Full;
- } else {
- bp->autoneg = 0;
- bp->advertising = 0;
- bp->req_duplex = DUPLEX_FULL;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
- bp->req_line_speed = SPEED_10;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
- bp->req_duplex = DUPLEX_HALF;
- }
- if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
- bp->req_line_speed = SPEED_100;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
- bp->req_duplex = DUPLEX_HALF;
- }
- if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
- bp->req_line_speed = SPEED_1000;
- if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
- bp->req_line_speed = SPEED_2500;
- }
- }
- static void
- bnx2_set_default_link(struct bnx2 *bp)
- {
- if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
- bnx2_set_default_remote_link(bp);
- return;
- }
- bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
- bp->req_line_speed = 0;
- if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
- u32 reg;
- bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
- reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
- reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
- if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
- bp->autoneg = 0;
- bp->req_line_speed = bp->line_speed = SPEED_1000;
- bp->req_duplex = DUPLEX_FULL;
- }
- } else
- bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
- }
- static void
- bnx2_send_heart_beat(struct bnx2 *bp)
- {
- u32 msg;
- u32 addr;
- spin_lock(&bp->indirect_lock);
- msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
- addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
- BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
- BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
- spin_unlock(&bp->indirect_lock);
- }
- static void
- bnx2_remote_phy_event(struct bnx2 *bp)
- {
- u32 msg;
- u8 link_up = bp->link_up;
- u8 old_port;
- msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
- if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
- bnx2_send_heart_beat(bp);
- msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
- if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
- bp->link_up = 0;
- else {
- u32 speed;
- bp->link_up = 1;
- speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
- bp->duplex = DUPLEX_FULL;
- switch (speed) {
- case BNX2_LINK_STATUS_10HALF:
- bp->duplex = DUPLEX_HALF;
- /* fall through */
- case BNX2_LINK_STATUS_10FULL:
- bp->line_speed = SPEED_10;
- break;
- case BNX2_LINK_STATUS_100HALF:
- bp->duplex = DUPLEX_HALF;
- /* fall through */
- case BNX2_LINK_STATUS_100BASE_T4:
- ca…