patch-2.2.18 linux/drivers/acorn/net/ether3.c
Next file: linux/drivers/acorn/net/ether3.h
Previous file: linux/drivers/acorn/net/ether1.c
Back to the patch index
Back to the overall index
- Lines: 409
- Date:
Fri Sep 15 23:31:12 2000
- Orig file:
v2.2.17/drivers/acorn/net/ether3.c
- Orig date:
Fri Apr 21 12:45:50 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
@@ -33,11 +33,12 @@
* packet starts two bytes from the end of the
* buffer, it corrupts the receiver chain, and
* never updates the transmit status correctly.
- * TODO:
- * When we detect a fatal error on the interface, we should restart it.
+ * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing.
+ * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy
+ * hardware.
*/
-static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
+static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n";
#include <linux/module.h>
#include <linux/kernel.h>
@@ -66,7 +67,7 @@
#include "ether3.h"
static unsigned int net_debug = NET_DEBUG;
-static const card_ids ether3_cids[] = {
+static const card_ids __init ether3_cids[] = {
{ MANU_ANT2, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */
@@ -77,9 +78,6 @@
static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt);
static void ether3_tx(struct device *dev, struct dev_priv *priv);
-extern int inswb(int reg, void *buffer, int len);
-extern int outswb(int reg, void *buffer, int len);
-
#define BUS_16 2
#define BUS_8 1
#define BUS_UNKNOWN 0
@@ -88,7 +86,7 @@
* I'm not sure what address we should default to if the internal one
* is corrupted...
*/
-unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+unsigned char def_eth_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
/* --------------------------------------------------------------------------- */
@@ -99,10 +97,20 @@
/*
* ether3 read/write. Slow things down a bit...
+ * The SEEQ8005 doesn't like us writing to it's registers
+ * too quickly.
*/
-#define ether3_outb(v,r) { outb((v),(r)); udelay(1); }
-#define ether3_outw(v,r) { outw((v),(r)); udelay(1); }
+static inline void ether3_outb(int v, const int r)
+{
+ outb(v, r);
+ udelay(1);
+}
+static inline void ether3_outw(int v, const int r)
+{
+ outw(v, r);
+ udelay(1);
+}
#define ether3_inb(r) ({ unsigned int __v = inb((r)); udelay(1); __v; })
#define ether3_inw(r) ({ unsigned int __v = inw((r)); udelay(1); __v; })
@@ -138,7 +146,7 @@
* write data to the buffer memory
*/
#define ether3_writebuffer(dev,data,length) \
- outswb(REG_BUFWIN, (data), (length))
+ outsw(REG_BUFWIN, (data), (length) >> 1)
#define ether3_writeword(dev,data) \
outw((data), REG_BUFWIN)
@@ -153,7 +161,7 @@
* read data from the buffer memory
*/
#define ether3_readbuffer(dev,data,length) \
- inswb(REG_BUFWIN, (data), (length))
+ insw(REG_BUFWIN, (data), (length) >> 1)
#define ether3_readword(dev) \
inw(REG_BUFWIN)
@@ -249,7 +257,7 @@
}
} else {
if (bad != -1) {
- if (bad != i - 1)
+ if (bad != i - 1)
printk(" - 0x%04X\n", i - 1);
printk("\n");
bad = -1;
@@ -335,7 +343,6 @@
for (i = 0; i < 6; i++)
ether3_outb(dev->dev_addr[i], REG_BUFWIN);
- priv->tx_used = 0;
priv->tx_head = 0;
priv->tx_tail = 0;
priv->regs.config2 |= CFG2_CTRLO;
@@ -471,6 +478,25 @@
return error;
}
+__initfunc(static void
+ether3_get_dev(struct device *dev, struct expansion_card *ec))
+{
+ ecard_claim(ec);
+
+ dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+ dev->irq = ec->irq;
+
+ if (ec->cid.manufacturer == MANU_ANT &&
+ ec->cid.product == PROD_ANT_ETHERB) {
+ dev->base_addr += 0x200;
+ }
+
+ ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
+ ec->irqmask = 0xf0;
+
+ ether3_addr(dev->dev_addr, ec);
+}
+
#ifndef MODULE
__initfunc(int
ether3_probe(struct device *dev))
@@ -485,12 +511,8 @@
if ((ec = ecard_find(0, ether3_cids)) == NULL)
return ENODEV;
- dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
- dev->irq = ec->irq;
-
- ecard_claim(ec);
+ ether3_get_dev(dev, ec);
- ether3_addr(dev->dev_addr, ec);
return ether3_probe1(dev);
}
#endif
@@ -581,33 +603,6 @@
}
/*
- * Allocate memory in transmitter ring buffer.
- */
-static int
-ether3_alloc_tx(struct dev_priv *priv, int length, int alloc)
-{
- int start, head, tail;
-
- tail = priv->tx_tail;
- start = priv->tx_head;
- head = start + length + 4;
-
- if (head >= TX_END) {
- if (tail > priv->tx_head)
- return -1;
- head -= TX_END - TX_START;
- if (tail < head)
- return -1;
- } else if (start < tail && tail < head)
- return -1;
-
- if (alloc)
- priv->tx_head = head;
-
- return start;
-}
-
-/*
* Transmit a packet
*/
static int
@@ -622,7 +617,7 @@
if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
unsigned long flags;
unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- int ptr;
+ unsigned int ptr, next_ptr;
length = (length + 1) & ~1;
@@ -633,23 +628,31 @@
return 0;
}
+ next_ptr = (priv->tx_head + 1) & 15;
+
save_flags_cli(flags);
- ptr = ether3_alloc_tx(priv, length, 1);
- if (ptr == -1)
+ if (priv->tx_tail == next_ptr) {
+ restore_flags(flags);
return 1; /* unable to queue */
+ }
+
+ dev->trans_start = jiffies;
+ ptr = 0x600 * priv->tx_head;
+ priv->tx_head = next_ptr;
+ next_ptr *= 0x600;
#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
- ether3_setbuffer(dev, buffer_write, priv->tx_head);
+ ether3_setbuffer(dev, buffer_write, next_ptr);
ether3_writelong(dev, 0);
-
ether3_setbuffer(dev, buffer_write, ptr);
ether3_writelong(dev, 0);
ether3_writebuffer(dev, skb->data, length);
-
+ ether3_writeword(dev, htons(next_ptr));
+ ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
ether3_setbuffer(dev, buffer_write, ptr);
- ether3_writeword(dev, htons(priv->tx_head));
+ ether3_writeword(dev, htons((ptr + length + 4)));
ether3_writeword(dev, TXHDR_FLAGS >> 16);
ether3_ledon(dev, priv);
@@ -658,11 +661,10 @@
ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
}
- if (ether3_alloc_tx(priv, 2044, 0) != -1)
+ next_ptr = (priv->tx_head + 1) & 15;
+ if (priv->tx_tail != next_ptr)
dev->tbusy = 0;
- dev->trans_start = jiffies;
-
restore_flags(flags);
dev_kfree_skb(skb);
@@ -689,7 +691,7 @@
ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
- printk(KERN_ERR "%s: tx head=%04X tx tail=%04X\n", dev->name,
+ printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
priv->tx_head, priv->tx_tail);
ether3_setbuffer(dev, buffer_read, priv->tx_tail);
printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
@@ -698,8 +700,9 @@
dev->tbusy = 0;
priv->regs.config2 |= CFG2_CTRLO;
priv->stats.tx_errors += 1;
- ether3_outw(priv->regs.config2 , REG_CONFIG2);
+ ether3_outw(priv->regs.config2, REG_CONFIG2);
dev->trans_start = jiffies;
+ priv->tx_head = priv->tx_tail = 0;
goto retry;
}
}
@@ -867,6 +870,7 @@
ether3_tx(struct device *dev, struct dev_priv *priv)
{
unsigned int tx_tail = priv->tx_tail;
+ int max_work = 14;
do {
unsigned long status;
@@ -874,7 +878,7 @@
/*
* Read the packet header
*/
- ether3_setbuffer(dev, buffer_read, tx_tail);
+ ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
status = ether3_readlong(dev);
/*
@@ -895,95 +899,72 @@
if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
}
- tx_tail = htons(status & TX_NEXT);
- if (tx_tail < TX_START || tx_tail >= TX_END) {
- printk("%s: transmit error: next pointer = %04X\n", dev->name, tx_tail);
- tx_tail = TX_START;
- priv->tx_head = TX_START;
- priv->tx_tail = TX_END;
- }
- } while (1);
+ tx_tail = (tx_tail + 1) & 15;
+ } while (--max_work);
if (priv->tx_tail != tx_tail) {
priv->tx_tail = tx_tail;
- if (priv->tx_used <= MAX_TX_BUFFERED) {
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
- }
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
}
}
#ifdef MODULE
-char ethernames[MAX_ECARDS][9];
-
-static struct device *my_ethers[MAX_ECARDS];
-static struct expansion_card *ec[MAX_ECARDS];
+static struct ether_dev {
+ struct expansion_card *ec;
+ char name[9];
+ struct device dev;
+} ether_devs[MAX_ECARDS];
int
init_module(void)
{
- int i;
+ struct expansion_card *ec;
+ int i, ret = -ENODEV;
- for(i = 0; i < MAX_ECARDS; i++) {
- my_ethers[i] = NULL;
- ec[i] = NULL;
- strcpy(ethernames[i], " ");
- }
+ memset(ether_devs, 0, sizeof(ether_devs));
+ ecard_startfind ();
+ ec = ecard_find(0, ether3_cids);
i = 0;
- ecard_startfind();
+ while (ec && i < MAX_ECARDS) {
+ ecard_claim(ec);
- do {
- if ((ec[i] = ecard_find(0, ether3_cids)) == NULL)
- break;
-
- my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
- memset(my_ethers[i], 0, sizeof(struct device));
+ ether_devs[i].ec = ec;
+ ether_devs[i].dev.init = ether3_probe1;
+ ether_devs[i].dev.name = ether_devs[i].name;
+ ether3_get_dev(ðer_devs[i].dev, ec);
+
+ ret = register_netdev(ðer_devs[i].dev);
+
+ if (ret) {
+ ecard_release(ec);
+ ether_devs[i].ec = NULL;
+ } else
+ i += 1;
- my_ethers[i]->irq = ec[i]->irq;
- my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0);
- my_ethers[i]->init = ether3_probe1;
- my_ethers[i]->name = ethernames[i];
-
- ether3_addr(my_ethers[i]->dev_addr, ec[i]);
-
- ecard_claim(ec[i]);
-
- if(register_netdev(my_ethers[i]) != 0) {
- for (i = 0; i < 4; i++) {
- if(my_ethers[i]) {
- kfree(my_ethers[i]);
- my_ethers[i] = NULL;
- }
- if(ec[i]) {
- ecard_release(ec[i]);
- ec[i] = NULL;
- }
- }
- return -EIO;
- }
- i++;
+ ec = ecard_find(0, ether3_cids);
}
- while(i < MAX_ECARDS);
- return i != 0 ? 0 : -ENODEV;
+ return i != 0 ? 0 : ret;
}
void
cleanup_module(void)
{
int i;
+
for (i = 0; i < MAX_ECARDS; i++) {
- if (my_ethers[i]) {
- release_region(my_ethers[i]->base_addr, 128);
- unregister_netdev(my_ethers[i]);
- my_ethers[i] = NULL;
- }
- if (ec[i]) {
- ecard_release(ec[i]);
- ec[i] = NULL;
+ if (ether_devs[i].ec) {
+ unregister_netdev(ðer_devs[i].dev);
+
+ release_region(ether_devs[i].dev.base_addr, 128);
+
+ ecard_release(ether_devs[i].ec);
+
+ ether_devs[i].ec = NULL;
}
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)