Commit a19d03a3 authored by David S. Miller's avatar David S. Miller

Merge 2.4.x Sun GEM/HME net driver fixes.

parent 71c54597
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
* I can at least detect gigabit with autoneg. * I can at least detect gigabit with autoneg.
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -35,9 +37,10 @@ ...@@ -35,9 +37,10 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/crc32.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/random.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/bitops.h> #include <asm/bitops.h>
...@@ -293,19 +296,119 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s ...@@ -293,19 +296,119 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
return 0; return 0;
} }
/* When we get a RX fifo overflow, the RX unit in GEM is probably hung
* so we do the following.
*
* If any part of the reset goes wrong, we return 1 and that causes the
* whole chip to be reset.
*/
static int gem_rxmac_reset(struct gem *gp)
{
struct net_device *dev = gp->dev;
int limit, i;
u64 desc_dma;
u32 val;
/* First, reset MAC RX. */
writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB,
gp->regs + MAC_RXCFG);
for (limit = 0; limit < 5000; limit++) {
if (!(readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB))
break;
udelay(10);
}
if (limit == 5000) {
printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
"chip.\n", dev->name);
return 1;
}
/* Second, disable RX DMA. */
writel(0, gp->regs + RXDMA_CFG);
for (limit = 0; limit < 5000; limit++) {
if (!(readl(gp->regs + RXDMA_CFG) & RXDMA_CFG_ENABLE))
break;
udelay(10);
}
if (limit == 5000) {
printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
"chip.\n", dev->name);
return 1;
}
udelay(5000);
/* Execute RX reset command. */
writel(gp->swrst_base | GREG_SWRST_RXRST,
gp->regs + GREG_SWRST);
for (limit = 0; limit < 5000; limit++) {
if (!(readl(gp->regs + GREG_SWRST) & GREG_SWRST_RXRST))
break;
udelay(10);
}
if (limit == 5000) {
printk(KERN_ERR "%s: RX reset command will not execute, resetting "
"whole chip.\n", dev->name);
return 1;
}
/* Refresh the RX ring. */
for (i = 0; i < RX_RING_SIZE; i++) {
struct gem_rxd *rxd = &gp->init_block->rxd[i];
if (gp->rx_skbs[i] == NULL) {
printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
"whole chip.\n", dev->name);
return 1;
}
rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
}
gp->rx_new = gp->rx_old = 0;
/* Now we must reprogram the rest of RX unit. */
desc_dma = (u64) gp->gblock_dvma;
desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
writel(val, gp->regs + RXDMA_CFG);
if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
writel(((5 & RXDMA_BLANK_IPKTS) |
((8 << 12) & RXDMA_BLANK_ITIME)),
gp->regs + RXDMA_BLANK);
else
writel(((5 & RXDMA_BLANK_IPKTS) |
((4 << 12) & RXDMA_BLANK_ITIME)),
gp->regs + RXDMA_BLANK);
val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF);
val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON);
writel(val, gp->regs + RXDMA_PTHRESH);
val = readl(gp->regs + RXDMA_CFG);
writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
val = readl(gp->regs + MAC_RXCFG);
writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
return 0;
}
static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
{ {
u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT); u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
int ret = 0;
if (netif_msg_intr(gp)) if (netif_msg_intr(gp))
printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n", printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
gp->dev->name, rxmac_stat); gp->dev->name, rxmac_stat);
if (rxmac_stat & MAC_RXSTAT_OFLW) { if (rxmac_stat & MAC_RXSTAT_OFLW) {
printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
dev->name);
gp->net_stats.rx_over_errors++; gp->net_stats.rx_over_errors++;
gp->net_stats.rx_fifo_errors++; gp->net_stats.rx_fifo_errors++;
ret = gem_rxmac_reset(gp);
} }
if (rxmac_stat & MAC_RXSTAT_ACE) if (rxmac_stat & MAC_RXSTAT_ACE)
...@@ -320,7 +423,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s ...@@ -320,7 +423,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
/* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE /* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE
* events. * events.
*/ */
return 0; return ret;
} }
static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
...@@ -480,7 +583,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat ...@@ -480,7 +583,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat
return 0; return 0;
do_reset: do_reset:
gp->reset_task_pending = 1; gp->reset_task_pending = 2;
schedule_task(&gp->reset_task); schedule_task(&gp->reset_task);
return 1; return 1;
...@@ -542,7 +645,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st ...@@ -542,7 +645,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
gp->tx_old = entry; gp->tx_old = entry;
if (netif_queue_stopped(dev) && if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL(gp) > 0) TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -717,7 +820,7 @@ static void gem_tx_timeout(struct net_device *dev) ...@@ -717,7 +820,7 @@ static void gem_tx_timeout(struct net_device *dev)
spin_lock_irq(&gp->lock); spin_lock_irq(&gp->lock);
gp->reset_task_pending = 1; gp->reset_task_pending = 2;
schedule_task(&gp->reset_task); schedule_task(&gp->reset_task);
spin_unlock_irq(&gp->lock); spin_unlock_irq(&gp->lock);
...@@ -752,9 +855,12 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -752,9 +855,12 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&gp->lock); spin_lock_irq(&gp->lock);
/* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irq(&gp->lock); spin_unlock_irq(&gp->lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1; return 1;
} }
...@@ -829,7 +935,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -829,7 +935,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
gp->tx_new = entry; gp->tx_new = entry;
if (TX_BUFFS_AVAIL(gp) <= 0) if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev); netif_stop_queue(dev);
if (netif_msg_tx_queued(gp)) if (netif_msg_tx_queued(gp))
...@@ -844,19 +950,28 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -844,19 +950,28 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
/* Jumbo-grams don't seem to work :-( */ /* Jumbo-grams don't seem to work :-( */
#define GEM_MIN_MTU 68
#if 1 #if 1
#define MAX_MTU 1500 #define GEM_MAX_MTU 1500
#else #else
#define MAX_MTU 9000 #define GEM_MAX_MTU 9000
#endif #endif
static int gem_change_mtu(struct net_device *dev, int new_mtu) static int gem_change_mtu(struct net_device *dev, int new_mtu)
{ {
struct gem *gp = dev->priv; struct gem *gp = dev->priv;
if (new_mtu < 0 || new_mtu > MAX_MTU) if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
return -EINVAL; return -EINVAL;
if (!netif_running(dev) || !netif_device_present(dev)) {
/* We'll just catch it later when the
* device is up'd or resumed.
*/
dev->mtu = new_mtu;
return 0;
}
spin_lock_irq(&gp->lock); spin_lock_irq(&gp->lock);
dev->mtu = new_mtu; dev->mtu = new_mtu;
gp->reset_task_pending = 1; gp->reset_task_pending = 1;
...@@ -870,6 +985,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) ...@@ -870,6 +985,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
#define STOP_TRIES 32 #define STOP_TRIES 32
/* Must be invoked under gp->lock. */
static void gem_stop(struct gem *gp) static void gem_stop(struct gem *gp)
{ {
int limit; int limit;
...@@ -879,7 +995,8 @@ static void gem_stop(struct gem *gp) ...@@ -879,7 +995,8 @@ static void gem_stop(struct gem *gp)
writel(0xffffffff, gp->regs + GREG_IMASK); writel(0xffffffff, gp->regs + GREG_IMASK);
/* Reset the chip */ /* Reset the chip */
writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST); writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST,
gp->regs + GREG_SWRST);
limit = STOP_TRIES; limit = STOP_TRIES;
...@@ -894,6 +1011,7 @@ static void gem_stop(struct gem *gp) ...@@ -894,6 +1011,7 @@ static void gem_stop(struct gem *gp)
printk(KERN_ERR "gem: SW reset is ghetto.\n"); printk(KERN_ERR "gem: SW reset is ghetto.\n");
} }
/* Must be invoked under gp->lock. */
static void gem_start_dma(struct gem *gp) static void gem_start_dma(struct gem *gp)
{ {
unsigned long val; unsigned long val;
...@@ -929,6 +1047,7 @@ static int phy_BCM5400_link_table[8][3] = { ...@@ -929,6 +1047,7 @@ static int phy_BCM5400_link_table[8][3] = {
{ 1, 0, 1 }, /* 1000BT */ { 1, 0, 1 }, /* 1000BT */
}; };
/* Must be invoked under gp->lock. */
static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
{ {
u16 ctl; u16 ctl;
...@@ -954,11 +1073,8 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) ...@@ -954,11 +1073,8 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
} }
start_aneg: start_aneg:
spin_lock_irq(&gp->lock); if (!gp->hw_running)
if (!gp->hw_running) {
spin_unlock_irq(&gp->lock);
return; return;
}
/* Configure PHY & start aneg */ /* Configure PHY & start aneg */
ctl = phy_read(gp, MII_BMCR); ctl = phy_read(gp, MII_BMCR);
...@@ -973,11 +1089,10 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) ...@@ -973,11 +1089,10 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
phy_write(gp, MII_BMCR, ctl); phy_write(gp, MII_BMCR, ctl);
gp->timer_ticks = 0; gp->timer_ticks = 0;
gp->link_timer.expires = jiffies + ((12 * HZ) / 10); mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
add_timer(&gp->link_timer);
spin_unlock_irq(&gp->lock);
} }
/* Must be invoked under gp->lock. */
static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause) static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
{ {
u32 val; u32 val;
...@@ -1021,6 +1136,8 @@ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause ...@@ -1021,6 +1136,8 @@ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause
/* A link-up condition has occurred, initialize and enable the /* A link-up condition has occurred, initialize and enable the
* rest of the chip. * rest of the chip.
*
* Must be invoked under gp->lock.
*/ */
static void gem_set_link_modes(struct gem *gp) static void gem_set_link_modes(struct gem *gp)
{ {
...@@ -1101,6 +1218,20 @@ static void gem_set_link_modes(struct gem *gp) ...@@ -1101,6 +1218,20 @@ static void gem_set_link_modes(struct gem *gp)
pause = 1; pause = 1;
} }
if (netif_msg_link(gp)) {
if (pause) {
printk(KERN_INFO "%s: Pause is enabled "
"(rxfifo: %d off: %d on: %d)\n",
gp->dev->name,
gp->rx_fifo_sz,
gp->rx_pause_off,
gp->rx_pause_on);
} else {
printk(KERN_INFO "%s: Pause is disabled\n",
gp->dev->name);
}
}
if (!full_duplex) if (!full_duplex)
writel(512, gp->regs + MAC_STIME); writel(512, gp->regs + MAC_STIME);
else else
...@@ -1115,6 +1246,7 @@ static void gem_set_link_modes(struct gem *gp) ...@@ -1115,6 +1246,7 @@ static void gem_set_link_modes(struct gem *gp)
gem_start_dma(gp); gem_start_dma(gp);
} }
/* Must be invoked under gp->lock. */
static int gem_mdio_link_not_up(struct gem *gp) static int gem_mdio_link_not_up(struct gem *gp)
{ {
u16 val; u16 val;
...@@ -1158,7 +1290,7 @@ static int gem_mdio_link_not_up(struct gem *gp) ...@@ -1158,7 +1290,7 @@ static int gem_mdio_link_not_up(struct gem *gp)
return 0; return 0;
} }
static void gem_init_rings(struct gem *, int); static void gem_init_rings(struct gem *);
static void gem_init_hw(struct gem *, int); static void gem_init_hw(struct gem *, int);
static void gem_reset_task(void *data) static void gem_reset_task(void *data)
...@@ -1169,24 +1301,27 @@ static void gem_reset_task(void *data) ...@@ -1169,24 +1301,27 @@ static void gem_reset_task(void *data)
* DMA stopped. Todo: Use this function for reset * DMA stopped. Todo: Use this function for reset
* on error as well. * on error as well.
*/ */
spin_lock_irq(&gp->lock);
if (gp->hw_running && gp->opened) { if (gp->hw_running && gp->opened) {
/* Make sure we don't get interrupts or tx packets */ /* Make sure we don't get interrupts or tx packets */
spin_lock_irq(&gp->lock);
netif_stop_queue(gp->dev); netif_stop_queue(gp->dev);
writel(0xffffffff, gp->regs + GREG_IMASK); writel(0xffffffff, gp->regs + GREG_IMASK);
spin_unlock_irq(&gp->lock);
/* Reset the chip & rings */ /* Reset the chip & rings */
gem_stop(gp); gem_stop(gp);
gem_init_rings(gp, 0); gem_init_rings(gp);
gem_init_hw(gp, 0);
gem_init_hw(gp,
(gp->reset_task_pending == 2));
netif_wake_queue(gp->dev); netif_wake_queue(gp->dev);
} }
gp->reset_task_pending = 0; gp->reset_task_pending = 0;
spin_unlock_irq(&gp->lock);
} }
static void gem_link_timer(unsigned long data) static void gem_link_timer(unsigned long data)
...@@ -1196,13 +1331,14 @@ static void gem_link_timer(unsigned long data) ...@@ -1196,13 +1331,14 @@ static void gem_link_timer(unsigned long data)
if (!gp->hw_running) if (!gp->hw_running)
return; return;
spin_lock_irq(&gp->lock);
/* If the link of task is still pending, we just /* If the link of task is still pending, we just
* reschedule the link timer * reschedule the link timer
*/ */
if (gp->reset_task_pending) if (gp->reset_task_pending)
goto restart; goto restart;
spin_lock_irq(&gp->lock);
if (gp->phy_type == phy_mii_mdio0 || if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) { gp->phy_type == phy_mii_mdio1) {
u16 val = phy_read(gp, MII_BMSR); u16 val = phy_read(gp, MII_BMSR);
...@@ -1247,16 +1383,15 @@ static void gem_link_timer(unsigned long data) ...@@ -1247,16 +1383,15 @@ static void gem_link_timer(unsigned long data)
if (netif_msg_link(gp)) if (netif_msg_link(gp))
printk(KERN_INFO "%s: Link down\n", printk(KERN_INFO "%s: Link down\n",
gp->dev->name); gp->dev->name);
gp->reset_task_pending = 1; gp->reset_task_pending = 2;
schedule_task(&gp->reset_task); schedule_task(&gp->reset_task);
restart = 1; restart = 1;
} else if (++gp->timer_ticks > 10) } else if (++gp->timer_ticks > 10)
restart = gem_mdio_link_not_up(gp); restart = gem_mdio_link_not_up(gp);
if (restart) { if (restart) {
spin_unlock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL); gem_begin_auto_negotiation(gp, NULL);
return; goto out_unlock;
} }
} }
} else { } else {
...@@ -1273,11 +1408,12 @@ static void gem_link_timer(unsigned long data) ...@@ -1273,11 +1408,12 @@ static void gem_link_timer(unsigned long data)
} }
restart: restart:
gp->link_timer.expires = jiffies + ((12 * HZ) / 10); mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
add_timer(&gp->link_timer); out_unlock:
spin_unlock_irq(&gp->lock); spin_unlock_irq(&gp->lock);
} }
/* Must be invoked under gp->lock. */
static void gem_clean_rings(struct gem *gp) static void gem_clean_rings(struct gem *gp)
{ {
struct gem_init_block *gb = gp->init_block; struct gem_init_block *gb = gp->init_block;
...@@ -1311,7 +1447,9 @@ static void gem_clean_rings(struct gem *gp) ...@@ -1311,7 +1447,9 @@ static void gem_clean_rings(struct gem *gp)
gp->tx_skbs[i] = NULL; gp->tx_skbs[i] = NULL;
for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
txd = &gb->txd[i]; int ent = i & (TX_RING_SIZE - 1);
txd = &gb->txd[ent];
dma_addr = le64_to_cpu(txd->buffer); dma_addr = le64_to_cpu(txd->buffer);
pci_unmap_page(gp->pdev, dma_addr, pci_unmap_page(gp->pdev, dma_addr,
le64_to_cpu(txd->control_word) & le64_to_cpu(txd->control_word) &
...@@ -1325,16 +1463,14 @@ static void gem_clean_rings(struct gem *gp) ...@@ -1325,16 +1463,14 @@ static void gem_clean_rings(struct gem *gp)
} }
} }
static void gem_init_rings(struct gem *gp, int from_irq) /* Must be invoked under gp->lock. */
static void gem_init_rings(struct gem *gp)
{ {
struct gem_init_block *gb = gp->init_block; struct gem_init_block *gb = gp->init_block;
struct net_device *dev = gp->dev; struct net_device *dev = gp->dev;
int i, gfp_flags = GFP_KERNEL; int i;
dma_addr_t dma_addr; dma_addr_t dma_addr;
if (from_irq)
gfp_flags = GFP_ATOMIC;
gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0; gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0;
gem_clean_rings(gp); gem_clean_rings(gp);
...@@ -1343,7 +1479,7 @@ static void gem_init_rings(struct gem *gp, int from_irq) ...@@ -1343,7 +1479,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
struct sk_buff *skb; struct sk_buff *skb;
struct gem_rxd *rxd = &gb->rxd[i]; struct gem_rxd *rxd = &gb->rxd[i];
skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags); skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
if (!skb) { if (!skb) {
rxd->buffer = 0; rxd->buffer = 0;
rxd->status_word = 0; rxd->status_word = 0;
...@@ -1372,6 +1508,7 @@ static void gem_init_rings(struct gem *gp, int from_irq) ...@@ -1372,6 +1508,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
} }
} }
/* Must be invoked under gp->lock. */
static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
{ {
u16 val; u16 val;
...@@ -1396,6 +1533,7 @@ static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr) ...@@ -1396,6 +1533,7 @@ static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
return (limit <= 0); return (limit <= 0);
} }
/* Must be invoked under gp->lock. */
static void gem_init_bcm5201_phy(struct gem *gp) static void gem_init_bcm5201_phy(struct gem *gp)
{ {
u16 data; u16 data;
...@@ -1405,6 +1543,7 @@ static void gem_init_bcm5201_phy(struct gem *gp) ...@@ -1405,6 +1543,7 @@ static void gem_init_bcm5201_phy(struct gem *gp)
phy_write(gp, MII_BCM5201_MULTIPHY, data); phy_write(gp, MII_BCM5201_MULTIPHY, data);
} }
/* Must be invoked under gp->lock. */
static void gem_init_bcm5400_phy(struct gem *gp) static void gem_init_bcm5400_phy(struct gem *gp)
{ {
u16 data; u16 data;
...@@ -1432,6 +1571,7 @@ static void gem_init_bcm5400_phy(struct gem *gp) ...@@ -1432,6 +1571,7 @@ static void gem_init_bcm5400_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_AUXCONTROL, data); phy_write(gp, MII_BCM5400_AUXCONTROL, data);
} }
/* Must be invoked under gp->lock. */
static void gem_init_bcm5401_phy(struct gem *gp) static void gem_init_bcm5401_phy(struct gem *gp)
{ {
u16 data; u16 data;
...@@ -1446,6 +1586,9 @@ static void gem_init_bcm5401_phy(struct gem *gp) ...@@ -1446,6 +1586,9 @@ static void gem_init_bcm5401_phy(struct gem *gp)
* WARNING ! OF and Darwin don't agree on the * WARNING ! OF and Darwin don't agree on the
* register addresses. OF seem to interpret the * register addresses. OF seem to interpret the
* register numbers below as decimal * register numbers below as decimal
*
* Note: This should (and does) match tg3_init_5401phy_dsp
* in the tg3.c driver. -DaveM
*/ */
phy_write(gp, 0x18, 0x0c20); phy_write(gp, 0x18, 0x0c20);
phy_write(gp, 0x17, 0x0012); phy_write(gp, 0x17, 0x0012);
...@@ -1475,6 +1618,7 @@ static void gem_init_bcm5401_phy(struct gem *gp) ...@@ -1475,6 +1618,7 @@ static void gem_init_bcm5401_phy(struct gem *gp)
__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f); __phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
} }
/* Must be invoked under gp->lock. */
static void gem_init_bcm5411_phy(struct gem *gp) static void gem_init_bcm5411_phy(struct gem *gp)
{ {
u16 data; u16 data;
...@@ -1501,6 +1645,7 @@ static void gem_init_bcm5411_phy(struct gem *gp) ...@@ -1501,6 +1645,7 @@ static void gem_init_bcm5411_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_GB_CONTROL, data); phy_write(gp, MII_BCM5400_GB_CONTROL, data);
} }
/* Must be invoked under gp->lock. */
static void gem_init_phy(struct gem *gp) static void gem_init_phy(struct gem *gp)
{ {
u32 mifcfg; u32 mifcfg;
...@@ -1649,7 +1794,9 @@ static void gem_init_phy(struct gem *gp) ...@@ -1649,7 +1794,9 @@ static void gem_init_phy(struct gem *gp)
val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
writel(val, gp->regs + PCS_CFG); writel(val, gp->regs + PCS_CFG);
/* Advertise all capabilities. */ /* Advertise all capabilities except assymetric
* pause.
*/
val = readl(gp->regs + PCS_MIIADV); val = readl(gp->regs + PCS_MIIADV);
val |= (PCS_MIIADV_FD | PCS_MIIADV_HD | val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
PCS_MIIADV_SP | PCS_MIIADV_AP); PCS_MIIADV_SP | PCS_MIIADV_AP);
...@@ -1684,9 +1831,9 @@ static void gem_init_phy(struct gem *gp) ...@@ -1684,9 +1831,9 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 && if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
gp->phy_mod != phymod_bcm5411) gp->phy_mod != phymod_bcm5411)
gp->link_cntl &= ~BMCR_SPD2; gp->link_cntl &= ~BMCR_SPD2;
} }
/* Must be invoked under gp->lock. */
static void gem_init_dma(struct gem *gp) static void gem_init_dma(struct gem *gp)
{ {
u64 desc_dma = (u64) gp->gblock_dvma; u64 desc_dma = (u64) gp->gblock_dvma;
...@@ -1702,7 +1849,7 @@ static void gem_init_dma(struct gem *gp) ...@@ -1702,7 +1849,7 @@ static void gem_init_dma(struct gem *gp)
writel(0, gp->regs + TXDMA_KICK); writel(0, gp->regs + TXDMA_KICK);
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512); ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
writel(val, gp->regs + RXDMA_CFG); writel(val, gp->regs + RXDMA_CFG);
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
...@@ -1724,6 +1871,7 @@ static void gem_init_dma(struct gem *gp) ...@@ -1724,6 +1871,7 @@ static void gem_init_dma(struct gem *gp)
gp->regs + RXDMA_BLANK); gp->regs + RXDMA_BLANK);
} }
/* Must be invoked under gp->lock. */
static u32 static u32
gem_setup_multicast(struct gem *gp) gem_setup_multicast(struct gem *gp)
{ {
...@@ -1766,10 +1914,10 @@ gem_setup_multicast(struct gem *gp) ...@@ -1766,10 +1914,10 @@ gem_setup_multicast(struct gem *gp)
return rxcfg; return rxcfg;
} }
/* Must be invoked under gp->lock. */
static void gem_init_mac(struct gem *gp) static void gem_init_mac(struct gem *gp)
{ {
unsigned char *e = &gp->dev->dev_addr[0]; unsigned char *e = &gp->dev->dev_addr[0];
u32 rxcfg;
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) gp->pdev->device == PCI_DEVICE_ID_SUN_GEM)
...@@ -1780,7 +1928,10 @@ static void gem_init_mac(struct gem *gp) ...@@ -1780,7 +1928,10 @@ static void gem_init_mac(struct gem *gp)
writel(0x04, gp->regs + MAC_IPG2); writel(0x04, gp->regs + MAC_IPG2);
writel(0x40, gp->regs + MAC_STIME); writel(0x40, gp->regs + MAC_STIME);
writel(0x40, gp->regs + MAC_MINFSZ); writel(0x40, gp->regs + MAC_MINFSZ);
writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ);
/* Ethernet payload + header + FCS + optional VLAN tag. */
writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ);
writel(0x07, gp->regs + MAC_PASIZE); writel(0x07, gp->regs + MAC_PASIZE);
writel(0x04, gp->regs + MAC_JAMSIZE); writel(0x04, gp->regs + MAC_JAMSIZE);
writel(0x10, gp->regs + MAC_ATTLIM); writel(0x10, gp->regs + MAC_ATTLIM);
...@@ -1806,7 +1957,7 @@ static void gem_init_mac(struct gem *gp) ...@@ -1806,7 +1957,7 @@ static void gem_init_mac(struct gem *gp)
writel(0, gp->regs + MAC_AF21MSK); writel(0, gp->regs + MAC_AF21MSK);
writel(0, gp->regs + MAC_AF0MSK); writel(0, gp->regs + MAC_AF0MSK);
rxcfg = gem_setup_multicast(gp); gp->mac_rx_cfg = gem_setup_multicast(gp);
writel(0, gp->regs + MAC_NCOLL); writel(0, gp->regs + MAC_NCOLL);
writel(0, gp->regs + MAC_FASUCC); writel(0, gp->regs + MAC_FASUCC);
...@@ -1824,7 +1975,7 @@ static void gem_init_mac(struct gem *gp) ...@@ -1824,7 +1975,7 @@ static void gem_init_mac(struct gem *gp)
* them once a link is established. * them once a link is established.
*/ */
writel(0, gp->regs + MAC_TXCFG); writel(0, gp->regs + MAC_TXCFG);
writel(rxcfg, gp->regs + MAC_RXCFG); writel(gp->mac_rx_cfg, gp->regs + MAC_RXCFG);
writel(0, gp->regs + MAC_MCCFG); writel(0, gp->regs + MAC_MCCFG);
writel(0, gp->regs + MAC_XIFCFG); writel(0, gp->regs + MAC_XIFCFG);
...@@ -1841,6 +1992,7 @@ static void gem_init_mac(struct gem *gp) ...@@ -1841,6 +1992,7 @@ static void gem_init_mac(struct gem *gp)
writel(0xffffffff, gp->regs + MAC_MCMASK); writel(0xffffffff, gp->regs + MAC_MCMASK);
} }
/* Must be invoked under gp->lock. */
static void gem_init_pause_thresholds(struct gem *gp) static void gem_init_pause_thresholds(struct gem *gp)
{ {
/* Calculate pause thresholds. Setting the OFF threshold to the /* Calculate pause thresholds. Setting the OFF threshold to the
...@@ -1851,8 +2003,9 @@ static void gem_init_pause_thresholds(struct gem *gp) ...@@ -1851,8 +2003,9 @@ static void gem_init_pause_thresholds(struct gem *gp)
if (gp->rx_fifo_sz <= (2 * 1024)) { if (gp->rx_fifo_sz <= (2 * 1024)) {
gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
} else { } else {
int off = (gp->rx_fifo_sz - (5 * 1024)); int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
int on = off - 1024; int off = (gp->rx_fifo_sz - (max_frame * 2));
int on = off - max_frame;
gp->rx_pause_off = off; gp->rx_pause_off = off;
gp->rx_pause_on = on; gp->rx_pause_on = on;
...@@ -1861,7 +2014,10 @@ static void gem_init_pause_thresholds(struct gem *gp) ...@@ -1861,7 +2014,10 @@ static void gem_init_pause_thresholds(struct gem *gp)
{ {
u32 cfg; u32 cfg;
cfg = GREG_CFG_IBURST; cfg = 0;
#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
cfg |= GREG_CFG_IBURST;
#endif
cfg |= ((31 << 1) & GREG_CFG_TXDMALIM); cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
cfg |= ((31 << 6) & GREG_CFG_RXDMALIM); cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
writel(cfg, gp->regs + GREG_CFG); writel(cfg, gp->regs + GREG_CFG);
...@@ -1881,6 +2037,7 @@ static int gem_check_invariants(struct gem *gp) ...@@ -1881,6 +2037,7 @@ static int gem_check_invariants(struct gem *gp)
gp->phy_type = phy_mii_mdio0; gp->phy_type = phy_mii_mdio0;
gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
gp->swrst_base = 0;
return 0; return 0;
} }
...@@ -1943,6 +2100,7 @@ static int gem_check_invariants(struct gem *gp) ...@@ -1943,6 +2100,7 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz); gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1; return -1;
} }
gp->swrst_base = 0;
} else { } else {
if (gp->tx_fifo_sz != (2 * 1024) || if (gp->tx_fifo_sz != (2 * 1024) ||
gp->rx_fifo_sz != (2 * 1024)) { gp->rx_fifo_sz != (2 * 1024)) {
...@@ -1950,12 +2108,14 @@ static int gem_check_invariants(struct gem *gp) ...@@ -1950,12 +2108,14 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz); gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1; return -1;
} }
gp->swrst_base = (64 / 4) << GREG_SWRST_CACHE_SHIFT;
} }
} }
return 0; return 0;
} }
/* Must be invoked under gp->lock. */
static void gem_init_hw(struct gem *gp, int restart_link) static void gem_init_hw(struct gem *gp, int restart_link)
{ {
/* On Apple's gmac, I initialize the PHY only after /* On Apple's gmac, I initialize the PHY only after
...@@ -1970,21 +2130,16 @@ static void gem_init_hw(struct gem *gp, int restart_link) ...@@ -1970,21 +2130,16 @@ static void gem_init_hw(struct gem *gp, int restart_link)
gem_init_mac(gp); gem_init_mac(gp);
gem_init_pause_thresholds(gp); gem_init_pause_thresholds(gp);
spin_lock_irq(&gp->lock);
if (restart_link) { if (restart_link) {
/* Default aneg parameters */ /* Default aneg parameters */
gp->timer_ticks = 0; gp->timer_ticks = 0;
gp->lstate = link_down; gp->lstate = link_down;
spin_unlock_irq(&gp->lock);
/* Can I advertise gigabit here ? I'd need BCM PHY docs... */ /* Can I advertise gigabit here ? I'd need BCM PHY docs... */
gem_begin_auto_negotiation(gp, NULL); gem_begin_auto_negotiation(gp, NULL);
} else { } else {
if (gp->lstate == link_up) if (gp->lstate == link_up)
gem_set_link_modes(gp); gem_set_link_modes(gp);
spin_unlock_irq(&gp->lock);
} }
} }
...@@ -2029,6 +2184,7 @@ static void gem_apple_powerdown(struct gem *gp) ...@@ -2029,6 +2184,7 @@ static void gem_apple_powerdown(struct gem *gp)
#endif /* CONFIG_ALL_PPC */ #endif /* CONFIG_ALL_PPC */
/* Must be invoked under gp->lock. */
static void gem_stop_phy(struct gem *gp) static void gem_stop_phy(struct gem *gp)
{ {
u32 mifcfg; u32 mifcfg;
...@@ -2100,14 +2256,21 @@ static void gem_shutdown(struct gem *gp) ...@@ -2100,14 +2256,21 @@ static void gem_shutdown(struct gem *gp)
schedule(); schedule();
/* Actually stop the chip */ /* Actually stop the chip */
spin_lock_irq(&gp->lock);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
gem_stop_phy(gp); gem_stop_phy(gp);
spin_unlock_irq(&gp->lock);
#ifdef CONFIG_ALL_PPC #ifdef CONFIG_ALL_PPC
/* Power down the chip */ /* Power down the chip */
gem_apple_powerdown(gp); gem_apple_powerdown(gp);
#endif /* CONFIG_ALL_PPC */ #endif /* CONFIG_ALL_PPC */
} else } else {
gem_stop(gp); gem_stop(gp);
spin_unlock_irq(&gp->lock);
}
} }
static void gem_pm_task(void *data) static void gem_pm_task(void *data)
...@@ -2142,14 +2305,19 @@ static void gem_pm_timer(unsigned long data) ...@@ -2142,14 +2305,19 @@ static void gem_pm_timer(unsigned long data)
static int gem_open(struct net_device *dev) static int gem_open(struct net_device *dev)
{ {
struct gem *gp = dev->priv; struct gem *gp = dev->priv;
int hw_was_up = gp->hw_running; int hw_was_up;
down(&gp->pm_sem); down(&gp->pm_sem);
hw_was_up = gp->hw_running;
/* Stop the PM timer/task */ /* Stop the PM timer/task */
del_timer(&gp->pm_timer); del_timer(&gp->pm_timer);
flush_scheduled_tasks(); flush_scheduled_tasks();
/* The power-management semaphore protects the hw_running
* etc. state so it is safe to do this bit without gp->lock
*/
if (!gp->hw_running) { if (!gp->hw_running) {
#ifdef CONFIG_ALL_PPC #ifdef CONFIG_ALL_PPC
/* First, we need to bring up the chip */ /* First, we need to bring up the chip */
...@@ -2158,18 +2326,26 @@ static int gem_open(struct net_device *dev) ...@@ -2158,18 +2326,26 @@ static int gem_open(struct net_device *dev)
gem_check_invariants(gp); gem_check_invariants(gp);
} }
#endif /* CONFIG_ALL_PPC */ #endif /* CONFIG_ALL_PPC */
/* Reset the chip */ /* Reset the chip */
spin_lock_irq(&gp->lock);
gem_stop(gp); gem_stop(gp);
spin_unlock_irq(&gp->lock);
gp->hw_running = 1; gp->hw_running = 1;
} }
spin_lock_irq(&gp->lock);
/* We can now request the interrupt as we know it's masked /* We can now request the interrupt as we know it's masked
* on the controller * on the controller
*/ */
if (request_irq(gp->pdev->irq, gem_interrupt, if (request_irq(gp->pdev->irq, gem_interrupt,
SA_SHIRQ, dev->name, (void *)dev)) { SA_SHIRQ, dev->name, (void *)dev)) {
spin_unlock_irq(&gp->lock);
printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
#ifdef CONFIG_ALL_PPC #ifdef CONFIG_ALL_PPC
if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerdown(gp); gem_apple_powerdown(gp);
...@@ -2183,13 +2359,15 @@ static int gem_open(struct net_device *dev) ...@@ -2183,13 +2359,15 @@ static int gem_open(struct net_device *dev)
} }
/* Allocate & setup ring buffers */ /* Allocate & setup ring buffers */
gem_init_rings(gp, 0); gem_init_rings(gp);
/* Init & setup chip hardware */ /* Init & setup chip hardware */
gem_init_hw(gp, !hw_was_up); gem_init_hw(gp, !hw_was_up);
gp->opened = 1; gp->opened = 1;
spin_unlock_irq(&gp->lock);
up(&gp->pm_sem); up(&gp->pm_sem);
return 0; return 0;
...@@ -2209,8 +2387,6 @@ static int gem_close(struct net_device *dev) ...@@ -2209,8 +2387,6 @@ static int gem_close(struct net_device *dev)
writel(0xffffffff, gp->regs + GREG_IMASK); writel(0xffffffff, gp->regs + GREG_IMASK);
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irq(&gp->lock);
/* Stop chip */ /* Stop chip */
gem_stop(gp); gem_stop(gp);
...@@ -2220,6 +2396,8 @@ static int gem_close(struct net_device *dev) ...@@ -2220,6 +2396,8 @@ static int gem_close(struct net_device *dev)
/* Bye, the pm timer will finish the job */ /* Bye, the pm timer will finish the job */
free_irq(gp->pdev->irq, (void *) dev); free_irq(gp->pdev->irq, (void *) dev);
spin_unlock_irq(&gp->lock);
/* Fire the PM timer that will shut us down in about 10 seconds */ /* Fire the PM timer that will shut us down in about 10 seconds */
gp->pm_timer.expires = jiffies + 10*HZ; gp->pm_timer.expires = jiffies + 10*HZ;
add_timer(&gp->pm_timer); add_timer(&gp->pm_timer);
...@@ -2245,21 +2423,21 @@ static int gem_suspend(struct pci_dev *pdev, u32 state) ...@@ -2245,21 +2423,21 @@ static int gem_suspend(struct pci_dev *pdev, u32 state)
/* If the driver is opened, we stop the DMA */ /* If the driver is opened, we stop the DMA */
if (gp->opened) { if (gp->opened) {
spin_lock_irq(&gp->lock);
/* Stop traffic, mark us closed */ /* Stop traffic, mark us closed */
netif_device_detach(dev); netif_device_detach(dev);
spin_lock_irq(&gp->lock);
writel(0xffffffff, gp->regs + GREG_IMASK); writel(0xffffffff, gp->regs + GREG_IMASK);
spin_unlock_irq(&gp->lock);
/* Stop chip */ /* Stop chip */
gem_stop(gp); gem_stop(gp);
/* Get rid of ring buffers */ /* Get rid of ring buffers */
gem_clean_rings(gp); gem_clean_rings(gp);
spin_unlock_irq(&gp->lock);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
disable_irq(gp->pdev->irq); disable_irq(gp->pdev->irq);
} }
...@@ -2290,10 +2468,15 @@ static int gem_resume(struct pci_dev *pdev) ...@@ -2290,10 +2468,15 @@ static int gem_resume(struct pci_dev *pdev)
gem_check_invariants(gp); gem_check_invariants(gp);
} }
#endif /* CONFIG_ALL_PPC */ #endif /* CONFIG_ALL_PPC */
spin_lock_irq(&gp->lock);
gem_stop(gp); gem_stop(gp);
gp->hw_running = 1; gp->hw_running = 1;
gem_init_rings(gp, 0); gem_init_rings(gp);
gem_init_hw(gp, 1); gem_init_hw(gp, 1);
spin_unlock_irq(&gp->lock);
netif_device_attach(dev); netif_device_attach(dev);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
enable_irq(gp->pdev->irq); enable_irq(gp->pdev->irq);
...@@ -2309,6 +2492,8 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) ...@@ -2309,6 +2492,8 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
struct gem *gp = dev->priv; struct gem *gp = dev->priv;
struct net_device_stats *stats = &gp->net_stats; struct net_device_stats *stats = &gp->net_stats;
spin_lock_irq(&gp->lock);
if (gp->hw_running) { if (gp->hw_running) {
stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
writel(0, gp->regs + MAC_FCSERR); writel(0, gp->regs + MAC_FCSERR);
...@@ -2326,6 +2511,9 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) ...@@ -2326,6 +2511,9 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
writel(0, gp->regs + MAC_ECOLL); writel(0, gp->regs + MAC_ECOLL);
writel(0, gp->regs + MAC_LCOLL); writel(0, gp->regs + MAC_LCOLL);
} }
spin_unlock_irq(&gp->lock);
return &gp->net_stats; return &gp->net_stats;
} }
...@@ -2338,10 +2526,12 @@ static void gem_set_multicast(struct net_device *dev) ...@@ -2338,10 +2526,12 @@ static void gem_set_multicast(struct net_device *dev)
if (!gp->hw_running) if (!gp->hw_running)
return; return;
spin_lock_irq(&gp->lock);
netif_stop_queue(dev); netif_stop_queue(dev);
rxcfg = readl(gp->regs + MAC_RXCFG); rxcfg = readl(gp->regs + MAC_RXCFG);
rxcfg_new = gem_setup_multicast(gp); gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp);
writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
...@@ -2355,8 +2545,9 @@ static void gem_set_multicast(struct net_device *dev) ...@@ -2355,8 +2545,9 @@ static void gem_set_multicast(struct net_device *dev)
writel(rxcfg, gp->regs + MAC_RXCFG); writel(rxcfg, gp->regs + MAC_RXCFG);
/* Hrm... we may walk on the reset task here... */
netif_wake_queue(dev); netif_wake_queue(dev);
spin_unlock_irq(&gp->lock);
} }
/* Eventually add support for changing the advertisement /* Eventually add support for changing the advertisement
...@@ -2405,11 +2596,13 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user) ...@@ -2405,11 +2596,13 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.phy_address = 0; /* XXX fixed PHYAD */ ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings if HW is on. */ /* Record PHY settings if HW is on. */
spin_lock_irq(&gp->lock);
if (gp->hw_running) { if (gp->hw_running) {
bmcr = phy_read(gp, MII_BMCR); bmcr = phy_read(gp, MII_BMCR);
gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause); gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
} else } else
bmcr = 0; bmcr = 0;
spin_unlock_irq(&gp->lock);
if (bmcr & BMCR_ANENABLE) { if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE; ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100); ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
...@@ -2443,18 +2636,22 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user) ...@@ -2443,18 +2636,22 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.duplex != DUPLEX_FULL))) ecmd.duplex != DUPLEX_FULL)))
return -EINVAL; return -EINVAL;
/* Apply settings and restart link process */ /* Apply settings and restart link process. */
if (gp->hw_running) spin_lock_irq(&gp->lock);
del_timer(&gp->link_timer);
gem_begin_auto_negotiation(gp, &ecmd); gem_begin_auto_negotiation(gp, &ecmd);
spin_unlock_irq(&gp->lock);
return 0; return 0;
case ETHTOOL_NWAY_RST: case ETHTOOL_NWAY_RST:
if ((gp->link_cntl & BMCR_ANENABLE) == 0) if ((gp->link_cntl & BMCR_ANENABLE) == 0)
return -EINVAL; return -EINVAL;
if (gp->hw_running)
del_timer(&gp->link_timer); /* Restart link process. */
spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL); gem_begin_auto_negotiation(gp, NULL);
spin_unlock_irq(&gp->lock);
return 0; return 0;
case ETHTOOL_GWOL: case ETHTOOL_GWOL:
...@@ -2602,8 +2799,10 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) ...@@ -2602,8 +2799,10 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
u32 rom_reg_orig; u32 rom_reg_orig;
void *p; void *p;
if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
pci_assign_resource(pdev, PCI_ROM_RESOURCE); if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
goto use_random;
}
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
pci_write_config_dword(pdev, pdev->rom_base_reg, pci_write_config_dword(pdev, pdev->rom_base_reg,
...@@ -2617,6 +2816,15 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) ...@@ -2617,6 +2816,15 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
iounmap(p); iounmap(p);
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
return;
use_random:
/* Sun MAC prefix then 3 random bytes. */
dev_addr[0] = 0x08;
dev_addr[1] = 0x00;
dev_addr[2] = 0x20;
get_random_bytes(dev_addr, 3);
return;
} }
#endif /* not Sparc and not PPC */ #endif /* not Sparc and not PPC */
...@@ -2773,12 +2981,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev, ...@@ -2773,12 +2981,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_APPLE) if (pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerup(gp); gem_apple_powerup(gp);
#endif #endif
spin_lock_irq(&gp->lock);
gem_stop(gp); gem_stop(gp);
spin_unlock_irq(&gp->lock);
if (gem_check_invariants(gp)) if (gem_check_invariants(gp))
goto err_out_iounmap; goto err_out_iounmap;
spin_lock_irq(&gp->lock);
gp->hw_running = 1; gp->hw_running = 1;
gem_init_phy(gp); gem_init_phy(gp);
gem_begin_auto_negotiation(gp, NULL); gem_begin_auto_negotiation(gp, NULL);
spin_unlock_irq(&gp->lock);
/* It is guarenteed that the returned buffer will be at least /* It is guarenteed that the returned buffer will be at least
* PAGE_SIZE aligned. * PAGE_SIZE aligned.
......
...@@ -94,6 +94,8 @@ ...@@ -94,6 +94,8 @@
#define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */ #define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */
#define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */ #define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */
#define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */ #define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */
#define GREG_SWRST_CACHESIZE 0x00ff0000 /* RIO only: cache line size */
#define GREG_SWRST_CACHE_SHIFT 16
/* TX DMA Registers */ /* TX DMA Registers */
#define TXDMA_KICK 0x2000UL /* TX Kick Register */ #define TXDMA_KICK 0x2000UL /* TX Kick Register */
...@@ -986,6 +988,9 @@ struct gem { ...@@ -986,6 +988,9 @@ struct gem {
int mii_phy_addr; int mii_phy_addr;
int gigabit_capable; int gigabit_capable;
u32 mac_rx_cfg;
u32 swrst_base;
/* Autoneg & PHY control */ /* Autoneg & PHY control */
int link_cntl; int link_cntl;
int link_advertise; int link_advertise;
......
...@@ -34,6 +34,7 @@ static char version[] = ...@@ -34,6 +34,7 @@ static char version[] =
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/random.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -2929,8 +2930,10 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) ...@@ -2929,8 +2930,10 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
if (is_quattro_p(pdev)) if (is_quattro_p(pdev))
index = PCI_SLOT(pdev->devfn); index = PCI_SLOT(pdev->devfn);
if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
pci_assign_resource(pdev, PCI_ROM_RESOURCE); if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
goto use_random;
}
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
pci_write_config_dword(pdev, pdev->rom_base_reg, pci_write_config_dword(pdev, pdev->rom_base_reg,
...@@ -2944,6 +2947,15 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) ...@@ -2944,6 +2947,15 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
iounmap(p); iounmap(p);
pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
return;
use_random:
/* Sun MAC prefix then 3 random bytes. */
dev_addr[0] = 0x08;
dev_addr[1] = 0x00;
dev_addr[2] = 0x20;
get_random_bytes(dev_addr, 3);
return;
} }
#endif /* !(__sparc__) */ #endif /* !(__sparc__) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment