X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fbnx2.c;h=09a53ff55290b31a9e20fdbd14cd0202d49ada46;hb=c2fbea4b185985eb51b00ccb5ed33687d1b99252;hp=1fdb16036264b022ec5ca4d19da91f7e7d54b3c9;hpb=c7ac0a6982b4512b54614ebfdd6a1805b5e9b273;p=linux-2.6.git diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1fdb16036..09a53ff55 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -11,8 +11,18 @@ #include +#include +#if (LINUX_VERSION_CODE < 0x020500) +#if defined(CONFIG_MODVERSIONS) && defined(MODULE) && ! defined(MODVERSIONS) +#define MODVERSIONS +#include +#endif +#endif + #include +#if (LINUX_VERSION_CODE >= 0x020600) #include +#endif #include #include @@ -26,12 +36,15 @@ #include #include #include +#if (LINUX_VERSION_CODE >= 0x020600) #include +#endif #include #include #include #include #include +#include #include #include #include @@ -44,19 +57,27 @@ #include #include #define BCM_TSO 1 +#ifndef NETIF_F_GSO +#define gso_size tso_size +#endif #endif +#if (LINUX_VERSION_CODE >= 0x020600) #include +#endif +#ifndef BNX2_BOOT_DISK #include +#endif #include #include +#include #include "bnx2.h" #include "bnx2_fw.h" #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.40" -#define DRV_MODULE_RELDATE "May 22, 2006" +#define DRV_MODULE_VERSION "1.4.43f" +#define DRV_MODULE_RELDATE "June 26, 2006" #define RUN_AT(x) (jiffies + (x)) @@ -71,10 +92,12 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); +#if (LINUX_VERSION_CODE >= 0x20600) static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); +#endif typedef enum { BCM5706 = 0, @@ -206,6 +229,22 @@ static struct flash_spec flash_table[] = MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); +#ifdef BNX2_BOOT_DISK +u32 ether_crc_le(size_t len, unsigned char const *p) +{ + u32 crc = ~0; + int i; +#define CRCPOLY_LE 0xedb88320 + + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + } + return crc; +} +#endif + static inline u32 bnx2_tx_avail(struct bnx2 *bp) { u32 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons); @@ -369,7 +408,11 @@ bnx2_disable_int_sync(struct bnx2 *bp) { atomic_inc(&bp->intr_sem); bnx2_disable_int(bp); +#if (LINUX_VERSION_CODE >= 0x2051c) synchronize_irq(bp->pdev->irq); +#else + synchronize_irq(); +#endif } static void @@ -431,11 +474,12 @@ bnx2_alloc_mem(struct bnx2 *bp) { int i, status_blk_size; - bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT, + bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT, GFP_KERNEL); if (bp->tx_buf_ring == NULL) return -ENOMEM; + memset(bp->tx_buf_ring, 0, sizeof(struct sw_bd) * TX_DESC_CNT); bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, sizeof(struct tx_bd) * TX_DESC_CNT, @@ -1421,7 +1465,8 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent) /* wait for an acknowledgement. */ for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) { - msleep(10); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ / 100); val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB); @@ -1638,7 +1683,7 @@ bnx2_tx_int(struct bnx2 *bp) skb = tx_buf->skb; #ifdef BCM_TSO /* partial BD completions possible with TSO packets */ - if (skb_shinfo(skb)->tso_size){ + if (skb_shinfo(skb)->gso_size) { u16 last_idx, last_ring_idx; last_idx = sw_cons + @@ -1674,7 +1719,7 @@ bnx2_tx_int(struct bnx2 *bp) tx_free_bd += last + 1; - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0; @@ -1695,6 +1740,7 @@ bnx2_tx_int(struct bnx2 *bp) } spin_unlock(&bp->tx_lock); } + } static inline void @@ -1820,9 +1866,9 @@ reuse_rx: skb->protocol = eth_type_trans(skb, bp->dev); if ((len > (bp->dev->mtu + ETH_HLEN)) && - (htons(skb->protocol) != 0x8100)) { + (ntohs(skb->protocol) != 0x8100)) { - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); goto next_rx; } @@ -1878,6 +1924,7 @@ next_rx: } +#ifdef CONFIG_PCI_MSI /* MSI ISR - The only difference between this and the INTx ISR * is that the MSI interrupt is always serviced. */ @@ -1900,6 +1947,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_HANDLED; } +#endif static irqreturn_t bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -2083,6 +2131,92 @@ bnx2_set_rx_mode(struct net_device *dev) spin_unlock_bh(&bp->phy_lock); } +#define FW_BUF_SIZE 0x8000 + +static int +bnx2_gunzip_init(struct bnx2 *bp) +{ + if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL) + goto gunzip_nomem1; + + if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL) + goto gunzip_nomem2; + + bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (bp->strm->workspace == NULL) + goto gunzip_nomem3; + + return 0; + +gunzip_nomem3: + kfree(bp->strm); + bp->strm = NULL; + +gunzip_nomem2: + vfree(bp->gunzip_buf); + bp->gunzip_buf = NULL; + +gunzip_nomem1: + printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for " + "uncompression.\n", bp->dev->name); + return -ENOMEM; +} + +static void +bnx2_gunzip_end(struct bnx2 *bp) +{ + kfree(bp->strm->workspace); + + kfree(bp->strm); + bp->strm = NULL; + + if (bp->gunzip_buf) { + vfree(bp->gunzip_buf); + bp->gunzip_buf = NULL; + } +} + +static int +bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen) +{ + int n, rc; + + /* check gzip header */ + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) + return -EINVAL; + + n = 10; + +#define FNAME 0x8 + if (zbuf[3] & FNAME) + while ((zbuf[n++] != 0) && (n < len)); + + bp->strm->next_in = zbuf + n; + bp->strm->avail_in = len - n; + bp->strm->next_out = bp->gunzip_buf; + bp->strm->avail_out = FW_BUF_SIZE; + + rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); + if (rc != Z_OK) + return rc; + + rc = zlib_inflate(bp->strm, Z_FINISH); + + *outlen = FW_BUF_SIZE - bp->strm->avail_out; + *outbuf = bp->gunzip_buf; + + if ((rc != Z_OK) && (rc != Z_STREAM_END)) + printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", + bp->dev->name, bp->strm->msg); + + zlib_inflateEnd(bp->strm); + + if (rc == Z_STREAM_END) + return 0; + + return rc; +} + static void load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, u32 rv2p_proc) @@ -2092,9 +2226,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, for (i = 0; i < rv2p_code_len; i += 8) { - REG_WR(bp, BNX2_RV2P_INSTR_HIGH, *rv2p_code); + REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code)); rv2p_code++; - REG_WR(bp, BNX2_RV2P_INSTR_LOW, *rv2p_code); + REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code)); rv2p_code++; if (rv2p_proc == RV2P_PROC1) { @@ -2134,7 +2268,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) int j; for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, fw->text[j]); + REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); } } @@ -2190,15 +2324,32 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) REG_WR_IND(bp, cpu_reg->mode, val); } -static void +static int bnx2_init_cpus(struct bnx2 *bp) { struct cpu_reg cpu_reg; struct fw_info fw; + int rc = 0; + void *text; + u32 text_len; + + if ((rc = bnx2_gunzip_init(bp)) != 0) + return rc; /* Initialize the RV2P processor. */ - load_rv2p_fw(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), RV2P_PROC1); - load_rv2p_fw(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), RV2P_PROC2); + rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text, + &text_len); + if (rc) + goto init_cpu_err; + + load_rv2p_fw(bp, text, text_len, RV2P_PROC1); + + rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text, + &text_len); + if (rc) + goto init_cpu_err; + + load_rv2p_fw(bp, text, text_len, RV2P_PROC2); /* Initialize the RX Processor. */ cpu_reg.mode = BNX2_RXP_CPU_MODE; @@ -2222,7 +2373,13 @@ bnx2_init_cpus(struct bnx2 *bp) fw.text_addr = bnx2_RXP_b06FwTextAddr; fw.text_len = bnx2_RXP_b06FwTextLen; fw.text_index = 0; - fw.text = bnx2_RXP_b06FwText; + + rc = bnx2_gunzip(bp, bnx2_RXP_b06FwText, sizeof(bnx2_RXP_b06FwText), + &text, &text_len); + if (rc) + goto init_cpu_err; + + fw.text = text; fw.data_addr = bnx2_RXP_b06FwDataAddr; fw.data_len = bnx2_RXP_b06FwDataLen; @@ -2268,7 +2425,13 @@ bnx2_init_cpus(struct bnx2 *bp) fw.text_addr = bnx2_TXP_b06FwTextAddr; fw.text_len = bnx2_TXP_b06FwTextLen; fw.text_index = 0; - fw.text = bnx2_TXP_b06FwText; + + rc = bnx2_gunzip(bp, bnx2_TXP_b06FwText, sizeof(bnx2_TXP_b06FwText), + &text, &text_len); + if (rc) + goto init_cpu_err; + + fw.text = text; fw.data_addr = bnx2_TXP_b06FwDataAddr; fw.data_len = bnx2_TXP_b06FwDataLen; @@ -2314,7 +2477,13 @@ bnx2_init_cpus(struct bnx2 *bp) fw.text_addr = bnx2_TPAT_b06FwTextAddr; fw.text_len = bnx2_TPAT_b06FwTextLen; fw.text_index = 0; - fw.text = bnx2_TPAT_b06FwText; + + rc = bnx2_gunzip(bp, bnx2_TPAT_b06FwText, sizeof(bnx2_TPAT_b06FwText), + &text, &text_len); + if (rc) + goto init_cpu_err; + + fw.text = text; fw.data_addr = bnx2_TPAT_b06FwDataAddr; fw.data_len = bnx2_TPAT_b06FwDataLen; @@ -2360,7 +2529,13 @@ bnx2_init_cpus(struct bnx2 *bp) fw.text_addr = bnx2_COM_b06FwTextAddr; fw.text_len = bnx2_COM_b06FwTextLen; fw.text_index = 0; - fw.text = bnx2_COM_b06FwText; + + rc = bnx2_gunzip(bp, bnx2_COM_b06FwText, sizeof(bnx2_COM_b06FwText), + &text, &text_len); + if (rc) + goto init_cpu_err; + + fw.text = text; fw.data_addr = bnx2_COM_b06FwDataAddr; fw.data_len = bnx2_COM_b06FwDataLen; @@ -2384,6 +2559,9 @@ bnx2_init_cpus(struct bnx2 *bp) load_cpu_fw(bp, &cpu_reg, &fw); +init_cpu_err: + bnx2_gunzip_end(bp); + return rc; } static int @@ -2401,9 +2579,11 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) (pmcsr & ~PCI_PM_CTRL_STATE_MASK) | PCI_PM_CTRL_PME_STATUS); - if (pmcsr & PCI_PM_CTRL_STATE_MASK) + if (pmcsr & PCI_PM_CTRL_STATE_MASK) { /* delay required during transition out of D3hot */ - msleep(20); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ / 50); + } val = REG_RD(bp, BNX2_EMAC_MODE); val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD; @@ -2766,7 +2946,6 @@ bnx2_init_nvram(struct bnx2 *bp) rc = 0; if (val & 0x40000000) { - /* Flash interface has been reconfigured */ for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) { @@ -3160,8 +3339,10 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val); if ((CHIP_ID(bp) == CHIP_ID_5706_A0) || - (CHIP_ID(bp) == CHIP_ID_5706_A1)) - msleep(15); + (CHIP_ID(bp) == CHIP_ID_5706_A1)) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ / 50); + } /* Reset takes approximate 30 usec */ for (i = 0; i < 10; i++) { @@ -3256,7 +3437,9 @@ bnx2_init_chip(struct bnx2 *bp) * context block must have already been enabled. */ bnx2_init_context(bp); - bnx2_init_cpus(bp); + if ((rc = bnx2_init_cpus(bp)) != 0) + return rc; + bnx2_init_nvram(bp); bnx2_set_mac_addr(bp); @@ -3556,7 +3739,9 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code) if (rc) return rc; - bnx2_init_chip(bp); + if ((rc = bnx2_init_chip(bp)) != 0) + return rc; + bnx2_init_tx_ring(bp); bnx2_init_rx_ring(bp); return 0; @@ -3863,7 +4048,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) udelay(5); pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) { goto loopback_test_done; @@ -4011,7 +4196,8 @@ bnx2_test_intr(struct bnx2 *bp) break; } - msleep_interruptible(10); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 100); } if (i < 10) return 0; @@ -4034,6 +4220,8 @@ bnx2_timer(unsigned long data) msg = (u32) ++bp->fw_drv_pulse_wr_seq; REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg); + bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT); + if ((bp->phy_flags & PHY_SERDES_FLAG) && (CHIP_NUM(bp) == CHIP_NUM_5706)) { @@ -4112,6 +4300,7 @@ bnx2_open(struct net_device *dev) if (rc) return rc; +#ifdef CONFIG_PCI_MSI if ((CHIP_ID(bp) != CHIP_ID_5706_A0) && (CHIP_ID(bp) != CHIP_ID_5706_A1) && !disable_msi) { @@ -4126,7 +4315,9 @@ bnx2_open(struct net_device *dev) SA_SHIRQ, dev->name, dev); } } - else { + else +#endif + { rc = request_irq(bp->pdev->irq, bnx2_interrupt, SA_SHIRQ, dev->name, dev); } @@ -4139,10 +4330,12 @@ bnx2_open(struct net_device *dev) if (rc) { free_irq(bp->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI if (bp->flags & USING_MSI_FLAG) { pci_disable_msi(bp->pdev); bp->flags &= ~USING_MSI_FLAG; } +#endif bnx2_free_skbs(bp); bnx2_free_mem(bp); return rc; @@ -4154,6 +4347,7 @@ bnx2_open(struct net_device *dev) bnx2_enable_int(bp); +#ifdef CONFIG_PCI_MSI if (bp->flags & USING_MSI_FLAG) { /* Test MSI to make sure it is working * If MSI test fails, go back to INTx mode @@ -4188,6 +4382,7 @@ bnx2_open(struct net_device *dev) if (bp->flags & USING_MSI_FLAG) { printk(KERN_INFO PFX "%s: using MSI\n", dev->name); } +#endif netif_start_queue(dev); @@ -4218,7 +4413,11 @@ bnx2_tx_timeout(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); /* This allows the netif to be shutdown gracefully before resetting */ +#if (LINUX_VERSION_CODE >= 0x20600) schedule_work(&bp->reset_task); +#else + schedule_task(&bp->reset_task); +#endif } #ifdef BCM_VLAN @@ -4252,6 +4451,93 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) } #endif +/* Test for DMA addresses > 40-bit. + * Only 64-bit systems without IOMMU requires DMA address checking. + */ +static inline int bnx2_40bit_overflow_test(struct bnx2 *bp, dma_addr_t mapping, + int len) +{ +#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) + if (CHIP_NUM(bp) == CHIP_NUM_5708) + return (((u64) mapping + len) > DMA_40BIT_MASK); + return 0; +#else + return 0; +#endif +} + +#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) +/* Workaround 40-bit hardware DMA bugs. */ +static int bnx2_dma_hwbug_workaround(struct bnx2 *bp, struct sk_buff **skb, + u16 *last_plus_one, u32 base_flags, + u32 mss) +{ + struct sk_buff *new_skb = skb_copy(*skb, GFP_ATOMIC); + dma_addr_t new_addr = 0; + int i, ret = 0; + u16 hw_prod = *last_plus_one; + u16 start, hw_start, prod; + + prod = TX_RING_IDX(hw_prod); + start = prod - 1 - skb_shinfo(*skb)->nr_frags; + hw_start = hw_prod - 1 - skb_shinfo(*skb)->nr_frags; + start &= MAX_TX_DESC_CNT; + if (start > prod) { + start--; + hw_start--; + } + + if (!new_skb) { + ret = -1; + } else { + struct tx_bd *txbd; + + /* New SKB is guaranteed to be linear. */ + new_addr = pci_map_single(bp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + txbd = &bp->tx_desc_ring[start]; + + txbd->tx_bd_haddr_hi = (u64) new_addr >> 32; + txbd->tx_bd_haddr_lo = (u64) new_addr & 0xffffffff; + txbd->tx_bd_mss_nbytes = new_skb->len | (mss << 16); + txbd->tx_bd_vlan_tag_flags = base_flags | TX_BD_FLAGS_START | + TX_BD_FLAGS_END; + + *last_plus_one = NEXT_TX_BD(hw_start); + } + + /* Now clean up the sw ring entries. */ + i = 0; + while (start != prod) { + int len; + + if (i == 0) + len = skb_headlen(*skb); + else + len = skb_shinfo(*skb)->frags[i-1].size; + + pci_unmap_single(bp->pdev, + pci_unmap_addr(&tp->tx_buf_ring[start], + mapping), + len, PCI_DMA_TODEVICE); + if (i == 0) { + bp->tx_buf_ring[start].skb = new_skb; + pci_unmap_addr_set(&bp->tx_buf_ring[start], mapping, + new_addr); + } + hw_start = NEXT_TX_BD(hw_start); + start = TX_RING_IDX(hw_start); + i++; + } + + dev_kfree_skb(*skb); + + *skb = new_skb; + + return ret; +} +#endif + /* Called with netif_tx_lock. * hard_start_xmit is pseudo-lockless - a lock is only required when * the tx queue is full. This way, we get the benefit of lockless @@ -4267,7 +4553,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) struct sw_bd *tx_buf; u32 len, vlan_tag_flags, last_frag, mss; u16 prod, ring_prod; - int i; + int i, would_hit_hwbug = 0; if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) { netif_stop_queue(dev); @@ -4285,20 +4571,24 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } +#ifdef BCM_VLAN if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) { vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } +#endif #ifdef BCM_TSO - if ((mss = skb_shinfo(skb)->tso_size) && + if ((mss = skb_shinfo(skb)->gso_size) && (skb->len > (bp->dev->mtu + ETH_HLEN))) { u32 tcp_opt_len, ip_tcp_len; +#if (LINUX_VERSION_CODE > 0x2060b) if (skb_header_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } +#endif tcp_opt_len = ((skb->h.th->doff - 5) * 4); vlan_tag_flags |= TX_BD_FLAGS_SW_LSO; @@ -4310,7 +4600,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr); skb->nh.iph->check = 0; - skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len); + skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, @@ -4360,10 +4650,26 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd->tx_bd_mss_nbytes = len | (mss << 16); txbd->tx_bd_vlan_tag_flags = vlan_tag_flags; + if (bnx2_40bit_overflow_test(bp, mapping, len)) + would_hit_hwbug = 1; } + txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END; prod = NEXT_TX_BD(prod); + +#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) + if (unlikely(would_hit_hwbug)) { + /* If the workaround fails due to memory/mapping + * failure, silently drop this packet. + */ + if (bnx2_dma_hwbug_workaround(bp, &skb, &prod, + vlan_tag_flags, mss)) + return NETDEV_TX_OK; + + } +#endif + bp->tx_prod_bseq += skb->len; REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod); @@ -4397,23 +4703,27 @@ bnx2_close(struct net_device *dev) * linkwatch_event() may be on the workqueue and it will try to get * the rtnl_lock which we are holding. */ - while (bp->in_reset_task) - msleep(1); + while (bp->in_reset_task) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } bnx2_netif_stop(bp); del_timer_sync(&bp->timer); if (bp->flags & NO_WOL_FLAG) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD; + reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; else if (bp->wol) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; else reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; bnx2_reset_chip(bp, reset_code); free_irq(bp->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI if (bp->flags & USING_MSI_FLAG) { pci_disable_msi(bp->pdev); bp->flags &= ~USING_MSI_FLAG; } +#endif bnx2_free_skbs(bp); bnx2_free_mem(bp); bp->link_up = 0; @@ -4504,6 +4814,10 @@ bnx2_get_stats(struct net_device *dev) net_stats->tx_aborted_errors + net_stats->tx_carrier_errors; + net_stats->rx_missed_errors = + (unsigned long) (stats_blk->stat_IfInMBUFDiscards + + stats_blk->stat_FwRxDrop); + return net_stats; } @@ -4757,7 +5071,8 @@ bnx2_nway_reset(struct net_device *dev) bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); - msleep(20); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ / 50); spin_lock_bh(&bp->phy_lock); if (CHIP_NUM(bp) == CHIP_NUM_5706) { @@ -4776,6 +5091,7 @@ bnx2_nway_reset(struct net_device *dev) return 0; } +#if (LINUX_VERSION_CODE >= 0x20418) static int bnx2_get_eeprom_len(struct net_device *dev) { @@ -4786,7 +5102,9 @@ bnx2_get_eeprom_len(struct net_device *dev) return (int) bp->flash_size; } +#endif +#ifdef ETHTOOL_GEEPROM static int bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *eebuf) @@ -4800,7 +5118,9 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, return rc; } +#endif +#ifdef ETHTOOL_SEEPROM static int bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *eebuf) @@ -4814,6 +5134,7 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, return rc; } +#endif static int bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) @@ -4986,7 +5307,7 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data) return 0; } -#define BNX2_NUM_STATS 45 +#define BNX2_NUM_STATS 46 static struct { char string[ETH_GSTRING_LEN]; @@ -5036,6 +5357,7 @@ static struct { { "rx_mac_ctrl_frames" }, { "rx_filtered_packets" }, { "rx_discards" }, + { "rx_fw_discards" }, }; #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4) @@ -5086,6 +5408,7 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { STATS_OFFSET32(stat_MacControlFramesReceived), STATS_OFFSET32(stat_IfInFramesL2FilterDiscards), STATS_OFFSET32(stat_IfInMBUFDiscards), + STATS_OFFSET32(stat_FwRxDrop), }; /* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are @@ -5096,7 +5419,7 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = { 4,0,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4, + 4,4,4,4,4,4, }; static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { @@ -5104,7 +5427,7 @@ static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4, + 4,4,4,4,4,4, }; #define BNX2_NUM_TESTS 6 @@ -5157,9 +5480,12 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) } /* wait for link up */ - msleep_interruptible(3000); - if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG)) - msleep_interruptible(4000); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(3 * HZ); + if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(4 * HZ); + } } if (bnx2_test_nvram(bp) != 0) { @@ -5265,7 +5591,8 @@ bnx2_phys_id(struct net_device *dev, u32 data) BNX2_EMAC_LED_TRAFFIC_OVERRIDE | BNX2_EMAC_LED_TRAFFIC); } - msleep_interruptible(500); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 2); if (signal_pending(current)) break; } @@ -5284,9 +5611,15 @@ static struct ethtool_ops bnx2_ethtool_ops = { .set_wol = bnx2_set_wol, .nway_reset = bnx2_nway_reset, .get_link = ethtool_op_get_link, +#if (LINUX_VERSION_CODE >= 0x20418) .get_eeprom_len = bnx2_get_eeprom_len, +#endif +#ifdef ETHTOOL_GEEPROM .get_eeprom = bnx2_get_eeprom, +#endif +#ifdef ETHTOOL_SEEPROM .set_eeprom = bnx2_set_eeprom, +#endif .get_coalesce = bnx2_get_coalesce, .set_coalesce = bnx2_set_coalesce, .get_ringparam = bnx2_get_ringparam, @@ -5296,7 +5629,9 @@ static struct ethtool_ops bnx2_ethtool_ops = { .get_rx_csum = bnx2_get_rx_csum, .set_rx_csum = bnx2_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, +#if (LINUX_VERSION_CODE >= 0x20418) .set_tx_csum = ethtool_op_set_tx_csum, +#endif .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, #ifdef BCM_TSO @@ -5309,14 +5644,20 @@ static struct ethtool_ops bnx2_ethtool_ops = { .phys_id = bnx2_phys_id, .get_stats_count = bnx2_get_stats_count, .get_ethtool_stats = bnx2_get_ethtool_stats, +#ifdef ETHTOOL_GPERMADDR .get_perm_addr = ethtool_op_get_perm_addr, +#endif }; /* Called with rtnl_lock */ static int bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { +#if (LINUX_VERSION_CODE >= 0x020607) struct mii_ioctl_data *data = if_mii(ifr); +#else + struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_ifru; +#endif struct bnx2 *bp = netdev_priv(dev); int err; @@ -5398,9 +5739,22 @@ poll_bnx2(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); - disable_irq(bp->pdev->irq); - bnx2_interrupt(bp->pdev->irq, dev, NULL); - enable_irq(bp->pdev->irq); +#if defined(RED_HAT_LINUX_KERNEL) && (LINUX_VERSION_CODE < 0x020600) + if (netdump_mode) { + bnx2_interrupt(bp->pdev->irq, dev, NULL); + if (dev->poll_list.prev) { + int budget = 64; + + bnx2_poll(dev, &budget); + } + } + else +#endif + { + disable_irq(bp->pdev->irq); + bnx2_interrupt(bp->pdev->irq, dev, NULL); + enable_irq(bp->pdev->irq); + } } #endif @@ -5411,9 +5765,12 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) unsigned long mem_len; int rc; u32 reg; + u64 dma_mask, persist_dma_mask; SET_MODULE_OWNER(dev); +#if (LINUX_VERSION_CODE >= 0x20419) SET_NETDEV_DEV(dev, &pdev->dev); +#endif bp = netdev_priv(dev); bp->flags = 0; @@ -5456,27 +5813,16 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_release; } - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { - bp->flags |= USING_DAC_FLAG; - if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { - printk(KERN_ERR PFX "pci_set_consistent_dma_mask " - "failed, aborting.\n"); - rc = -EIO; - goto err_out_release; - } - } - else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { - printk(KERN_ERR PFX "System does not support DMA, aborting.\n"); - rc = -EIO; - goto err_out_release; - } - bp->dev = dev; bp->pdev = pdev; spin_lock_init(&bp->phy_lock); spin_lock_init(&bp->tx_lock); +#if (LINUX_VERSION_CODE >= 0x20600) INIT_WORK(&bp->reset_task, bnx2_reset_task, bp); +#else + INIT_TQUEUE(&bp->reset_task, bnx2_reset_task, bp); +#endif dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0); mem_len = MB_GET_CID_ADDR(17); @@ -5503,6 +5849,33 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->chip_id = REG_RD(bp, BNX2_MISC_ID); + /* 5708 cannot support DMA addresses > 40-bit. + * On 64-bit systems with IOMMU, use 40-bit dma_mask. + * On 64-bit systems without IOMMU, use 64-bit dma_mask and + * do DMA address check in bnx2_start_xmit(). + */ + if (CHIP_NUM(bp) == CHIP_NUM_5708) { + persist_dma_mask = dma_mask = DMA_40BIT_MASK; +#ifdef CONFIG_HIGHMEM + dma_mask = DMA_64BIT_MASK; +#endif + } else + persist_dma_mask = dma_mask = DMA_64BIT_MASK; + + /* Configure DMA attributes. */ + if (pci_set_dma_mask(pdev, dma_mask) == 0) { + dev->features |= NETIF_F_HIGHDMA; + rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask); + if (rc) { + printk(KERN_ERR PFX "pci_set_consistent_dma_mask " + "failed, aborting.\n"); + goto err_out_unmap; + } + } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) { + printk(KERN_ERR PFX "System does not support DMA, aborting.\n"); + goto err_out_unmap; + } + /* Get bus information. */ reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS); if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { @@ -5634,7 +6007,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } } - if (CHIP_NUM(bp) == CHIP_NUM_5708) + if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || + (CHIP_ID(bp) == CHIP_ID_5708_B0) || + (CHIP_ID(bp) == CHIP_ID_5708_B1)) bp->flags |= NO_WOL_FLAG; if (CHIP_ID(bp) == CHIP_ID_5706_A0) { @@ -5704,14 +6079,23 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO "%s", version); /* dev zeroed in init_etherdev */ +#if (LINUX_VERSION_CODE >= 0x20418) dev = alloc_etherdev(sizeof(*bp)); +#else + dev = init_etherdev(NULL, sizeof(*bp)); +#endif if (!dev) return -ENOMEM; rc = bnx2_init_board(pdev, dev); if (rc < 0) { +#if (LINUX_VERSION_CODE >= 0x20418) free_netdev(dev); +#else + unregister_netdev(dev); + kfree(dev); +#endif return rc; } @@ -5739,6 +6123,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->poll_controller = poll_bnx2; #endif +#if (LINUX_VERSION_CODE >= 0x20418) if ((rc = register_netdev(dev))) { printk(KERN_ERR PFX "Cannot register net device\n"); if (bp->regview) @@ -5749,11 +6134,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) free_netdev(dev); return rc; } +#endif pci_set_drvdata(pdev, dev); memcpy(dev->dev_addr, bp->mac_addr, 6); +#ifdef ETHTOOL_GPERMADDR memcpy(dev->perm_addr, bp->mac_addr, 6); +#endif bp->name = board_info[ent->driver_data].name, printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, " "IRQ %d, ", @@ -5772,10 +6160,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) printk("%2.2x", dev->dev_addr[i]); printk("\n"); - dev->features |= NETIF_F_SG; - if (bp->flags & USING_DAC_FLAG) - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_IP_CSUM; + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #ifdef BCM_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif @@ -5794,14 +6179,20 @@ bnx2_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); +#if (LINUX_VERSION_CODE >= 0x20600) flush_scheduled_work(); +#endif unregister_netdev(dev); if (bp->regview) iounmap(bp->regview); +#if (LINUX_VERSION_CODE >= 0x20418) free_netdev(dev); +#else + kfree(dev); +#endif pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -5817,7 +6208,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; - flush_scheduled_work(); bnx2_netif_stop(bp); netif_device_detach(dev); del_timer_sync(&bp->timer); @@ -5829,7 +6219,11 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; bnx2_reset_chip(bp, reset_code); bnx2_free_skbs(bp); +#if (LINUX_VERSION_CODE < 0x2060b) + bnx2_set_power_state(bp, state); +#else bnx2_set_power_state(bp, pci_choose_state(pdev, state)); +#endif return 0; }