X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2F7990.c;h=2d5ba076471c29d3b62a43c3765780711eb5d4af;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=0e5aec0d57d17d1a50196607bd74d5da373dadea;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 0e5aec0d5..2d5ba0764 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -1,7 +1,7 @@ -/* - * 7990.c -- LANCE ethernet IC generic routines. +/* + * 7990.c -- LANCE ethernet IC generic routines. * This is an attempt to separate out the bits of various ethernet - * drivers that are common because they all use the AMD 7990 LANCE + * drivers that are common because they all use the AMD 7990 LANCE * (Local Area Network Controller for Ethernet) chip. * * Copyright (C) 05/1998 Peter Maydell @@ -9,12 +9,11 @@ * Most of this stuff was obtained by looking at other LANCE drivers, * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful. * NB: this was made easy by the fact that Jes Sorensen had cleaned up - * most of a2025 and sunlance with the aim of merging them, so the + * most of a2025 and sunlance with the aim of merging them, so the * common code was pretty obvious. */ #include #include -#include #include #include #include @@ -30,26 +29,67 @@ #include #include #include +#include /* Used for the temporal inet entries and routing */ #include +#include #include -#include #include #include #include +#ifdef CONFIG_HP300 +#include +#endif #include "7990.h" +#define WRITERAP(lp,x) out_be16(lp->base + LANCE_RAP, (x)) +#define WRITERDP(lp,x) out_be16(lp->base + LANCE_RDP, (x)) +#define READRDP(lp) in_be16(lp->base + LANCE_RDP) + +#if defined(CONFIG_HPLANCE) || defined(CONFIG_HPLANCE_MODULE) +#include "hplance.h" + +#undef WRITERAP +#undef WRITERDP +#undef READRDP + +#if defined(CONFIG_MVME147_NET) || defined(CONFIG_MVME147_NET_MODULE) + /* Lossage Factor Nine, Mr Sulu. */ -#define WRITERAP(x) (lp->writerap(lp,x)) -#define WRITERDP(x) (lp->writerdp(lp,x)) -#define READRDP() (lp->readrdp(lp)) -/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh. - * If you want to switch them back then - * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll - */ -#define DECLARE_LL /* nothing to declare */ +#define WRITERAP(lp,x) (lp->writerap(lp,x)) +#define WRITERDP(lp,x) (lp->writerdp(lp,x)) +#define READRDP(lp) (lp->readrdp(lp)) + +#else + +/* These inlines can be used if only CONFIG_HPLANCE is defined */ +static inline void WRITERAP(struct lance_private *lp, __u16 value) +{ + do { + out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value); + } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0); +} + +static inline void WRITERDP(struct lance_private *lp, __u16 value) +{ + do { + out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value); + } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0); +} + +static inline __u16 READRDP(struct lance_private *lp) +{ + __u16 value; + do { + value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP); + } while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0); + return value; +} + +#endif +#endif /* CONFIG_HPLANCE || CONFIG_HPLANCE_MODULE */ /* debugging output macros, various flavours */ /* #define TEST_HITS */ @@ -69,29 +109,28 @@ do { \ ib->btx_ring[t].length,\ ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\ }\ -} while (0) +} while (0) #else #define PRINT_RINGS() -#endif +#endif /* Load the CSR registers. The LANCE has to be STOPped when we do this! */ static void load_csrs (struct lance_private *lp) { volatile struct lance_init_block *aib = lp->lance_init_block; int leptr; - DECLARE_LL; leptr = LANCE_ADDR (aib); - WRITERAP(LE_CSR1); /* load address of init block */ - WRITERDP(leptr & 0xFFFF); - WRITERAP(LE_CSR2); - WRITERDP(leptr >> 16); - WRITERAP(LE_CSR3); - WRITERDP(lp->busmaster_regval); /* set byteswap/ALEctrl/byte ctrl */ + WRITERAP(lp, LE_CSR1); /* load address of init block */ + WRITERDP(lp, leptr & 0xFFFF); + WRITERAP(lp, LE_CSR2); + WRITERDP(lp, leptr >> 16); + WRITERAP(lp, LE_CSR3); + WRITERDP(lp, lp->busmaster_regval); /* set byteswap/ALEctrl/byte ctrl */ /* Point back to csr0 */ - WRITERAP(LE_CSR0); + WRITERAP(lp, LE_CSR0); } /* #define to 0 or 1 appropriately */ @@ -118,7 +157,7 @@ static void lance_init_ring (struct net_device *dev) * a2065 and atarilance do the byteswap and lance.c (PC) doesn't. * However, the datasheet says that the BSWAP bit doesn't affect * the init block, so surely it should be low byte first for - * everybody? Um.] + * everybody? Um.] * We could define the ib->physaddr as three 16bit values and * use (addr[1] << 8) | addr[0] & co, but this is more efficient. */ @@ -132,11 +171,11 @@ static void lance_init_ring (struct net_device *dev) #else for (i=0; i<6; i++) ib->phys_addr[i] = dev->dev_addr[i]; -#endif +#endif if (DEBUG_IRING) printk ("TX rings:\n"); - + lp->tx_full = 0; /* Setup the Tx ring entries */ for (i = 0; i < (1<lance_log_tx_bufs); i++) { @@ -146,7 +185,7 @@ static void lance_init_ring (struct net_device *dev) ib->btx_ring [i].tmd1_bits = 0; ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */ ib->btx_ring [i].misc = 0; - if (DEBUG_IRING) + if (DEBUG_IRING) printk ("%d: 0x%8.8x\n", i, leptr); } @@ -167,14 +206,14 @@ static void lance_init_ring (struct net_device *dev) } /* Setup the initialization block */ - + /* Setup rx descriptor pointer */ leptr = LANCE_ADDR(&aib->brx_ring); ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16); ib->rx_ptr = leptr; if (DEBUG_IRING) printk ("RX ptr: %8.8x\n", leptr); - + /* Setup tx descriptor pointer */ leptr = LANCE_ADDR(&aib->btx_ring); ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16); @@ -192,24 +231,23 @@ static void lance_init_ring (struct net_device *dev) static int init_restart_lance (struct lance_private *lp) { int i; - DECLARE_LL; - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_INIT); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_INIT); /* Need a hook here for sunlance ledma stuff */ /* Wait for the lance to complete initialization */ - for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++) + for (i = 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++) barrier(); - if ((i == 100) || (READRDP() & LE_C0_ERR)) { - printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP()); + if ((i == 100) || (READRDP(lp) & LE_C0_ERR)) { + printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP(lp)); return -1; } /* Clear IDON by writing a "1", enable interrupts and start lance */ - WRITERDP(LE_C0_IDON); - WRITERDP(LE_C0_INEA | LE_C0_STRT); + WRITERDP(lp, LE_C0_IDON); + WRITERDP(lp, LE_C0_INEA | LE_C0_STRT); return 0; } @@ -218,11 +256,10 @@ static int lance_reset (struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int status; - DECLARE_LL; - + /* Stop the lance */ - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_STOP); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STOP); load_csrs (lp); lance_init_ring (dev); @@ -245,7 +282,6 @@ static int lance_rx (struct net_device *dev) #ifdef TEST_HITS int i; #endif - DECLARE_LL; #ifdef TEST_HITS printk ("["); @@ -259,8 +295,10 @@ static int lance_rx (struct net_device *dev) } printk ("]"); #endif - - WRITERDP(LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */ +#ifdef CONFIG_HP300 + blinken_leds(0x40, 0); +#endif + WRITERDP(lp, LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */ for (rd = &ib->brx_ring [lp->rx_new]; /* For each Rx ring we own... */ !((bits = rd->rmd1_bits) & LE_R1_OWN); rd = &ib->brx_ring [lp->rx_new]) { @@ -292,7 +330,7 @@ static int lance_rx (struct net_device *dev) lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask; return 0; } - + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put (skb, len); /* make room */ @@ -321,10 +359,12 @@ static int lance_tx (struct net_device *dev) volatile struct lance_tx_desc *td; int i, j; int status; - DECLARE_LL; +#ifdef CONFIG_HP300 + blinken_leds(0x80, 0); +#endif /* csr0 is 2f3 */ - WRITERDP(LE_C0_TINT | LE_C0_INEA); + WRITERDP(lp, LE_C0_TINT | LE_C0_INEA); /* csr0 is 73 */ j = lp->tx_old; @@ -334,10 +374,10 @@ static int lance_tx (struct net_device *dev) /* If we hit a packet not owned by us, stop */ if (td->tmd1_bits & LE_T1_OWN) break; - + if (td->tmd1_bits & LE_T1_ERR) { status = td->misc; - + lp->stats.tx_errors++; if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; @@ -349,8 +389,8 @@ static int lance_tx (struct net_device *dev) printk("%s: Carrier Lost, trying %s\n", dev->name, lp->tpe?"TPE":"AUI"); /* Stop the lance */ - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_STOP); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STOP); lance_init_ring (dev); load_csrs (lp); init_restart_lance (lp); @@ -366,8 +406,8 @@ static int lance_tx (struct net_device *dev) printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); /* Stop the lance */ - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_STOP); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STOP); lance_init_ring (dev); load_csrs (lp); init_restart_lance (lp); @@ -389,40 +429,39 @@ static int lance_tx (struct net_device *dev) lp->stats.tx_packets++; } - + j = (j + 1) & lp->tx_ring_mod_mask; } lp->tx_old = j; - WRITERDP(LE_C0_TINT | LE_C0_INEA); + WRITERDP(lp, LE_C0_TINT | LE_C0_INEA); return 0; } static irqreturn_t -lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) +lance_interrupt (int irq, void *dev_id) { struct net_device *dev = (struct net_device *)dev_id; struct lance_private *lp = netdev_priv(dev); int csr0; - DECLARE_LL; spin_lock (&lp->devlock); - WRITERAP(LE_CSR0); /* LANCE Controller Status */ - csr0 = READRDP(); + WRITERAP(lp, LE_CSR0); /* LANCE Controller Status */ + csr0 = READRDP(lp); PRINT_RINGS(); - + if (!(csr0 & LE_C0_INTR)) { /* Check if any interrupt has */ - spin_lock (&lp->devlock); + spin_unlock (&lp->devlock); return IRQ_NONE; /* been generated by the Lance. */ } /* Acknowledge all the interrupt sources ASAP */ - WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT)); + WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT)); if ((csr0 & LE_C0_ERR)) { /* Clear the error condition */ - WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA); + WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA); } if (csr0 & LE_C0_RINT) @@ -437,19 +476,19 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) if (csr0 & LE_C0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ if (csr0 & LE_C0_MERR) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", + printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); /* Restart the chip. */ - WRITERDP(LE_C0_STRT); + WRITERDP(lp, LE_C0_STRT); } if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >= 0)) { lp->tx_full = 0; netif_wake_queue (dev); } - - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA); + + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA); spin_unlock (&lp->devlock); return IRQ_HANDLED; @@ -459,14 +498,13 @@ int lance_open (struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); int res; - DECLARE_LL; - + /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */ - if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev)) + if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev)) return -EAGAIN; res = lance_reset(dev); - lp->devlock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&lp->devlock); netif_start_queue (dev); return res; @@ -475,13 +513,12 @@ int lance_open (struct net_device *dev) int lance_close (struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); - DECLARE_LL; - + netif_stop_queue (dev); /* Stop the LANCE */ - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_STOP); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STOP); free_irq(lp->irq, dev); @@ -504,7 +541,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) int entry, skblen, len; static int outs; unsigned long flags; - DECLARE_LL; if (!TX_BUFFS_AVAIL) return -1; @@ -517,7 +553,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) /* dump the packet */ { int i; - + for (i = 0; i < 64; i++) { if ((i % 16) == 0) printk ("\n"); @@ -529,21 +565,21 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) entry = lp->tx_new & lp->tx_ring_mod_mask; ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - + if (skb->len < ETH_ZLEN) memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); - + /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; outs++; /* Kick the lance: transmit now */ - WRITERDP(LE_C0_INEA | LE_C0_TDMD); + WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD); dev->trans_start = jiffies; dev_kfree_skb (skb); - + spin_lock_irqsave (&lp->devlock, flags); if (TX_BUFFS_AVAIL) netif_start_queue (dev); @@ -571,9 +607,9 @@ static void lance_load_multicast (struct net_device *dev) char *addrs; int i; u32 crc; - + /* set all multicast bits */ - if (dev->flags & IFF_ALLMULTI){ + if (dev->flags & IFF_ALLMULTI){ ib->filter [0] = 0xffffffff; ib->filter [1] = 0xffffffff; return; @@ -590,7 +626,7 @@ static void lance_load_multicast (struct net_device *dev) /* multicast address? */ if (!(*addrs & 1)) continue; - + crc = ether_crc_le(6, addrs); crc = crc >> 26; mcast_table [crc >> 4] |= 1 << (crc & 0xf); @@ -604,7 +640,6 @@ void lance_set_multicast (struct net_device *dev) struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int stopped; - DECLARE_LL; stopped = netif_queue_stopped(dev); if (!stopped) @@ -613,8 +648,8 @@ void lance_set_multicast (struct net_device *dev) while (lp->tx_old != lp->tx_new) schedule(); - WRITERAP(LE_CSR0); - WRITERDP(LE_C0_STOP); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STOP); lance_init_ring (dev); if (dev->flags & IFF_PROMISC) { @@ -630,4 +665,17 @@ void lance_set_multicast (struct net_device *dev) netif_start_queue (dev); } +#ifdef CONFIG_NET_POLL_CONTROLLER +void lance_poll(struct net_device *dev) +{ + struct lance_private *lp = netdev_priv(dev); + + spin_lock (&lp->devlock); + WRITERAP(lp, LE_CSR0); + WRITERDP(lp, LE_C0_STRT); + spin_unlock (&lp->devlock); + lance_interrupt(dev->irq, dev); +} +#endif + MODULE_LICENSE("GPL");