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

SunHME driver updates:

- Fix SMP locking throughout
- Deal with hw bug involving lost writes to rxring base address
- Disable Never Give Up mode on transmitter, set TX attempts
  limit to 16 (the default).  This deals with a possible hang
  when the TX deadlocks with the PHY when a jabber occurs.
- Delete some dead code.
parent 332f3f1d
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
*/ */
static char version[] = static char version[] =
"sunhme.c:v2.00 20/Mar/2002 David S. Miller (davem@redhat.com)\n"; "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
#include <linux/module.h> #include <linux/module.h>
...@@ -697,7 +697,7 @@ static int set_happy_link_modes(struct happy_meal *hp, unsigned long tregs) ...@@ -697,7 +697,7 @@ static int set_happy_link_modes(struct happy_meal *hp, unsigned long tregs)
return 1; return 1;
} }
static int happy_meal_init(struct happy_meal *hp, int from_irq); static int happy_meal_init(struct happy_meal *hp);
static int is_lucent_phy(struct happy_meal *hp) static int is_lucent_phy(struct happy_meal *hp)
{ {
...@@ -708,12 +708,8 @@ static int is_lucent_phy(struct happy_meal *hp) ...@@ -708,12 +708,8 @@ static int is_lucent_phy(struct happy_meal *hp)
mr2 = happy_meal_tcvr_read(hp, tregs, 2); mr2 = happy_meal_tcvr_read(hp, tregs, 2);
mr3 = happy_meal_tcvr_read(hp, tregs, 3); mr3 = happy_meal_tcvr_read(hp, tregs, 3);
if ((mr2 & 0xffff) == 0x0180 && if ((mr2 & 0xffff) == 0x0180 &&
((mr3 & 0xffff) >> 10) == 0x1d) { ((mr3 & 0xffff) >> 10) == 0x1d)
#if 0
printk("HMEDEBUG: Lucent PHY detected.\n");
#endif
ret = 1; ret = 1;
}
return ret; return ret;
} }
...@@ -724,6 +720,8 @@ static void happy_meal_timer(unsigned long data) ...@@ -724,6 +720,8 @@ static void happy_meal_timer(unsigned long data)
unsigned long tregs = hp->tcvregs; unsigned long tregs = hp->tcvregs;
int restart_timer = 0; int restart_timer = 0;
spin_lock_irq(&hp->happy_lock);
hp->timer_ticks++; hp->timer_ticks++;
switch(hp->timer_state) { switch(hp->timer_state) {
case arbwait: case arbwait:
...@@ -853,13 +851,13 @@ static void happy_meal_timer(unsigned long data) ...@@ -853,13 +851,13 @@ static void happy_meal_timer(unsigned long data)
printk(KERN_NOTICE "%s: Link down, cable problem?\n", printk(KERN_NOTICE "%s: Link down, cable problem?\n",
hp->dev->name); hp->dev->name);
ret = happy_meal_init(hp, 0); ret = happy_meal_init(hp);
if (ret) { if (ret) {
/* ho hum... */ /* ho hum... */
printk(KERN_ERR "%s: Error, cannot re-init the " printk(KERN_ERR "%s: Error, cannot re-init the "
"Happy Meal.\n", hp->dev->name); "Happy Meal.\n", hp->dev->name);
} }
return; goto out;
} }
if (!is_lucent_phy(hp)) { if (!is_lucent_phy(hp)) {
hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
...@@ -891,11 +889,15 @@ static void happy_meal_timer(unsigned long data) ...@@ -891,11 +889,15 @@ static void happy_meal_timer(unsigned long data)
hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
add_timer(&hp->happy_timer); add_timer(&hp->happy_timer);
} }
out:
spin_unlock_irq(&hp->happy_lock);
} }
#define TX_RESET_TRIES 32 #define TX_RESET_TRIES 32
#define RX_RESET_TRIES 32 #define RX_RESET_TRIES 32
/* hp->happy_lock must be held */
static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
{ {
int tries = TX_RESET_TRIES; int tries = TX_RESET_TRIES;
...@@ -915,6 +917,7 @@ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs) ...@@ -915,6 +917,7 @@ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
HMD(("done\n")); HMD(("done\n"));
} }
/* hp->happy_lock must be held */
static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
{ {
int tries = RX_RESET_TRIES; int tries = RX_RESET_TRIES;
...@@ -936,6 +939,7 @@ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs) ...@@ -936,6 +939,7 @@ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
#define STOP_TRIES 16 #define STOP_TRIES 16
/* hp->happy_lock must be held */
static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
{ {
int tries = STOP_TRIES; int tries = STOP_TRIES;
...@@ -955,6 +959,7 @@ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs) ...@@ -955,6 +959,7 @@ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
HMD(("done\n")); HMD(("done\n"));
} }
/* hp->happy_lock must be held */
static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
{ {
struct net_device_stats *stats = &hp->net_stats; struct net_device_stats *stats = &hp->net_stats;
...@@ -977,53 +982,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs) ...@@ -977,53 +982,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
hme_write32(hp, bregs + BMAC_LTCTR, 0); hme_write32(hp, bregs + BMAC_LTCTR, 0);
} }
#if 0 /* hp->happy_lock must be held */
static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs)
{
u32 tmp;
int speed;
ASD(("happy_meal_poll_start: "));
if (!(hp->happy_flags & HFLAG_POLLENABLE)) {
HMD(("polling disabled, return\n"));
return;
}
/* Start the MIF polling on the external transceiver. */
ASD(("polling on, "));
tmp = hme_read32(hp, tregs + TCVR_CFG);
tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
tmp |= ((hp->paddr & 0x1f) << 10);
tmp |= (TCV_PADDR_ETX << 3);
tmp |= TCV_CFG_PENABLE;
hme_write32(hp, tregs + TCVR_CFG, tmp);
/* Let the bits set. */
udelay(200);
/* We are polling now. */
ASD(("now polling, "));
hp->happy_flags |= HFLAG_POLL;
/* Clear the poll flags, get the basic status as of now. */
hp->poll_flag = 0;
hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;
if (hp->happy_flags & HFLAG_AUTO)
speed = hp->auto_speed;
else
speed = hp->forced_speed;
/* Listen only for the MIF interrupts we want to hear. */
ASD(("mif ints on, "));
if (speed == 100)
hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);
else
hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);
ASD(("done\n"));
}
#endif
static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
{ {
ASD(("happy_meal_poll_stop: ")); ASD(("happy_meal_poll_stop: "));
...@@ -1058,6 +1017,7 @@ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs) ...@@ -1058,6 +1017,7 @@ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
#define TCVR_RESET_TRIES 16 /* It should reset quickly */ #define TCVR_RESET_TRIES 16 /* It should reset quickly */
#define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ #define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */
/* hp->happy_lock must be held */
static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
{ {
u32 tconfig; u32 tconfig;
...@@ -1152,7 +1112,10 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs) ...@@ -1152,7 +1112,10 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
return 0; return 0;
} }
/* Figure out whether we have an internal or external transceiver. */ /* Figure out whether we have an internal or external transceiver.
*
* hp->happy_lock must be held
*/
static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs) static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs)
{ {
unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG);
...@@ -1304,14 +1267,12 @@ static void happy_meal_clean_rings(struct happy_meal *hp) ...@@ -1304,14 +1267,12 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
} }
} }
static void happy_meal_init_rings(struct happy_meal *hp, int from_irq) /* hp->happy_lock must be held */
static void happy_meal_init_rings(struct happy_meal *hp)
{ {
struct hmeal_init_block *hb = hp->happy_block; struct hmeal_init_block *hb = hp->happy_block;
struct net_device *dev = hp->dev; struct net_device *dev = hp->dev;
int i, gfp_flags = GFP_KERNEL; int i;
if (from_irq || in_interrupt())
gfp_flags = GFP_ATOMIC;
HMD(("happy_meal_init_rings: counters to zero, ")); HMD(("happy_meal_init_rings: counters to zero, "));
hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0; hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
...@@ -1325,7 +1286,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq) ...@@ -1325,7 +1286,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb; struct sk_buff *skb;
skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) { if (!skb) {
hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);
continue; continue;
...@@ -1348,6 +1309,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq) ...@@ -1348,6 +1309,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
HMD(("done\n")); HMD(("done\n"));
} }
/* hp->happy_lock must be held */
static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
unsigned long tregs, unsigned long tregs,
struct ethtool_cmd *ep) struct ethtool_cmd *ep)
...@@ -1471,7 +1433,8 @@ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp, ...@@ -1471,7 +1433,8 @@ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
add_timer(&hp->happy_timer); add_timer(&hp->happy_timer);
} }
static int happy_meal_init(struct happy_meal *hp, int from_irq) /* hp->happy_lock must be held */
static int happy_meal_init(struct happy_meal *hp)
{ {
unsigned long gregs = hp->gregs; unsigned long gregs = hp->gregs;
unsigned long etxregs = hp->etxregs; unsigned long etxregs = hp->etxregs;
...@@ -1502,7 +1465,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) ...@@ -1502,7 +1465,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Alloc and reset the tx/rx descriptor chains. */ /* Alloc and reset the tx/rx descriptor chains. */
HMD(("happy_meal_init: to happy_meal_init_rings\n")); HMD(("happy_meal_init: to happy_meal_init_rings\n"));
happy_meal_init_rings(hp, from_irq); happy_meal_init_rings(hp);
/* Shut up the MIF. */ /* Shut up the MIF. */
HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ", HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
...@@ -1619,6 +1582,17 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) ...@@ -1619,6 +1582,17 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
hme_write32(hp, etxregs + ETX_RING, hme_write32(hp, etxregs + ETX_RING,
((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
/* Parity issues in the ERX unit of some HME revisions can cause some
* registers to not be written unless their parity is even. Detect such
* lost writes and simply rewrite with a low bit set (which will be ignored
* since the rxring needs to be 2K aligned).
*/
if (hme_read32(hp, erxregs + ERX_RING) !=
((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)))
hme_write32(hp, erxregs + ERX_RING,
((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))
| 0x4);
/* Set the supported burst sizes. */ /* Set the supported burst sizes. */
HMD(("happy_meal_init: old[%08x] bursts<", HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG))); hme_read32(hp, gregs + GREG_CFG)));
...@@ -1699,7 +1673,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) ...@@ -1699,7 +1673,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Enable Big Mac hash table filter. */ /* Enable Big Mac hash table filter. */
HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ", HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
hme_read32(hp, bregs + BMAC_RXCFG))); hme_read32(hp, bregs + BMAC_RXCFG)));
rxcfg = BIGMAC_RXCFG_HENABLE; rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME;
if (hp->dev->flags & IFF_PROMISC) if (hp->dev->flags & IFF_PROMISC)
rxcfg |= BIGMAC_RXCFG_PMISC; rxcfg |= BIGMAC_RXCFG_PMISC;
hme_write32(hp, bregs + BMAC_RXCFG, rxcfg); hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);
...@@ -1712,7 +1686,14 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) ...@@ -1712,7 +1686,14 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
regtmp = 0; regtmp = 0;
if (hp->happy_flags & HFLAG_FULL) if (hp->happy_flags & HFLAG_FULL)
regtmp |= BIGMAC_TXCFG_FULLDPLX; regtmp |= BIGMAC_TXCFG_FULLDPLX;
hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);
/* Don't turn on the "don't give up" bit for now. It could cause hme
* to deadlock with the PHY if a Jabber occurs.
*/
hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/);
/* Give up after 16 TX attempts. */
hme_write32(hp, bregs + BMAC_ALIMIT, 16);
/* Enable the output drivers no matter what. */ /* Enable the output drivers no matter what. */
regtmp = BIGMAC_XCFG_ODENABLE; regtmp = BIGMAC_XCFG_ODENABLE;
...@@ -1745,6 +1726,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq) ...@@ -1745,6 +1726,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
return 0; return 0;
} }
/* hp->happy_lock must be held */
static void happy_meal_set_initial_advertisement(struct happy_meal *hp) static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
{ {
unsigned long tregs = hp->tcvregs; unsigned long tregs = hp->tcvregs;
...@@ -1802,6 +1784,8 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp) ...@@ -1802,6 +1784,8 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
/* Once status is latched (by happy_meal_interrupt) it is cleared by /* Once status is latched (by happy_meal_interrupt) it is cleared by
* the hardware, so we cannot re-read it and get a correct value. * the hardware, so we cannot re-read it and get a correct value.
*
* hp->happy_lock must be held
*/ */
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{ {
...@@ -1910,12 +1894,13 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) ...@@ -1910,12 +1894,13 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
if (reset) { if (reset) {
printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name); printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
happy_meal_init(hp, 1); happy_meal_init(hp);
return 1; return 1;
} }
return 0; return 0;
} }
/* hp->happy_lock must be held */
static void happy_meal_mif_interrupt(struct happy_meal *hp) static void happy_meal_mif_interrupt(struct happy_meal *hp)
{ {
unsigned long tregs = hp->tcvregs; unsigned long tregs = hp->tcvregs;
...@@ -1949,6 +1934,7 @@ static void happy_meal_mif_interrupt(struct happy_meal *hp) ...@@ -1949,6 +1934,7 @@ static void happy_meal_mif_interrupt(struct happy_meal *hp)
#define TXD(x) #define TXD(x)
#endif #endif
/* hp->happy_lock must be held */
static void happy_meal_tx(struct happy_meal *hp) static void happy_meal_tx(struct happy_meal *hp)
{ {
struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
...@@ -1956,8 +1942,6 @@ static void happy_meal_tx(struct happy_meal *hp) ...@@ -1956,8 +1942,6 @@ static void happy_meal_tx(struct happy_meal *hp)
struct net_device *dev = hp->dev; struct net_device *dev = hp->dev;
int elem; int elem;
spin_lock(&hp->happy_lock);
elem = hp->tx_old; elem = hp->tx_old;
TXD(("TX<")); TXD(("TX<"));
while (elem != hp->tx_new) { while (elem != hp->tx_new) {
...@@ -2001,10 +1985,8 @@ static void happy_meal_tx(struct happy_meal *hp) ...@@ -2001,10 +1985,8 @@ static void happy_meal_tx(struct happy_meal *hp)
TXD((">")); TXD((">"));
if (netif_queue_stopped(dev) && if (netif_queue_stopped(dev) &&
TX_BUFFS_AVAIL(hp) > 0) TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev); netif_wake_queue(dev);
spin_unlock(&hp->happy_lock);
} }
#ifdef RXDEBUG #ifdef RXDEBUG
...@@ -2019,6 +2001,8 @@ static void happy_meal_tx(struct happy_meal *hp) ...@@ -2019,6 +2001,8 @@ static void happy_meal_tx(struct happy_meal *hp)
* with all of the packets it has DMA'd in. So now I just drop the entire * with all of the packets it has DMA'd in. So now I just drop the entire
* ring when we cannot get a new skb and give them all back to the happy meal, * ring when we cannot get a new skb and give them all back to the happy meal,
* maybe things will be "happier" now. * maybe things will be "happier" now.
*
* hp->happy_lock must be held
*/ */
static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
{ {
...@@ -2128,10 +2112,12 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -2128,10 +2112,12 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
HMD(("happy_meal_interrupt: status=%08x ", happy_status)); HMD(("happy_meal_interrupt: status=%08x ", happy_status));
spin_lock(&hp->happy_lock);
if (happy_status & GREG_STAT_ERRORS) { if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS ")); HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
return; goto out;
} }
if (happy_status & GREG_STAT_MIFIRQ) { if (happy_status & GREG_STAT_MIFIRQ) {
...@@ -2150,6 +2136,8 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -2150,6 +2136,8 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} }
HMD(("done\n")); HMD(("done\n"));
out:
spin_unlock(&hp->happy_lock);
} }
#ifdef CONFIG_SBUS #ifdef CONFIG_SBUS
...@@ -2171,10 +2159,12 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs ...@@ -2171,10 +2159,12 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
GREG_STAT_RXTOHOST))) GREG_STAT_RXTOHOST)))
continue; continue;
spin_lock(&hp->happy_lock);
if (happy_status & GREG_STAT_ERRORS) { if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS ")); HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, happy_status)) if (happy_meal_is_not_so_happy(hp, happy_status))
break; goto next;
} }
if (happy_status & GREG_STAT_MIFIRQ) { if (happy_status & GREG_STAT_MIFIRQ) {
...@@ -2191,6 +2181,9 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs ...@@ -2191,6 +2181,9 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
HMD(("RXTOHOST ")); HMD(("RXTOHOST "));
happy_meal_rx(hp, dev); happy_meal_rx(hp, dev);
} }
next:
spin_unlock(&hp->happy_lock);
} }
HMD(("done\n")); HMD(("done\n"));
} }
...@@ -2223,7 +2216,11 @@ static int happy_meal_open(struct net_device *dev) ...@@ -2223,7 +2216,11 @@ static int happy_meal_open(struct net_device *dev)
} }
HMD(("to happy_meal_init\n")); HMD(("to happy_meal_init\n"));
res = happy_meal_init(hp, 0);
spin_lock_irq(&hp->happy_lock);
res = happy_meal_init(hp);
spin_unlock_irq(&hp->happy_lock);
if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)) if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO))
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
return res; return res;
...@@ -2233,12 +2230,15 @@ static int happy_meal_close(struct net_device *dev) ...@@ -2233,12 +2230,15 @@ static int happy_meal_close(struct net_device *dev)
{ {
struct happy_meal *hp = dev->priv; struct happy_meal *hp = dev->priv;
spin_lock_irq(&hp->happy_lock);
happy_meal_stop(hp, hp->gregs); happy_meal_stop(hp, hp->gregs);
happy_meal_clean_rings(hp); happy_meal_clean_rings(hp);
/* If auto-negotiation timer is running, kill it. */ /* If auto-negotiation timer is running, kill it. */
del_timer(&hp->happy_timer); del_timer(&hp->happy_timer);
spin_unlock_irq(&hp->happy_lock);
/* On Quattro QFE cards, all hme interrupts are concentrated /* On Quattro QFE cards, all hme interrupts are concentrated
* into a single source which we register handling at probe * into a single source which we register handling at probe
* time and never unregister. * time and never unregister.
...@@ -2255,7 +2255,6 @@ static int happy_meal_close(struct net_device *dev) ...@@ -2255,7 +2255,6 @@ static int happy_meal_close(struct net_device *dev)
#define SXD(x) #define SXD(x)
#endif #endif
#ifdef CONFIG_SBUS
static void happy_meal_tx_timeout(struct net_device *dev) static void happy_meal_tx_timeout(struct net_device *dev)
{ {
struct happy_meal *hp = dev->priv; struct happy_meal *hp = dev->priv;
...@@ -2266,10 +2265,13 @@ static void happy_meal_tx_timeout(struct net_device *dev) ...@@ -2266,10 +2265,13 @@ static void happy_meal_tx_timeout(struct net_device *dev)
hme_read32(hp, hp->gregs + GREG_STAT), hme_read32(hp, hp->gregs + GREG_STAT),
hme_read32(hp, hp->etxregs + ETX_CFG), hme_read32(hp, hp->etxregs + ETX_CFG),
hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
happy_meal_init(hp, 0);
spin_lock_irq(&hp->happy_lock);
happy_meal_init(hp);
spin_unlock_irq(&hp->happy_lock);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
#endif
static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
...@@ -2294,6 +2296,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2294,6 +2296,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irq(&hp->happy_lock); spin_unlock_irq(&hp->happy_lock);
printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1; return 1;
} }
...@@ -2346,7 +2350,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2346,7 +2350,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
hp->tx_new = entry; hp->tx_new = entry;
if (TX_BUFFS_AVAIL(hp) <= 0) if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev); netif_stop_queue(dev);
/* Get it going. */ /* Get it going. */
...@@ -2364,7 +2368,10 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) ...@@ -2364,7 +2368,10 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
{ {
struct happy_meal *hp = dev->priv; struct happy_meal *hp = dev->priv;
spin_lock_irq(&hp->happy_lock);
happy_meal_get_counters(hp, hp->bigmacregs); happy_meal_get_counters(hp, hp->bigmacregs);
spin_unlock_irq(&hp->happy_lock);
return &hp->net_stats; return &hp->net_stats;
} }
...@@ -2377,7 +2384,8 @@ static void happy_meal_set_multicast(struct net_device *dev) ...@@ -2377,7 +2384,8 @@ static void happy_meal_set_multicast(struct net_device *dev)
int i; int i;
u32 crc; u32 crc;
/* Lock out others. */ spin_lock_irq(&hp->happy_lock);
netif_stop_queue(dev); netif_stop_queue(dev);
if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
...@@ -2411,8 +2419,9 @@ static void happy_meal_set_multicast(struct net_device *dev) ...@@ -2411,8 +2419,9 @@ static void happy_meal_set_multicast(struct net_device *dev)
hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);
} }
/* Let us get going again. */
netif_wake_queue(dev); netif_wake_queue(dev);
spin_unlock_irq(&hp->happy_lock);
} }
/* Ethtool support... */ /* Ethtool support... */
...@@ -2440,8 +2449,11 @@ static int happy_meal_ioctl(struct net_device *dev, ...@@ -2440,8 +2449,11 @@ static int happy_meal_ioctl(struct net_device *dev,
ecmd.phy_address = 0; /* XXX fixed PHYAD */ ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings. */ /* Record PHY settings. */
spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA); hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
spin_unlock_irq(&hp->happy_lock);
if (hp->sw_bmcr & BMCR_ANENABLE) { if (hp->sw_bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE; ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = ecmd.speed =
...@@ -2483,10 +2495,12 @@ static int happy_meal_ioctl(struct net_device *dev, ...@@ -2483,10 +2495,12 @@ static int happy_meal_ioctl(struct net_device *dev,
return -EINVAL; return -EINVAL;
/* Ok, do it to it. */ /* Ok, do it to it. */
spin_lock_irq(&hp->happy_lock);
del_timer(&hp->happy_timer); del_timer(&hp->happy_timer);
happy_meal_begin_auto_negotiation(hp, happy_meal_begin_auto_negotiation(hp,
hp->tcvregs, hp->tcvregs,
&ecmd); &ecmd);
spin_unlock_irq(&hp->happy_lock);
return 0; return 0;
} else } else
...@@ -2808,7 +2822,9 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe) ...@@ -2808,7 +2822,9 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
/* Grrr, Happy Meal comes up by default not advertising /* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this. * full duplex 100baseT capabilities, fix this.
*/ */
spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp); happy_meal_set_initial_advertisement(hp);
spin_unlock_irq(&hp->happy_lock);
if (register_netdev(hp->dev)) { if (register_netdev(hp->dev)) {
printk(KERN_ERR "happymeal: Cannot register net device, " printk(KERN_ERR "happymeal: Cannot register net device, "
...@@ -3121,6 +3137,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) ...@@ -3121,6 +3137,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->hard_start_xmit = &happy_meal_start_xmit; dev->hard_start_xmit = &happy_meal_start_xmit;
dev->get_stats = &happy_meal_get_stats; dev->get_stats = &happy_meal_get_stats;
dev->set_multicast_list = &happy_meal_set_multicast; dev->set_multicast_list = &happy_meal_set_multicast;
dev->tx_timeout = &happy_meal_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->do_ioctl = &happy_meal_ioctl; dev->do_ioctl = &happy_meal_ioctl;
dev->irq = pdev->irq; dev->irq = pdev->irq;
dev->dma = 0; dev->dma = 0;
...@@ -3143,7 +3161,9 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev) ...@@ -3143,7 +3161,9 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* Grrr, Happy Meal comes up by default not advertising /* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this. * full duplex 100baseT capabilities, fix this.
*/ */
spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp); happy_meal_set_initial_advertisement(hp);
spin_unlock_irq(&hp->happy_lock);
if (register_netdev(hp->dev)) { if (register_netdev(hp->dev)) {
printk(KERN_ERR "happymeal(PCI): Cannot register net device, " printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
......
...@@ -227,7 +227,7 @@ ...@@ -227,7 +227,7 @@
#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */ #define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */
#define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */ #define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */
#define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */ #define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */
#define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */ #define BIGMAC_RXCFG_REJME 0x00000200 /* Reject packets addressed to me */
#define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */ #define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */
#define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */ #define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */
#define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */ #define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */
......
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