diff options
-rw-r--r-- | drivers/net/sky2.c | 147 |
1 files changed, 84 insertions, 63 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index d2c0d04be723..0cc57293faf9 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -468,9 +468,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) /* serial mode register */ reg = DATA_BLIND_VAL(DATA_BLIND_DEF) | - GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); + GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); - if (hw->dev[port]->mtu > 1500) + if (hw->dev[port]->mtu > ETH_DATA_LEN) reg |= GM_SMOD_JUMBO_ENA; gma_write16(hw, port, GM_SERIAL_MODE, reg); @@ -515,8 +515,6 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, size_t len) len /= 8; end = start + len - 1; - pr_debug("sky2_ramset start=%d end=%d\n", start, end); - sky2_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); sky2_write32(hw, RB_ADDR(q, RB_START), start); sky2_write32(hw, RB_ADDR(q, RB_END), end); @@ -528,7 +526,6 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, size_t len) rxlo = len/2; rxup = rxlo + len/4; - pr_debug(" utpp=%d ltpp=%d\n", rxup, rxlo); /* Set thresholds on receive queue's */ sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), rxup); @@ -662,16 +659,44 @@ static void rx_set_checksum(struct sky2_port *sky2) le->ctrl = 0; le->opcode = OP_TCPSTART | HW_OWNER; - sky2_write16(sky2->hw, Y2_QADDR(rxqaddr[sky2->port], - PREF_UNIT_PUT_IDX), sky2->rx_put); - sky2_read16(sky2->hw, Y2_QADDR(rxqaddr[sky2->port], PREF_UNIT_PUT_IDX)); - mdelay(1); sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } +/* + * The RX Stop command will not work for Yukon-2 if the BMU does not + * reach the end of packet and since we can't make sure that we have + * incoming data, we must reset the BMU while it is not doing a DMA + * transfer. Since it is possible that the RX path is still active, + * the RX RAM buffer will be stopped first, so any possible incoming + * data will not trigger a DMA. After the RAM buffer is stopped, the + * BMU is polled until any DMA in progress is ended and only then it + * will be reset. + */ +static void sky2_rx_stop(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + unsigned rxq = rxqaddr[sky2->port]; + int i; + + /* disable the RAM Buffer receive queue */ + sky2_write8(hw, RB_ADDR(rxq, RB_CTRL), RB_DIS_OP_MD); + + for (i = 0; i < 0xffff; i++) + if (sky2_read8(hw, RB_ADDR(rxq, Q_RSL)) + == sky2_read8(hw, RB_ADDR(rxq, Q_RL))) + goto stopped; + + printk(KERN_WARNING PFX "%s: receiver stop failed\n", + sky2->netdev->name); +stopped: + sky2_write32(hw, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); + + /* reset the Rx prefetch unit */ + sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); +} /* Cleanout receive buffer area, assumes receiver hardware stopped */ static void sky2_rx_clean(struct sky2_port *sky2) @@ -693,7 +718,7 @@ static void sky2_rx_clean(struct sky2_port *sky2) } #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -static inline unsigned sky2_rx_size(const struct sky2_port *sky2) +static inline unsigned rx_size(const struct sky2_port *sky2) { return roundup(sky2->netdev->mtu + ETH_HLEN + 4, 8); } @@ -709,12 +734,18 @@ static inline unsigned sky2_rx_size(const struct sky2_port *sky2) * is not aligned. This means we can't use skb_reserve to align * the IP header. */ -static int sky2_rx_fill(struct sky2_port *sky2) +static int sky2_rx_start(struct sky2_port *sky2) { - unsigned i; - unsigned size = sky2_rx_size(sky2); + struct sky2_hw *hw = sky2->hw; + unsigned size = rx_size(sky2); + unsigned rxq = rxqaddr[sky2->port]; + int i; + + sky2->rx_put = sky2->rx_next = 0; + sky2_qset(hw, rxq, is_pciex(hw) ? 0x80 : 0x600); + sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); - pr_debug("rx_fill size=%d\n", size); + rx_set_checksum(sky2); for (i = 0; i < sky2->rx_pending; i++) { struct ring_info *re = sky2->rx_ring + i; @@ -722,12 +753,15 @@ static int sky2_rx_fill(struct sky2_port *sky2) if (!re->skb) goto nomem; - re->mapaddr = pci_map_single(sky2->hw->pdev, re->skb->data, + re->mapaddr = pci_map_single(hw->pdev, re->skb->data, size, PCI_DMA_FROMDEVICE); re->maplen = size; sky2_rx_add(sky2, re); } + /* Tell chip about available buffers */ + sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put); + sky2->rx_last_put = sky2_read16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX)); return 0; nomem: sky2_rx_clean(sky2); @@ -792,28 +826,14 @@ static int sky2_up(struct net_device *dev) sky2_write8(hw, RB_ADDR(port == 0 ? Q_XS1 : Q_XS2, RB_CTRL), RB_RST_SET); - sky2_qset(hw, rxqaddr[port], is_pciex(hw) ? 0x80 : 0x600); sky2_qset(hw, txqaddr[port], 0x600); + sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, + TX_RING_SIZE - 1); - sky2->rx_put = sky2->rx_next = 0; - sky2_prefetch_init(hw, rxqaddr[port], sky2->rx_le_map, RX_LE_SIZE - 1); - - rx_set_checksum(sky2); - - err = sky2_rx_fill(sky2); + err = sky2_rx_start(sky2); if (err) goto err_out; - /* Give buffers to receiver */ - sky2_write16(sky2->hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX), - sky2->rx_put); - sky2->rx_last_put = sky2_read16(sky2->hw, - Y2_QADDR(rxqaddr[port], - PREF_UNIT_PUT_IDX)); - - sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, - TX_RING_SIZE - 1); - /* Enable interrupts from phy/mac for port */ hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; sky2_write32(hw, B0_IMSK, hw->intr_mask); @@ -1076,7 +1096,6 @@ static int sky2_down(struct net_device *dev) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 ctrl; - int i; if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); @@ -1121,30 +1140,7 @@ static int sky2_down(struct net_device *dev) sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); - /* - * The RX Stop command will not work for Yukon-2 if the BMU does not - * reach the end of packet and since we can't make sure that we have - * incoming data, we must reset the BMU while it is not doing a DMA - * transfer. Since it is possible that the RX path is still active, - * the RX RAM buffer will be stopped first, so any possible incoming - * data will not trigger a DMA. After the RAM buffer is stopped, the - * BMU is polled until any DMA in progress is ended and only then it - * will be reset. - */ - - /* disable the RAM Buffer receive queue */ - sky2_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_DIS_OP_MD); - - for (i = 0; i < 0xffff; i++) - if (sky2_read8(hw, RB_ADDR(rxqaddr[port], Q_RSL)) - == sky2_read8(hw, RB_ADDR(rxqaddr[port], Q_RL))) - break; - - sky2_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), - BMU_RST_SET | BMU_FIFO_RST); - /* reset the Rx prefetch unit */ - sky2_write32(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_CTRL), - PREF_UNIT_RST_SET); + sky2_rx_stop(sky2); sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); @@ -1379,19 +1375,44 @@ static void sky2_tx_timeout(struct net_device *dev) static int sky2_change_mtu(struct net_device *dev, int new_mtu) { - int err = 0; + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; + int err; + u16 ctl, mode; if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; - if (netif_running(dev)) - sky2_down(dev); + if (!netif_running(dev)) { + dev->mtu = new_mtu; + return 0; + } + + local_irq_disable(); + sky2_write32(hw, B0_IMSK, 0); + + ctl = gma_read16(hw, sky2->port, GM_GP_CTRL); + gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); + sky2_rx_stop(sky2); + sky2_rx_clean(sky2); dev->mtu = new_mtu; + mode = DATA_BLIND_VAL(DATA_BLIND_DEF) | + GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); - if (netif_running(dev)) - err = sky2_up(dev); + if (dev->mtu > ETH_DATA_LEN) + mode |= GM_SMOD_JUMBO_ENA; + + gma_write16(hw, sky2->port, GM_SERIAL_MODE, mode); + + sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD); + + err = sky2_rx_start(sky2); + gma_write16(hw, sky2->port, GM_GP_CTRL, ctl); + sky2_write32(hw, B0_IMSK, hw->intr_mask); + sky2_read32(hw, B0_IMSK); + local_irq_enable(); return err; } @@ -1407,7 +1428,7 @@ static struct sk_buff *sky2_receive(struct sky2_hw *hw, unsigned port, struct sky2_port *sky2 = netdev_priv(dev); struct ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; - const unsigned int bufsize = sky2_rx_size(sky2); + const unsigned int bufsize = rx_size(sky2); if (unlikely(netif_msg_rx_status(sky2))) printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", |