X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;ds=inline;f=drivers%2Fnet%2Fsky2.c;h=3764008270a223eb816839069d7fc05987b44f49;hb=549a68c3fe2ca320b0764d1289d17af797daa5d1;hp=53839979cfb8fb1249dc27161b4cab2649fb994c;hpb=6d04e3b04b6ab569cabeb5ca28ad1be11777e895;p=linux-2.6-omap-h63xx.git diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 53839979cfb..3764008270a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.13" +#define DRV_VERSION "1.14" #define PFX DRV_NAME " " /* @@ -510,9 +511,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ledover &= ~PHY_M_LED_MO_RX; } - if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U && + hw->chip_rev == CHIP_REV_YU_EC_U_A1) { /* apply fixes in PHY AFE */ - pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255); /* increase differential signal amplitude in 10BASE-T */ @@ -524,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, 0x17, 0x2002); /* set page register to 0 */ - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); } else if (hw->chip_id != CHIP_ID_YUKON_EX) { gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); @@ -740,12 +741,17 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); - if (hw->dev[port]->mtu > ETH_DATA_LEN) { - /* set Tx GMAC FIFO Almost Empty Threshold */ - sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), 0x180); - /* Disable Store & Forward mode for TX */ - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS); - } + + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); + + if (hw->dev[port]->mtu > ETH_DATA_LEN) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_DIS); + else + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); } } @@ -1278,7 +1284,7 @@ static int sky2_up(struct net_device *dev) /* Set almost empty threshold */ if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_U_A0) - sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0); + sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV); sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, TX_RING_SIZE - 1); @@ -1383,8 +1389,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Check for TCP Segmentation Offload */ mss = skb_shinfo(skb)->gso_size; if (mss != 0) { - mss += ((skb->h.th->doff - 5) * 4); /* TCP options */ - mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); + mss += tcp_optlen(skb); /* TCP options */ + mss += ip_hdrlen(skb) + sizeof(struct tcphdr); mss += ETH_HLEN; if (mss != sky2->tx_last_mss) { @@ -1412,14 +1418,14 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Handle TCP checksum offload */ if (skb->ip_summed == CHECKSUM_PARTIAL) { - unsigned offset = skb->h.raw - skb->data; + const unsigned offset = skb_transport_offset(skb); u32 tcpsum; tcpsum = offset << 16; /* sum start */ tcpsum |= offset + skb->csum_offset; /* sum write */ ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM; - if (skb->nh.iph->protocol == IPPROTO_UDP) + if (ip_hdr(skb)->protocol == IPPROTO_UDP) ctrl |= UDPTCP; if (tcpsum != sky2->tx_tcpsum) { @@ -1561,6 +1567,7 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); + netif_carrier_off(dev); /* Disable port IRQ */ imask = sky2_read32(hw, B0_IMSK); @@ -1583,13 +1590,6 @@ static int sky2_down(struct net_device *dev) sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET | RB_DIS_OP_MD); - /* WA for dev. #4.209 */ - if (hw->chip_id == CHIP_ID_YUKON_EC_U - && (hw->chip_rev == CHIP_REV_YU_EC_U_A1 || hw->chip_rev == CHIP_REV_YU_EC_U_B0)) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - sky2->speed != SPEED_1000 ? - TX_STFW_ENA : TX_STFW_DIS); - ctrl = gma_read16(hw, port, GM_GP_CTRL); ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); @@ -1889,6 +1889,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; int err; u16 ctl, mode; u32 imask; @@ -1896,9 +1897,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; - /* TSO on Yukon Ultra and MTU > 1500 not supported */ - if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN) - dev->features &= ~NETIF_F_TSO; + if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE) + return -EINVAL; if (!netif_running(dev)) { dev->mtu = new_mtu; @@ -1914,8 +1914,18 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) synchronize_irq(hw->pdev->irq); - ctl = gma_read16(hw, sky2->port, GM_GP_CTRL); - gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { + if (new_mtu > ETH_DATA_LEN) { + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_DIS); + dev->features &= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; + } else + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); + } + + ctl = gma_read16(hw, port, GM_GP_CTRL); + gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); sky2_rx_stop(sky2); sky2_rx_clean(sky2); @@ -1927,9 +1937,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (dev->mtu > ETH_DATA_LEN) mode |= GM_SMOD_JUMBO_ENA; - gma_write16(hw, sky2->port, GM_SERIAL_MODE, mode); + gma_write16(hw, port, GM_SERIAL_MODE, mode); - sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD); + sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD); err = sky2_rx_start(sky2); sky2_write32(hw, B0_IMSK, imask); @@ -1937,7 +1947,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (err) dev_close(dev); else { - gma_write16(hw, sky2->port, GM_GP_CTRL, ctl); + gma_write16(hw, port, GM_GP_CTRL, ctl); netif_poll_enable(hw->dev[0]); netif_wake_queue(dev); @@ -1958,7 +1968,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); - memcpy(skb->data, re->skb->data, length); + skb_copy_from_linear_data(re->skb, skb->data, length); skb->ip_summed = re->skb->ip_summed; skb->csum = re->skb->csum; pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, @@ -2165,9 +2175,27 @@ force_update: /* fall through */ #endif case OP_RXCHKS: - skb = sky2->rx_ring[sky2->rx_next].skb; - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = status & 0xffff; + if (!sky2->rx_csum) + break; + + /* Both checksum counters are programmed to start at + * the same offset, so unless there is a problem they + * should match. This failure is an early indication that + * hardware receive checksumming won't work. + */ + if (likely(status >> 16 == (status & 0xffff))) { + skb = sky2->rx_ring[sky2->rx_next].skb; + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = status & 0xffff; + } else { + printk(KERN_NOTICE PFX "%s: hardware receive " + "checksum problem (status = %#x)\n", + dev->name, status); + sky2->rx_csum = 0; + sky2_write32(sky2->hw, + Q_ADDR(rxqaddr[le->link], Q_CSR), + BMU_DIS_RX_CHKSUM); + } break; case OP_TXINDEXLE: @@ -2321,26 +2349,22 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) } } -/* This should never happen it is a fatal situation */ -static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, - const char *rxtx, u32 mask) +/* This should never happen it is a bug. */ +static void sky2_le_error(struct sky2_hw *hw, unsigned port, + u16 q, unsigned ring_size) { struct net_device *dev = hw->dev[port]; struct sky2_port *sky2 = netdev_priv(dev); - u32 imask; + unsigned idx; + const u64 *le = (q == Q_R1 || q == Q_R2) + ? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le; - printk(KERN_ERR PFX "%s: %s descriptor error (hardware problem)\n", - dev ? dev->name : "", rxtx); + idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); + printk(KERN_ERR PFX "%s: descriptor error q=%#x get=%u [%llx] put=%u\n", + dev->name, (unsigned) q, idx, (unsigned long long) le[idx], + (unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX))); - imask = sky2_read32(hw, B0_IMSK); - imask &= ~mask; - sky2_write32(hw, B0_IMSK, imask); - - if (dev) { - spin_lock(&sky2->phy_lock); - sky2_link_down(sky2); - spin_unlock(&sky2->phy_lock); - } + sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK); } /* If idle then force a fake soft NAPI poll once a second @@ -2364,23 +2388,15 @@ static void sky2_idle(unsigned long arg) mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout)); } - -static int sky2_poll(struct net_device *dev0, int *budget) +/* Hardware/software error handling */ +static void sky2_err_intr(struct sky2_hw *hw, u32 status) { - struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; - int work_limit = min(dev0->quota, *budget); - int work_done = 0; - u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + if (net_ratelimit()) + dev_warn(&hw->pdev->dev, "error interrupt status=%#x\n", status); if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); - if (status & Y2_IS_IRQ_PHY1) - sky2_phy_intr(hw, 0); - - if (status & Y2_IS_IRQ_PHY2) - sky2_phy_intr(hw, 1); - if (status & Y2_IS_IRQ_MAC1) sky2_mac_intr(hw, 0); @@ -2388,16 +2404,33 @@ static int sky2_poll(struct net_device *dev0, int *budget) sky2_mac_intr(hw, 1); if (status & Y2_IS_CHK_RX1) - sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); + sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE); if (status & Y2_IS_CHK_RX2) - sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); + sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE); if (status & Y2_IS_CHK_TXA1) - sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); + sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE); if (status & Y2_IS_CHK_TXA2) - sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); + sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE); +} + +static int sky2_poll(struct net_device *dev0, int *budget) +{ + struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; + int work_limit = min(dev0->quota, *budget); + int work_done = 0; + u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + + if (unlikely(status & Y2_IS_ERROR)) + sky2_err_intr(hw, status); + + if (status & Y2_IS_IRQ_PHY1) + sky2_phy_intr(hw, 0); + + if (status & Y2_IS_IRQ_PHY2) + sky2_phy_intr(hw, 1); work_done = sky2_status_intr(hw, work_limit); if (work_done < work_limit) { @@ -2515,16 +2548,14 @@ static void sky2_reset(struct sky2_hw *hw) int i; /* disable ASF */ - if (hw->chip_id <= CHIP_ID_YUKON_EC) { - if (hw->chip_id == CHIP_ID_YUKON_EX) { - status = sky2_read16(hw, HCU_CCSR); - status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE | - HCU_CCSR_UC_STATE_MSK); - sky2_write16(hw, HCU_CCSR, status); - } else - sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); - sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE); - } + if (hw->chip_id == CHIP_ID_YUKON_EX) { + status = sky2_read16(hw, HCU_CCSR); + status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE | + HCU_CCSR_UC_STATE_MSK); + sky2_write16(hw, HCU_CCSR, status); + } else + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); + sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE); /* do a SW reset */ sky2_write8(hw, B0_CTST, CS_RST_SET); @@ -3309,6 +3340,36 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, regs->len - B3_RI_WTO_R1); } +/* In order to do Jumbo packets on these chips, need to turn off the + * transmit store/forward. Therefore checksum offload won't work. + */ +static int no_tx_offload(struct net_device *dev) +{ + const struct sky2_port *sky2 = netdev_priv(dev); + const struct sky2_hw *hw = sky2->hw; + + return dev->mtu > ETH_DATA_LEN && + (hw->chip_id == CHIP_ID_YUKON_EX + || hw->chip_id == CHIP_ID_YUKON_EC_U); +} + +static int sky2_set_tx_csum(struct net_device *dev, u32 data) +{ + if (data && no_tx_offload(dev)) + return -EINVAL; + + return ethtool_op_set_tx_csum(dev, data); +} + + +static int sky2_set_tso(struct net_device *dev, u32 data) +{ + if (data && no_tx_offload(dev)) + return -EINVAL; + + return ethtool_op_set_tso(dev, data); +} + static const struct ethtool_ops sky2_ethtool_ops = { .get_settings = sky2_get_settings, .set_settings = sky2_set_settings, @@ -3324,9 +3385,9 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, + .set_tx_csum = sky2_set_tx_csum, .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, + .set_tso = sky2_set_tso, .get_rx_csum = sky2_get_rx_csum, .set_rx_csum = sky2_set_rx_csum, .get_strings = sky2_get_strings, @@ -3517,10 +3578,21 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out; } + /* Some Gigabyte motherboards have 88e8056 but cause problems + * There is some unresolved hardware related problem that causes + * descriptor errors and receive data corruption. + */ + if (pdev->vendor == PCI_VENDOR_ID_MARVELL && + pdev->device == 0x4364 && pdev->subsystem_vendor == 0x1458) { + dev_err(&pdev->dev, + "88E8056 on Gigabyte motherboards not supported\n"); + goto err_out_disable; + } + err = pci_request_regions(pdev, DRV_NAME); if (err) { dev_err(&pdev->dev, "cannot obtain PCI resources\n"); - goto err_out; + goto err_out_disable; } pci_set_master(pdev); @@ -3657,8 +3729,10 @@ err_out_free_hw: kfree(hw); err_out_free_regions: pci_release_regions(pdev); +err_out_disable: pci_disable_device(pdev); err_out: + pci_set_drvdata(pdev, NULL); return err; } @@ -3711,6 +3785,9 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) struct sky2_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; + if (!hw) + return 0; + del_timer_sync(&hw->idle_timer); netif_poll_disable(hw->dev[0]); @@ -3742,6 +3819,9 @@ static int sky2_resume(struct pci_dev *pdev) struct sky2_hw *hw = pci_get_drvdata(pdev); int i, err; + if (!hw) + return 0; + err = pci_set_power_state(pdev, PCI_D0); if (err) goto out; @@ -3751,6 +3831,11 @@ static int sky2_resume(struct pci_dev *pdev) goto out; pci_enable_wake(pdev, PCI_D0, 0); + + /* Re-enable all clocks */ + if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U) + sky2_pci_write32(hw, PCI_DEV_REG3, 0); + sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); @@ -3783,6 +3868,9 @@ static void sky2_shutdown(struct pci_dev *pdev) struct sky2_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; + if (!hw) + return; + del_timer_sync(&hw->idle_timer); netif_poll_disable(hw->dev[0]);