X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fsky2.c;h=54c662690f65482b613954918ce499121a84ea61;hb=ed85f2c3b2b72bd20f617ac749f5c22be8d0f66e;hp=bc15940ce1bc8ed74ba8127df49f0599d2262c48;hpb=9b73e76f3cf63379dcf45fcd4f112f5812418d0a;p=linux-2.6 diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bc15940ce1..54c662690f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.20" +#define DRV_VERSION "1.21" #define PFX DRV_NAME " " /* @@ -64,7 +64,6 @@ #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) #define RX_MAX_PENDING (RX_LE_SIZE/6 - 2) #define RX_DEF_PENDING RX_MAX_PENDING -#define RX_SKB_ALIGN 8 #define TX_RING_SIZE 512 #define TX_DEF_PENDING (TX_RING_SIZE - 1) @@ -135,6 +134,8 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436D) }, /* 88E8055 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4370) }, /* 88E8075 */ { 0 } }; @@ -548,6 +549,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: + case CHIP_ID_YUKON_SUPR: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ @@ -570,8 +572,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) default: /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; + /* turn off the Rx LED (LED_RX) */ - ledover &= ~PHY_M_LED_MO_RX; + ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); } if (hw->chip_id == CHIP_ID_YUKON_EC_U && @@ -600,7 +603,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ - ledover |= PHY_M_LED_MO_100; + ledover |= PHY_M_LED_MO_100(MO_LED_ON); } if (ledover) @@ -621,6 +624,7 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA }; + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); /* Turn on/off phy power saving */ if (onoff) @@ -632,7 +636,8 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) reg1 |= coma_mode[port]; sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + sky2_pci_read32(hw, PCI_DEV_REG1); udelay(100); } @@ -714,23 +719,33 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) { struct net_device *dev = hw->dev[port]; - if (dev->mtu <= ETH_DATA_LEN) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); + if ( (hw->chip_id == CHIP_ID_YUKON_EX && + hw->chip_rev != CHIP_REV_YU_EX_A0) || + hw->chip_id == CHIP_ID_YUKON_FE_P || + hw->chip_id == CHIP_ID_YUKON_SUPR) { + /* Yukon-Extreme B0 and further Extreme devices */ + /* enable Store & Forward mode for TX */ - else if (hw->chip_id != CHIP_ID_YUKON_EC_U) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_STFW_ENA | TX_JUMBO_ENA); - else { - /* 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 (dev->mtu <= ETH_DATA_LEN) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); - 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_ENA| TX_STFW_ENA); + } else { + if (dev->mtu <= ETH_DATA_LEN) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA); + else { + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); - /* Can't do offload because of lack of store/forward */ - dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS); + + /* Can't do offload because of lack of store/forward */ + dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); + } } } @@ -843,7 +858,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); /* On chips without ram buffer, pause is controled by MAC level */ - if (sky2_read8(hw, B2_E_0) == 0) { + if (!(hw->flags & SKY2_HW_RAM_BUFFER)) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); @@ -1174,24 +1189,32 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp /* * Allocate an skb for receiving. If the MTU is large enough * make the skb non-linear with a fragment list of pages. - * - * It appears the hardware has a bug in the FIFO logic that - * cause it to hang if the FIFO gets overrun and the receive buffer - * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is - * aligned except if slab debugging is enabled. */ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) { struct sk_buff *skb; - unsigned long p; int i; - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN); - if (!skb) - goto nomem; - - p = (unsigned long) skb->data; - skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p); + if (sky2->hw->flags & SKY2_HW_RAM_BUFFER) { + unsigned char *start; + /* + * Workaround for a bug in FIFO that cause hang + * if the FIFO if the receive buffer is not 64 byte aligned. + * The buffer returned from netdev_alloc_skb is + * aligned except if slab debugging is enabled. + */ + skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + 8); + if (!skb) + goto nomem; + start = PTR_ALIGN(skb->data, 8); + skb_reserve(skb, start - skb->data); + } else { + skb = netdev_alloc_skb(sky2->netdev, + sky2->rx_data_size + NET_IP_ALIGN); + if (!skb) + goto nomem; + skb_reserve(skb, NET_IP_ALIGN); + } for (i = 0; i < sky2->rx_nfrags; i++) { struct page *page = alloc_page(GFP_ATOMIC); @@ -1227,7 +1250,7 @@ static int sky2_rx_start(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; struct rx_ring_info *re; unsigned rxq = rxqaddr[sky2->port]; - unsigned i, size, space, thresh; + unsigned i, size, thresh; sky2->rx_put = sky2->rx_next = 0; sky2_qset(hw, rxq); @@ -1254,28 +1277,18 @@ static int sky2_rx_start(struct sky2_port *sky2) /* Stopping point for hardware truncation */ thresh = (size - 8) / sizeof(u32); - /* Account for overhead of skb - to avoid order > 0 allocation */ - space = SKB_DATA_ALIGN(size) + NET_SKB_PAD - + sizeof(struct skb_shared_info); - - sky2->rx_nfrags = space >> PAGE_SHIFT; + sky2->rx_nfrags = size >> PAGE_SHIFT; BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr)); - if (sky2->rx_nfrags != 0) { - /* Compute residue after pages */ - space = sky2->rx_nfrags << PAGE_SHIFT; + /* Compute residue after pages */ + size -= sky2->rx_nfrags << PAGE_SHIFT; - if (space < size) - size -= space; - else - size = 0; + /* Optimize to handle small packets and headers */ + if (size < copybreak) + size = copybreak; + if (size < ETH_HLEN) + size = ETH_HLEN; - /* Optimize to handle small packets and headers */ - if (size < copybreak) - size = copybreak; - if (size < ETH_HLEN) - size = ETH_HLEN; - } sky2->rx_data_size = size; /* Fill Rx ring */ @@ -1375,6 +1388,7 @@ static int sky2_up(struct net_device *dev) if (ramsize > 0) { u32 rxspace; + hw->flags |= SKY2_HW_RAM_BUFFER; pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize); if (ramsize < 16) rxspace = ramsize / 2; @@ -1412,6 +1426,7 @@ static int sky2_up(struct net_device *dev) imask |= portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); + sky2_set_multicast(dev); return 0; err_out: @@ -2013,7 +2028,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) synchronize_irq(hw->pdev->irq); - if (sky2_read8(hw, B2_E_0) == 0) + if (!(hw->flags & SKY2_HW_RAM_BUFFER)) sky2_set_tx_stfwd(hw, port); ctl = gma_read16(hw, port, GM_GP_CTRL); @@ -2426,6 +2441,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) { u16 pci_err; + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); pci_err = sky2_pci_read16(hw, PCI_STATUS); if (net_ratelimit()) dev_err(&pdev->dev, "PCI hardware error (0x%x)\n", @@ -2433,12 +2449,14 @@ static void sky2_hw_intr(struct sky2_hw *hw) sky2_pci_write16(hw, PCI_STATUS, pci_err | PCI_STATUS_ERROR_BITS); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } if (status & Y2_IS_PCI_EXP) { /* PCI-Express uncorrectable Error occurred */ u32 err; + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS); sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS, 0xfffffffful); @@ -2446,6 +2464,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err); sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } if (status & Y2_HWE_L1_MASK) @@ -2549,7 +2568,7 @@ static void sky2_watchdog(unsigned long arg) ++active; /* For chips with Rx FIFO, check if stuck */ - if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) && + if ((hw->flags & SKY2_HW_RAM_BUFFER) && sky2_rx_hung(dev)) { pr_info(PFX "%s: receiver hang detected\n", dev->name); @@ -2663,6 +2682,7 @@ static u32 sky2_mhz(const struct sky2_hw *hw) case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: + case CHIP_ID_YUKON_SUPR: return 125; case CHIP_ID_YUKON_FE: @@ -2704,11 +2724,7 @@ static int __devinit sky2_init(struct sky2_hw *hw) switch(hw->chip_id) { case CHIP_ID_YUKON_XL: - hw->flags = SKY2_HW_GIGABIT - | SKY2_HW_NEWER_PHY; - if (hw->chip_rev < 3) - hw->flags |= SKY2_HW_FIFO_HANG_CHECK; - + hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY; break; case CHIP_ID_YUKON_EC_U: @@ -2734,7 +2750,7 @@ static int __devinit sky2_init(struct sky2_hw *hw) dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n"); return -EOPNOTSUPP; } - hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK; + hw->flags = SKY2_HW_GIGABIT; break; case CHIP_ID_YUKON_FE: @@ -2746,6 +2762,15 @@ static int __devinit sky2_init(struct sky2_hw *hw) | SKY2_HW_AUTO_TX_SUM | SKY2_HW_ADV_POWER_CTL; break; + + case CHIP_ID_YUKON_SUPR: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_NEWER_PHY + | SKY2_HW_NEW_LE + | SKY2_HW_AUTO_TX_SUM + | SKY2_HW_ADV_POWER_CTL; + break; + default: dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", hw->chip_id); @@ -2811,12 +2836,14 @@ static void sky2_reset(struct sky2_hw *hw) } sky2_power_on(hw); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); for (i = 0; i < hw->ports; i++) { sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); - if (hw->chip_id == CHIP_ID_YUKON_EX) + if (hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_SUPR) sky2_write16(hw, SK_REG(i, GMAC_CTRL), GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | GMC_BYP_RETR_ON); @@ -3296,82 +3323,80 @@ static void sky2_set_multicast(struct net_device *dev) /* Can have one global because blinking is controlled by * ethtool and that is always under RTNL mutex */ -static void sky2_led(struct sky2_hw *hw, unsigned port, int on) +static void sky2_led(struct sky2_port *sky2, enum led_mode mode) { - u16 pg; + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; - switch (hw->chip_id) { - case CHIP_ID_YUKON_XL: + spin_lock_bh(&sky2->phy_lock); + if (hw->chip_id == CHIP_ID_YUKON_EC_U || + hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_SUPR) { + u16 pg; pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, - on ? (PHY_M_LEDC_LOS_CTRL(1) | - PHY_M_LEDC_INIT_CTRL(7) | - PHY_M_LEDC_STA1_CTRL(7) | - PHY_M_LEDC_STA0_CTRL(7)) - : 0); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - break; + switch (mode) { + case MO_LED_OFF: + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + PHY_M_LEDC_LOS_CTRL(8) | + PHY_M_LEDC_INIT_CTRL(8) | + PHY_M_LEDC_STA1_CTRL(8) | + PHY_M_LEDC_STA0_CTRL(8)); + break; + case MO_LED_ON: + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + PHY_M_LEDC_LOS_CTRL(9) | + PHY_M_LEDC_INIT_CTRL(9) | + PHY_M_LEDC_STA1_CTRL(9) | + PHY_M_LEDC_STA0_CTRL(9)); + break; + case MO_LED_BLINK: + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + PHY_M_LEDC_LOS_CTRL(0xa) | + PHY_M_LEDC_INIT_CTRL(0xa) | + PHY_M_LEDC_STA1_CTRL(0xa) | + PHY_M_LEDC_STA0_CTRL(0xa)); + break; + case MO_LED_NORM: + gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, + PHY_M_LEDC_LOS_CTRL(1) | + PHY_M_LEDC_INIT_CTRL(8) | + PHY_M_LEDC_STA1_CTRL(7) | + PHY_M_LEDC_STA0_CTRL(7)); + } - default: - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); + gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); + } else gm_phy_write(hw, port, PHY_MARV_LED_OVER, - on ? PHY_M_LED_ALL : 0); - } + PHY_M_LED_MO_DUP(mode) | + PHY_M_LED_MO_10(mode) | + PHY_M_LED_MO_100(mode) | + PHY_M_LED_MO_1000(mode) | + PHY_M_LED_MO_RX(mode) | + PHY_M_LED_MO_TX(mode)); + + spin_unlock_bh(&sky2->phy_lock); } /* blink LED's for finding board */ static int sky2_phys_id(struct net_device *dev, u32 data) { struct sky2_port *sky2 = netdev_priv(dev); - struct sky2_hw *hw = sky2->hw; - unsigned port = sky2->port; - u16 ledctrl, ledover = 0; - long ms; - int interrupted; - int onoff = 1; + unsigned int i; - if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)) - ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT); - else - ms = data * 1000; + if (data == 0) + data = UINT_MAX; - /* save initial values */ - spin_lock_bh(&sky2->phy_lock); - if (hw->chip_id == CHIP_ID_YUKON_XL) { - u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - ledctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - } else { - ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL); - ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER); - } - - interrupted = 0; - while (!interrupted && ms > 0) { - sky2_led(hw, port, onoff); - onoff = !onoff; - - spin_unlock_bh(&sky2->phy_lock); - interrupted = msleep_interruptible(250); - spin_lock_bh(&sky2->phy_lock); - - ms -= 250; - } - - /* resume regularly scheduled programming */ - if (hw->chip_id == CHIP_ID_YUKON_XL) { - u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ledctrl); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - } else { - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); + for (i = 0; i < data; i++) { + sky2_led(sky2, MO_LED_ON); + if (msleep_interruptible(500)) + break; + sky2_led(sky2, MO_LED_OFF); + if (msleep_interruptible(500)) + break; } - spin_unlock_bh(&sky2->phy_lock); + sky2_led(sky2, MO_LED_NORM); return 0; } @@ -3533,8 +3558,6 @@ static int sky2_set_ringparam(struct net_device *dev, err = sky2_up(dev); if (err) dev_close(dev); - else - sky2_set_multicast(dev); } return err; @@ -4368,8 +4391,6 @@ static int sky2_resume(struct pci_dev *pdev) dev_close(dev); goto out; } - - sky2_set_multicast(dev); } }