patch-2.1.17 linux/drivers/net/tulip.c
Next file: linux/drivers/net/wavelan.c
Previous file: linux/drivers/net/soundmodem.c
Back to the patch index
Back to the overall index
- Lines: 324
- Date:
Fri Dec 20 10:48:16 1996
- Orig file:
v2.1.16/linux/drivers/net/tulip.c
- Orig date:
Fri Nov 22 18:28:18 1996
diff -u --recursive --new-file v2.1.16/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
@@ -12,13 +12,16 @@
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Subscribe to linux-tulip@cesdis.gsfc.nasa.gov and linux-tulip-bugs@cesdis.gsfc.nasa.gov
+ for late breaking news and exciting develovements.
*/
static char *version =
"tulip.c:v0.10 8/11/95 becker@cesdis.gsfc.nasa.gov\n"
" +0.72 4/17/96 "
"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n"
-" +0.01 10/24/96 mjacob@feral.com (2.1.7)\n";
+" +0.02 12/15/96 mjacob@feral.com (2.0.27)\n";
/* A few user-configurable values. */
@@ -402,6 +405,8 @@
0x0000f400, PCI_DEVICE_ID_DEC_TULIP_FAST, "LA100PCI", 0},
{cogent21140_select, generic21140_fail,
0x00009200, PCI_DEVICE_ID_DEC_TULIP_FAST, "cogent_em110", 0},
+ {generic21040_select, generic21040_fail,
+ 0x00009200, PCI_DEVICE_ID_DEC_TULIP, "cogent_em96x", 1},
{generic21140_select, generic21140_fail,
0x0000f800, PCI_DEVICE_ID_DEC_TULIP_FAST, "DE500", 0},
{generic21041_select, generic21041_fail,
@@ -681,6 +686,7 @@
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int ioaddr = dev->base_addr;
+ int i;
/* Reset the chip, holding bit 0 set at least 10 PCI cycles. */
tio_write(tio_read(CSR0)|TBMOD_RESET, CSR0);
@@ -717,7 +723,7 @@
tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
tp->tx_ring[0].buffer2 = 0;
tp->tx_ring[0].status = TRING_OWN;
-
+ barrier();
tp->cur_tx++, tp->dirty_tx++;
}
@@ -727,16 +733,38 @@
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
-
- if (tp->port_select) tp->port_select(dev);
-
+ /*
+ * process setup frame completely prior to fiddling with media.
+ */
+ tio_write((tio_read(CSR6) & ~TCMOD_PROMISC) | TCMOD_TxSTART, CSR6);
+ tio_write(TPOLL_TRIGGER, CSR1);
+ sti();
+ for (i = 0; i < 1000; i++) {
+ if (tp->tx_ring[0].status >= 0) {
+ break;
+ }
+ udelay(1000);
+ }
+ if (i == 500) {
+ printk("%s: initial setup frame didn't complete.\n", dev->name);
+ dev->start = 0;
+ dev->tbusy = 1;
+ tio_write(TINTR_DISABLE, CSR7);
+ tio_write(tio_read(CSR6) & ~(TCMOD_TRxSTART), CSR6);
+ tio_write(TSIAC_CONFIG, CSR13);
+ tio_write(0, CSR13);
+ free_irq(dev->irq, dev);
+ return (-EIO);
+ }
+ /*
+ * Whack the chip to stop it and *then* do initial media setup.
+ */
+ tio_write((tio_read(CSR6) & ~(TCMOD_PROMISC|TCMOD_TxSTART)), CSR6);
+ if (tp->port_select)
+ tp->port_select(dev);
/* Start the chip's Tx and Rx processes. */
tio_write(tio_read(CSR6) | TCMOD_TRxSTART
| (tp->full_duplex ? TCMOD_FULLDUPLEX:0), CSR6);
-
- /* Trigger an immediate transmit demand to process the setup frame. */
- tio_write(TPOLL_TRIGGER, CSR1);
-
/* Enable interrupts by setting the interrupt mask. */
tio_write(TINTR_ENABLE, CSR7);
@@ -777,7 +805,8 @@
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int ioaddr = dev->base_addr;
- int entry;
+ int entry, len;
+ unsigned long daddr;
/* Transmitter timeout, serious problems. */
if (dev->tbusy || (tp->port_fail && tp->port_fail(dev))) {
@@ -820,7 +849,7 @@
return(0);
}
- if (skb == NULL || skb->len <= 0) {
+ if (skb == NULL || (skb != (struct sk_buff *) -1 && skb->len <= 0)) {
printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
dev->name);
dev_tint(dev);
@@ -842,12 +871,24 @@
entry = tp->cur_tx % TX_RING_SIZE;
tp->tx_full = 1;
+ /*
+ * If skb is == -1, then this is a funky setup_frame redo.
+ */
+ if (skb == (struct sk_buff *) -1) {
+ daddr = virt_to_bus((char *)tp->setup_frame);
+ len = 192;
+ skb = NULL;
+ } else {
+ daddr = virt_to_bus(skb->data);
+ len = skb->len;
+ }
tp->tx_skbuff[entry] = skb;
- tp->tx_ring[entry].length = skb->len |
+ tp->tx_ring[entry].length = len |
(entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000);
- tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+ tp->tx_ring[entry].buffer1 = daddr;
tp->tx_ring[entry].buffer2 = 0;
tp->tx_ring[entry].status = TRING_OWN; /* Pass ownership to the chip. */
+ barrier();
tp->cur_tx++;
@@ -920,7 +961,8 @@
}
/* Free the original skb. */
- dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+ if (lp->tx_skbuff[entry] != NULL)
+ dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
dirty_tx++;
}
@@ -1138,28 +1180,8 @@
*setup_frm++ = eaddrs[2];
} while (++i < 15);
-#ifndef __alpha__
/* Now add this frame to the Tx list. */
- {
- unsigned long flags;
- unsigned int entry;
-
- save_flags(flags); cli();
- entry = tp->cur_tx++ % TX_RING_SIZE;
- tp->dirty_tx++;
- restore_flags(flags);
-
- tp->tx_skbuff[entry] = 0;
- /* Put the setup frame on the Tx list. */
- tp->tx_ring[entry].length = 192 |
- (entry == TX_RING_SIZE-1 ? 0x0a000000 : 0x08000000);
- tp->tx_ring[entry].buffer1 = virt_to_bus((char *)tp->setup_frame);
- tp->tx_ring[entry].buffer2 = 0;
- tp->tx_ring[entry].status = TRING_OWN;
- /* Trigger an immediate transmit demand. */
- tio_write(TPOLL_TRIGGER, CSR1);
- }
-#endif
+ tulip_start_xmit((struct sk_buff *) -1, dev);
}
}
@@ -1299,7 +1321,7 @@
static struct device *tulip_head=NULL;
u_char pci_bus, pci_device_fn, pci_latency, pci_irq;
u_int pci_ioaddr;
- u_short pci_command;
+ u_short pci_command, vendor_id, device_id;
u_int pci_chips[] = {
PCI_DEVICE_ID_DEC_TULIP,
PCI_DEVICE_ID_DEC_TULIP_FAST,
@@ -1307,67 +1329,83 @@
PCI_DEVICE_ID_NONE
};
int num=0, cno;
- int pci_index;
+ static int pci_index = 0;
if (!pcibios_present()) return(-ENODEV);
- for (pci_index = 0; pci_index < 0xff; pci_index++) {
- /* Search for the PCI_DEVICE_ID_DEV_TULIP* chips */
- for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++) {
- if (pcibios_find_device(PCI_VENDOR_ID_DEC,
- pci_chips[cno],
- pci_index, &pci_bus,
- &pci_device_fn) == 0) {
-
- /* get IO address */
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0,
- &pci_ioaddr);
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
- /* get IRQ */
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq);
- dev = init_etherdev(NULL,
- ROUND_UP(sizeof(struct device) +
- sizeof (struct tulip_private) +
- ETHNAMSIZ, 8));
-
- if (dev == NULL) break;
- if (!tulip_head) {
- printk(version);
- tulip_head = dev;
- }
+ for (; pci_index < 0xff; pci_index++) {
+ if (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+ &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+ break;
- /* Get and check the bus-master and latency values. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(" PCI Master Bit has not been set!"
- " Setting...\n");
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER,
- &pci_latency);
- if (pci_latency < 10) {
- printk(" PCI latency timer (CFLT) is"
- " unreasonably low at %d."
- " Setting to 100 clocks.\n", pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 100);
- }
- if (tulip_hwinit(dev, pci_ioaddr, pci_irq,
- pci_chips[cno]) < 0) {
- continue;
- }
- num++;
+ /* get vendor id */
+ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID,
+ &vendor_id);
+ /* get IRQ */
+ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE,
+ &pci_irq);
+
+ /* get device id */
+ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID,
+ &device_id);
+
+ /* get IO address */
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+ &pci_ioaddr);
+
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
+ if (vendor_id != PCI_VENDOR_ID_DEC)
+ continue;
+
+ for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++)
+ if (device_id == pci_chips[cno])
+ break;
+ if (pci_chips[cno] == PCI_DEVICE_ID_NONE) {
+ printk("Unknown Digital PCI ethernet chip type %4.4x detected:"
+ " not configured.\n", device_id);
+ continue;
+ }
+ dev = init_etherdev(NULL, ROUND_UP(sizeof(struct device) +
+ sizeof (struct tulip_private) +
+ ETHNAMSIZ, 8));
+ if (dev == NULL)
+ break;
+
+ if (!tulip_head) {
+ printk(version);
+ tulip_head = dev;
+ }
+
+ /* Get and check the bus-master and latency values. */
+ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND,
+ &pci_command);
+ if ((pci_command & PCI_COMMAND_MASTER) == 0) {
+ printk(" PCI Master Bit has not been set!"
+ " Setting...\n");
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND,
+ pci_command);
+ }
+
+ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER,
+ &pci_latency);
+
+ if (pci_latency < 10) {
+ printk(" PCI latency timer (CFLT) is"
+ " unreasonably low at %d."
+ " Setting to 100 clocks.\n", pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 100);
+ }
+
+ if (tulip_hwinit(dev, pci_ioaddr, pci_irq, pci_chips[cno]) < 0) {
+ continue;
+ }
+ num++;
#ifdef TULIP_MAX_CARDS
- if (num >= TULIP_MAX_CARDS) return(0);
+ if (num >= TULIP_MAX_CARDS) return(0);
#endif
- }
- }
}
return(num > 0 ? 0: -ENODEV);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov