patch-2.2.0-pre9 linux/drivers/net/fmv18x.c
Next file: linux/drivers/net/irda/Config.in
Previous file: linux/drivers/net/at1700.c
Back to the patch index
Back to the overall index
- Lines: 201
- Date:
Tue Jan 19 10:13:13 1999
- Orig file:
v2.2.0-pre8/linux/drivers/net/fmv18x.c
- Orig date:
Thu Feb 12 20:56:08 1998
diff -u --recursive --new-file v2.2.0-pre8/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
@@ -32,7 +32,7 @@
*/
static const char *version =
- "fmv18x.c:v1.3.71e 03/04/96 Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
+ "fmv18x.c:v2.2.0 09/24/98 Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
#include <linux/module.h>
@@ -74,6 +74,8 @@
struct net_device_stats stats;
long open_time; /* Useless example local info. */
uint tx_started:1; /* Number of packet on the Tx queue. */
+ uint tx_queue_ready:1; /* Tx queue is ready to be sent. */
+ uint rx_started:1; /* Packets are Rxing. */
uchar tx_queue; /* Number of packet on the Tx queue. */
ushort tx_queue_len; /* Current length of the Tx queue. */
};
@@ -92,7 +94,7 @@
/* Run-time register bank 2 definitions. */
#define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */
#define TX_START 10
-#define COL16CNTL 11
+#define COL16CNTL 11 /* Controll Reg for 16 collisions */
#define MODE13 13
/* Fujitsu FMV-18x Card Configuration */
#define FJ_STATUS0 0x10
@@ -164,6 +166,7 @@
__initfunc(int fmv18x_probe1(struct device *dev, short ioaddr))
{
char irqmap[4] = {3, 7, 10, 15};
+ char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
unsigned int i, irq;
/* Resetting the chip doesn't reset the ISA interface, so don't bother.
@@ -171,13 +174,26 @@
*/
/* Check I/O address configuration and Fujitsu vendor code */
- if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr
- || inb(ioaddr+FJ_MACADDR ) != 0x00
+ if (inb(ioaddr+FJ_MACADDR ) != 0x00
|| inb(ioaddr+FJ_MACADDR+1) != 0x00
|| inb(ioaddr+FJ_MACADDR+2) != 0x0e)
return -ENODEV;
- irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
+ /* Check PnP mode for FMV-183/184/183A/184A. */
+ /* This PnP routine is very poor. IO and IRQ should be known. */
+ if (inb(ioaddr + FJ_STATUS1) & 0x20) {
+ irq = dev->irq;
+ for (i = 0; i < 8; i++) {
+ if (irq == irqmap_pnp[i])
+ break;
+ }
+ if (i == 8)
+ return -ENODEV;
+ } else {
+ if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr)
+ return -ENODEV;
+ irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
+ }
/* Snarf the interrupt vector now. */
if (request_irq(irq, &net_interrupt, 0, "fmv18x", dev)) {
@@ -247,6 +263,7 @@
/* Switch to bank 2 and lock our I/O address. */
outb(0x08, ioaddr + CONFIG_1);
outb(dev->if_port, ioaddr + MODE13);
+ outb(0x00, ioaddr + COL16CNTL);
if (net_debug)
printk(version);
@@ -283,6 +300,8 @@
outb(0xe8, ioaddr + CONFIG_1);
lp->tx_started = 0;
+ lp->tx_queue_ready = 1;
+ lp->rx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
@@ -364,14 +383,20 @@
printk("%s: Transmitting a packet of length %lu.\n", dev->name,
(unsigned long)skb->len);
- /* Disable both interrupts. */
- outw(0x0000, ioaddr + TX_INTR);
-
- outw(length, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+ /* We may not start transmitting unless we finish transferring
+ a packet into the Tx queue. During executing the following
+ codes we possibly catch a Tx interrupt. Thus we flag off
+ tx_queue_ready, so that we prevent the interrupt routine
+ (net_interrupt) to start transmitting. */
+ lp->tx_queue_ready = 0;
+ {
+ outw(length, ioaddr + DATAPORT);
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+ }
+ lp->tx_queue_ready = 1;
if (lp->tx_started == 0) {
/* If the Tx is idle, always trigger a transmit. */
@@ -384,9 +409,6 @@
} else if (lp->tx_queue_len < 4096 - 1502)
/* Yes, there is room for one more packet. */
dev->tbusy = 0;
-
- /* Re-enable interrupts */
- outw(0x8182, ioaddr + TX_INTR);
}
dev_kfree_skb (skb);
@@ -410,23 +432,37 @@
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
-
- /* Avoid multiple interrupts. */
- outw(0x0000, ioaddr + TX_INTR);
-
- status = inw(ioaddr + TX_STATUS);
+ status = inw(ioaddr + TX_STATUS);
outw(status, ioaddr + TX_STATUS);
if (net_debug > 4)
printk("%s: Interrupt with status %04x.\n", dev->name, status);
- if (status & 0xff00
- || (inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Got a packet(s). */
+ if (lp->rx_started == 0 &&
+ (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0)) {
+ /* Got a packet(s).
+ We cannot execute net_rx more than once at the same time for
+ the same device. During executing net_rx, we possibly catch a
+ Tx interrupt. Thus we flag on rx_started, so that we prevent
+ the interrupt routine (net_interrupt) to dive into net_rx
+ again. */
+ lp->rx_started = 1;
+ outb(0x00, ioaddr + RX_INTR); /* Disable RX intr. */
net_rx(dev);
+ outb(0x81, ioaddr + RX_INTR); /* Enable RX intr. */
+ lp->rx_started = 0;
}
if (status & 0x00ff) {
- if (status & 0x80) {
+ if (status & 0x02) {
+ /* More than 16 collisions occurred */
+ if (net_debug > 4)
+ printk("%s: 16 Collision occur during Txing.\n", dev->name);
+ /* Cancel sending a packet. */
+ outb(0x03, ioaddr + COL16CNTL);
+ lp->stats.collisions++;
+ }
+ if (status & 0x82) {
lp->stats.tx_packets++;
- if (lp->tx_queue) {
+ if (lp->tx_queue && lp->tx_queue_ready) {
outb(0x80 | lp->tx_queue, ioaddr + TX_START);
lp->tx_queue = 0;
lp->tx_queue_len = 0;
@@ -439,16 +475,9 @@
mark_bh(NET_BH); /* Inform upper layers. */
}
}
- if (status & 0x02 ) {
- if (net_debug > 4)
- printk("%s: 16 Collision occur during Txing.\n", dev->name);
- /* Retry to send the packet */
- outb(0x02, ioaddr + COL16CNTL);
- }
}
dev->interrupt = 0;
- outw(0x8182, ioaddr + TX_INTR);
return;
}
@@ -458,7 +487,7 @@
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- int boguscount = 10; /* 5 -> 10: by agy 19940922 */
+ int boguscount = 5;
while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
/* Clear PKT_RDY bit: by agy 19940922 */
@@ -619,6 +648,7 @@
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
+MODULE_PARM(net_debug, "i");
int init_module(void)
{
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov