summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /drivers/net
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/.cvsignore1
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c503.c6
-rw-r--r--drivers/net/3c505.c4
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c7
-rw-r--r--drivers/net/3c523.c6
-rw-r--r--drivers/net/3c59x.c167
-rw-r--r--drivers/net/8390.c15
-rw-r--r--drivers/net/CONFIG102
-rw-r--r--drivers/net/Config.in20
-rw-r--r--drivers/net/Makefile121
-rw-r--r--drivers/net/Space.c9
-rw-r--r--drivers/net/a2065.c2
-rw-r--r--drivers/net/ac3200.c2
-rw-r--r--drivers/net/am79c961a.c638
-rw-r--r--drivers/net/am79c961a.h128
-rw-r--r--drivers/net/apricot.c6
-rw-r--r--drivers/net/arc-rimi.c3
-rw-r--r--drivers/net/arcnet.c24
-rw-r--r--drivers/net/ariadne.c2
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atari_bionet.c2
-rw-r--r--drivers/net/atari_pamsnet.c2
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/com20020.c3
-rw-r--r--drivers/net/com90io.c3
-rw-r--r--drivers/net/com90xx.c3
-rw-r--r--drivers/net/cops.c13
-rw-r--r--drivers/net/cs89x0.c5
-rw-r--r--drivers/net/de4x5.c8959
-rw-r--r--drivers/net/de4x5.h35
-rw-r--r--drivers/net/de600.c2
-rw-r--r--drivers/net/de620.c3
-rw-r--r--drivers/net/defxx.c8
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dgrs.c14
-rw-r--r--drivers/net/dlci.c5
-rw-r--r--drivers/net/dmascc.c1260
-rw-r--r--drivers/net/dummy.c18
-rw-r--r--drivers/net/e2100.c4
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c9
-rw-r--r--drivers/net/eexpress.c4
-rw-r--r--drivers/net/eql.c2
-rw-r--r--drivers/net/es3210.c4
-rw-r--r--drivers/net/eth16i.c5
-rw-r--r--drivers/net/ethertap.c233
-rw-r--r--drivers/net/ewrk3.c4
-rw-r--r--drivers/net/fmv18x.c2
-rw-r--r--drivers/net/hamradio/.cvsignore1
-rw-r--r--drivers/net/hamradio/Config.in80
-rw-r--r--drivers/net/hamradio/Makefile8
-rw-r--r--drivers/net/hamradio/baycom_par.c8
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c2
-rw-r--r--drivers/net/hamradio/bpqether.c24
-rw-r--r--drivers/net/hamradio/dmascc.c137
-rw-r--r--drivers/net/hamradio/hdlcdrv.c8
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/pi2.c8
-rw-r--r--drivers/net/hamradio/pt.c6
-rw-r--r--drivers/net/hamradio/scc.c59
-rw-r--r--drivers/net/hamradio/soundmodem/.cvsignore1
-rw-r--r--drivers/net/hamradio/soundmodem/gentbl.c12
-rw-r--r--drivers/net/hamradio/soundmodem/sm.c2
-rw-r--r--drivers/net/hp-plus.c10
-rw-r--r--drivers/net/hp.c7
-rw-r--r--drivers/net/hp100.c6
-rw-r--r--drivers/net/hydra.c2
-rw-r--r--drivers/net/ibmtr.c6
-rw-r--r--drivers/net/ipddp.c228
-rw-r--r--drivers/net/ipddp.h11
-rw-r--r--drivers/net/lance.c10
-rw-r--r--drivers/net/lapbether.c15
-rw-r--r--drivers/net/loopback.c4
-rw-r--r--drivers/net/ltpc.c3
-rw-r--r--drivers/net/mace.c8
-rw-r--r--drivers/net/myri_sbus.c61
-rw-r--r--drivers/net/ne.c21
-rw-r--r--drivers/net/ni5010.c2
-rw-r--r--drivers/net/ni52.c10
-rw-r--r--drivers/net/ni65.c16
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/plip.c128
-rw-r--r--drivers/net/ppp.c2078
-rw-r--r--drivers/net/ppp_deflate.c47
-rw-r--r--drivers/net/sdla.c1
-rw-r--r--drivers/net/sdla_fr.c1725
-rw-r--r--drivers/net/sdla_ppp.c1757
-rw-r--r--drivers/net/sdla_x25.c509
-rw-r--r--drivers/net/sdladrv.c1
-rw-r--r--drivers/net/sdlamain.c39
-rw-r--r--drivers/net/seeq8005.c14
-rw-r--r--drivers/net/sgiseeq.c4
-rw-r--r--drivers/net/shaper.c51
-rw-r--r--drivers/net/sk_g16.c2
-rw-r--r--drivers/net/skeleton.c2
-rw-r--r--drivers/net/slhc.c32
-rw-r--r--drivers/net/slip.c973
-rw-r--r--drivers/net/slip.h3
-rw-r--r--drivers/net/smc-mca.c2
-rw-r--r--drivers/net/smc-ultra.c8
-rw-r--r--drivers/net/smc9194.c6
-rw-r--r--drivers/net/sonic.c4
-rw-r--r--drivers/net/strip.c6
-rw-r--r--drivers/net/sunhme.c10
-rw-r--r--drivers/net/sunlance.c26
-rw-r--r--drivers/net/sunqe.c8
-rw-r--r--drivers/net/tlan.c5
-rw-r--r--drivers/net/tulip.c3087
-rw-r--r--drivers/net/wavelan.c2
-rw-r--r--drivers/net/wd.c4
-rw-r--r--drivers/net/x25_asy.c13
-rw-r--r--drivers/net/zlib.c25
-rw-r--r--drivers/net/zlib.h6
-rw-r--r--drivers/net/znet.c2
118 files changed, 13261 insertions, 9984 deletions
diff --git a/drivers/net/.cvsignore b/drivers/net/.cvsignore
index 4671378ae..857dd22e9 100644
--- a/drivers/net/.cvsignore
+++ b/drivers/net/.cvsignore
@@ -1 +1,2 @@
.depend
+.*.flags
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index d5cb133d6..dd1b4a6ae 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -470,7 +470,7 @@ load_it_again_sam:
if (el_debug > 2)
printk(" queued xmit.\n");
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 228404fc6..a2010a526 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -76,7 +76,7 @@ static int el2_close(struct device *dev);
static void el2_reset_8390(struct device *dev);
static void el2_init_card(struct device *dev);
static void el2_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void el2_block_input(struct device *dev, int count, struct sk_buff *skb,
int ring_offset);
static void el2_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
@@ -432,7 +432,7 @@ el2_init_card(struct device *dev)
*/
static void
el2_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page)
+ const unsigned char *buf, int start_page)
{
unsigned short int *wrd;
int boguscount; /* timeout counter */
@@ -675,10 +675,10 @@ cleanup_module(void)
struct device *dev = &dev_el2[this_dev];
if (dev->priv != NULL) {
/* NB: el2_close() handles free_irq */
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, EL2_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index d645ce165..d28bb2c52 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -698,7 +698,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR),
dev);
if (adapter->current_dma.direction) {
- dev_kfree_skb(adapter->current_dma.skb, FREE_WRITE);
+ dev_kfree_skb(adapter->current_dma.skb);
} else {
struct sk_buff *skb = adapter->current_dma.skb;
if (skb) {
@@ -1694,10 +1694,10 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
struct device *dev = &dev_3c505[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, ELP_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index a331f72d6..f6332d952 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -493,7 +493,7 @@ static int el16_send_packet(struct sk_buff *skb, struct device *dev)
outb(0x84, ioaddr + MISC_CTRL);
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index febe4b514..bb9ee3c30 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -34,7 +34,7 @@ static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n";
#include <linux/module.h>
-#include <linux/config.h>
+#include <linux/config.h> /* for CONFIG_MCA */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -47,7 +47,6 @@ static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n";
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/config.h> /* for CONFIG_MCA */
#include <linux/delay.h> /* for udelay() */
#include <linux/init.h>
@@ -548,7 +547,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct device *dev)
outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* Clear the Tx status stack. */
{
@@ -864,11 +863,11 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) {
struct device *dev = &dev_3c509[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree_s(dev->priv,sizeof(struct el3_private));
dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(dev->base_addr, EL3_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 39750860e..e0f47e712 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1154,7 +1154,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
elmc_attn586();
dev->trans_start = jiffies;
if(!i) {
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
}
WAIT_4_SCB_CMD();
if( (p->scb->status & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
@@ -1179,7 +1179,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
dev->trans_start = jiffies;
p->nop_point = next_nop;
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
# endif
#else
p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
@@ -1201,7 +1201,7 @@ elmc_send_packet(struct sk_buff *skb, struct device *dev)
dev->tbusy = 0;
}
sti();
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
#endif
}
return 0;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 4202f8ef6..7b8f9ec10 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -15,14 +15,14 @@
*/
static char *version =
-"3c59x.c:v0.46B 9/25/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.47H 12/4/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */
-static const rx_copybreak = 200;
+static const int rx_copybreak = 200;
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const mtu = 1500;
+static const int mtu = 1500;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
@@ -44,7 +44,6 @@ static int max_interrupt_work = 20;
#define RX_RING_SIZE 32
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-#include <linux/config.h>
#ifdef MODULE
#ifdef MODVERSIONS
#include <linux/modversions.h>
@@ -89,9 +88,10 @@ static int max_interrupt_work = 20;
#endif
#define virt_to_bus(addr) ((unsigned long)addr)
#define bus_to_virt(addr) ((void*)addr)
+#define NR_IRQS 16
#else /* 1.3.0 and later */
#define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
#endif
#ifdef SA_SHIRQ
@@ -111,8 +111,19 @@ static int max_interrupt_work = 20;
#define udelay(microsec) do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
#endif
-#if (LINUX_VERSION_CODE < 0x20123)
+#if LINUX_VERSION_CODE < 0x20115
#define test_and_set_bit(val, addr) set_bit(val, addr)
+#elif defined(MODULE)
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(compaq_ioaddr, "i");
+MODULE_PARM(compaq_irq, "i");
+MODULE_PARM(compaq_prod_id, "i");
#endif
/* "Knobs" for adjusting internal parameters. */
@@ -147,7 +158,8 @@ static char mii_preamble_required = 0;
/* Caution! These entries must be consistent, with the EISA ones last. */
static const int product_ids[] = {
- 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0};
+ 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0x9055,
+ 0, 0};
static const char *product_names[] = {
"3c590 Vortex 10Mbps",
"3c595 Vortex 100baseTX",
@@ -157,11 +169,12 @@ static const char *product_names[] = {
"3c900 Boomerang 10Mbps/Combo",
"3c905 Boomerang 100baseTx",
"3c905 Boomerang 100baseT4",
+ "3c905B Cyclone 100baseTx",
"3c592 EISA 10mbps Demon/Vortex",
"3c597 EISA Fast Demon/Vortex",
};
-#define DEMON10_INDEX 8
-#define DEMON100_INDEX 9
+#define DEMON10_INDEX 9
+#define DEMON100_INDEX 10
/*
Theory of Operation
@@ -424,7 +437,7 @@ static struct media_table {
static int vortex_scan(struct device *dev);
static struct device *vortex_found_device(struct device *dev, int ioaddr,
- int irq, int product_index,
+ int irq, const char *product_name,
int options, int card_idx);
static int vortex_probe1(struct device *dev);
static int vortex_open(struct device *dev);
@@ -468,14 +481,16 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
/* Note: this is the only limit on the number of cards supported!! */
static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+#ifdef MODULE
static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* A list of all installed Vortex devices, for removing the driver module. */
static struct device *root_vortex_dev = NULL;
+#endif
+#ifdef MODULE
/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0;
+static int compaq_ioaddr = 0, compaq_irq = 0;
-#ifdef MODULE
static int debug = -1;
int
@@ -510,6 +525,7 @@ int tc59x_probe(struct device *dev)
static int vortex_scan(struct device *dev)
{
int cards_found = 0;
+ const char *product_name;
#ifndef NO_PCI /* Allow an EISA-only driver. */
/* Ideally we would detect all cards in slot order. That would
@@ -522,10 +538,10 @@ static int vortex_scan(struct device *dev)
for (;pci_index < 0xff; pci_index++) {
unsigned char pci_irq_line, pci_latency;
- unsigned short pci_command, vendor, device;
+ unsigned short pci_command, new_command, vendor, device;
unsigned int pci_ioaddr;
-
int board_index = 0;
+
if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
pci_index, &pci_bus, &pci_device_fn)
!= PCIBIOS_SUCCESSFUL)
@@ -538,6 +554,8 @@ static int vortex_scan(struct device *dev)
PCI_INTERRUPT_LINE, &pci_irq_line);
pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
@@ -548,7 +566,13 @@ static int vortex_scan(struct device *dev)
if (device == product_ids[board_index])
break;
}
- if (product_ids[board_index] == 0) {
+ if (product_ids[board_index])
+ product_name = product_names[board_index];
+ else if ((device & 0xfff0) == 0x9000)
+ product_name = "3c900";
+ else if ((device & 0xfff0) == 0x9050)
+ product_name = "3c905";
+ else {
printk("Unknown 3Com PCI ethernet adapter type %4.4x detected:"
" not configured.\n", device);
continue;
@@ -556,34 +580,34 @@ static int vortex_scan(struct device *dev)
if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
continue;
+ new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " device! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
+ }
+
dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
- board_index, dev && dev->mem_start
+ product_name, dev && dev->mem_start
? dev->mem_start : options[cards_found],
cards_found);
if (dev) {
- /* Get and check the bus-master and latency values.
- Some PCI BIOSes fail to set the master-enable bit, and
+ /* Get and check the latency values. On the 3c590 series
the latency timer must be set to the maximum value to avoid
data corruption that occurs when the timer expires during
- a transfer -- a bug in the Vortex chip. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk("%s: PCI Master Bit has not been set! "
- " Setting...\n", dev->name);
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
+ a transfer -- a bug in the Vortex chip only. */
+ unsigned char new_latency = (device&0xff00) == 0x5900 ? 248 : 32;
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency != 248) {
+ if (pci_latency < new_latency) {
printk("%s: Overriding PCI latency"
- " timer (CFLT) setting of %d, new value is 248.\n",
- dev->name, pci_latency);
+ " timer (CFLT) setting of %d, new value is %d.\n",
+ dev->name, pci_latency, new_latency);
pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 248);
+ PCI_LATENCY_TIMER, new_latency);
}
dev = 0;
cards_found++;
@@ -596,7 +620,8 @@ static int vortex_scan(struct device *dev)
if (EISA_bus) {
static int ioaddr = 0x1000;
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- int product_id, product_index;
+ int product_id;
+ char *product_name;
if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
continue;
/* Check the standard EISA ID register for an encoded '3Com'. */
@@ -605,13 +630,13 @@ static int vortex_scan(struct device *dev)
/* Check for a product that we support, 3c59{2,7} any rev. */
product_id = inw(ioaddr + 0xC82) & 0xF0FF;
if (product_id == 0x7059) /* 597 */
- product_index = DEMON100_INDEX;
+ product_name = "3c597 EISA Fast Demon/Vortex";
else if (product_id == 0x2059) /* 592 */
- product_index = DEMON10_INDEX;
+ product_name = "3c592 EISA 10mbps Demon/Vortex";
else
continue;
vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- product_index, dev && dev->mem_start
+ product_name, dev && dev->mem_start
? dev->mem_start : options[cards_found],
cards_found);
dev = 0;
@@ -619,24 +644,25 @@ static int vortex_scan(struct device *dev)
}
}
+#ifdef MODULE
/* Special code to work-around the Compaq PCI BIOS32 problem. */
if (compaq_ioaddr) {
- vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id,
+ vortex_found_device(dev, compaq_ioaddr, compaq_irq, "3Com Vortex",
dev && dev->mem_start ? dev->mem_start
: options[cards_found], cards_found);
cards_found++;
dev = 0;
}
+#endif
- /* Finally check for a 3c515 on the ISA bus. */
- /* (3c515 support omitted on this version.) */
+ /* 3c515 cards are now supported by the 3c515.c driver. */
return cards_found;
}
static struct device *
vortex_found_device(struct device *dev, int ioaddr, int irq,
- int product_index, int options, int card_idx)
+ const char *product_name, int options, int card_idx)
{
struct vortex_private *vp;
@@ -654,7 +680,7 @@ vortex_found_device(struct device *dev, int ioaddr, int irq,
dev->base_addr = ioaddr;
dev->irq = irq;
dev->init = vortex_probe1;
- vp->product_name = product_names[product_index];
+ vp->product_name = product_name;
vp->options = options;
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
@@ -687,7 +713,7 @@ vortex_found_device(struct device *dev, int ioaddr, int irq,
dev->mtu = mtu;
vp = (struct vortex_private *)dev->priv;
- vp->product_name = product_names[product_index];
+ vp->product_name = product_name;
vp->options = options;
if (options >= 0) {
vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
@@ -717,7 +743,7 @@ static int vortex_probe1(struct device *dev)
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
for (i = 0; i < 0x18; i++) {
- short *phys_addr = (short *)dev->dev_addr;
+ u16 *phys_addr = (u16 *)dev->dev_addr;
int timer;
outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
@@ -792,7 +818,7 @@ static int vortex_probe1(struct device *dev)
vp->info1 = eeprom[13];
vp->info2 = eeprom[15];
vp->capabilities = eeprom[16];
- if ((vp->capabilities & 0x20) && vp->bus_master) {
+ if (vp->capabilities & 0x20) {
vp->full_bus_master_tx = 1;
printk(" Enabling bus-master transmits and %s receives.\n",
(vp->info2 & 1) ? "early" : "whole-frame" );
@@ -1045,13 +1071,17 @@ vortex_open(struct device *dev)
vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
vp->rx_ring[i].status = 0; /* Clear complete bit. */
vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
- skb = dev_alloc_skb(PKT_BUF_SZ);
+ skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
vp->rx_skbuff[i] = skb;
if (skb == NULL)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE >= 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[i].addr = virt_to_bus(skb->tail);
+#else
+ vp->rx_ring[i].addr = virt_to_bus(skb->data);
+#endif
}
vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
@@ -1248,7 +1278,7 @@ static void vortex_tx_timeout(struct device *dev)
if (vp->tx_skbuff[entry]) {
if (vortex_debug > 0)
printk(" %d\n", entry);
- dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
+ dev_kfree_skb(vp->tx_skbuff[entry]);
vp->tx_skbuff[entry] = 0;
vp->stats.tx_dropped++;
}
@@ -1309,7 +1339,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
} else {
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
if (inw(ioaddr + TxFree) > 1536) {
dev->tbusy = 0;
} else
@@ -1319,7 +1349,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
#else
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
if (inw(ioaddr + TxFree) > 1536) {
dev->tbusy = 0;
} else
@@ -1332,7 +1362,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
/* Clear the Tx status stack. */
{
short tx_status;
- int i = 4;
+ int i = 32;
while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
@@ -1431,9 +1461,10 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
int latency;
int i = max_interrupt_work;
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
+ if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+ printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+ return;
+ }
ioaddr = dev->base_addr;
latency = inb(ioaddr + Timer);
@@ -1495,7 +1526,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
virt_to_bus(&lp->tx_ring[entry]))
break; /* It still hasn't been processed. */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+ dev_kfree_skb(lp->tx_skbuff[entry]);
lp->tx_skbuff[entry] = 0;
}
/* lp->stats.tx_packets++; Counted below. */
@@ -1513,7 +1544,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
if (status & DMADone) {
outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
dev->tbusy = 0;
- dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
+ dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */
mark_bh(NET_BH);
}
#endif
@@ -1560,7 +1591,16 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
dev->name, fifo_diag);
/* Adapter failure requires Tx/Rx reset and reinit. */
- if (fifo_diag & 0x0400) {
+ if (lp->full_bus_master_tx) {
+ int j;
+ outw(TotalReset | 0xff, ioaddr + EL3_CMD);
+ for (j = 200; j >= 0 ; j--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ /* Re-enable the receiver. */
+ outw(RxEnable, ioaddr + EL3_CMD);
+ outw(TxEnable, ioaddr + EL3_CMD);
+ } else if (fifo_diag & 0x0400) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
for (j = 20; j >= 0 ; j--)
@@ -1675,6 +1715,7 @@ boomerang_rx(struct device *dev)
int entry = vp->cur_rx % RX_RING_SIZE;
int ioaddr = dev->base_addr;
int rx_status;
+ int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
if (vortex_debug > 5)
printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
@@ -1704,11 +1745,16 @@ boomerang_rx(struct device *dev)
if (pkt_len < rx_copybreak
&& (skb = DEV_ALLOC_SKB(pkt_len + 2)) != 0) {
skb->dev = dev;
+#if LINUX_VERSION_CODE >= 0x10300
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
memcpy(skb_put(skb, pkt_len),
bus_to_virt(vp->rx_ring[entry].addr),
pkt_len);
+#else
+ memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len);
+ skb->len = pkt_len;
+#endif
rx_copy++;
} else{
void *temp;
@@ -1734,13 +1780,15 @@ boomerang_rx(struct device *dev)
vp->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
+ if (--rx_work_limit < 0)
+ break;
}
/* Refill the Rx ring buffers. */
for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb(PKT_BUF_SZ);
+ skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
if (skb == NULL)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
@@ -1805,7 +1853,7 @@ vortex_close(struct device *dev)
#if LINUX_VERSION_CODE < 0x20100
vp->rx_skbuff[i]->free = 1;
#endif
- dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+ dev_kfree_skb (vp->rx_skbuff[i]);
vp->rx_skbuff[i] = 0;
}
}
@@ -1813,7 +1861,7 @@ vortex_close(struct device *dev)
outl(0, ioaddr + DownListPtr);
for (i = 0; i < TX_RING_SIZE; i++)
if (vp->tx_skbuff[i]) {
- dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+ dev_kfree_skb(vp->tx_skbuff[i]);
vp->tx_skbuff[i] = 0;
}
}
@@ -1914,7 +1962,7 @@ static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
static void
set_rx_mode(struct device *dev)
{
- short ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
short new_mode;
if (dev->flags & IFF_PROMISC) {
@@ -1964,4 +2012,3 @@ cleanup_module(void)
* tab-width: 4
* End:
*/
-
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 597566c24..23bd0883f 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -54,6 +54,8 @@ static const char *version =
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
@@ -185,12 +187,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
/* Mask interrupts from the ethercard. */
outb_p(0x00, e8390_base + EN0_IMR);
+ disable_irq(dev->irq);
synchronize_irq();
if (dev->interrupt) {
printk("%s: Tx request while isr active.\n",dev->name);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
ei_local->stat.tx_errors++;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
ei_local->irqlock = 1;
@@ -226,6 +230,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
ei_local->irqlock = 0;
dev->tbusy = 1;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
ei_local->stat.tx_errors++;
return 1;
}
@@ -272,8 +277,9 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
/* Turn 8390 interrupts back on. */
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ enable_irq(dev->irq);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
ei_local->stat.tx_bytes += send_length;
return 0;
@@ -608,7 +614,6 @@ static void ei_receive(struct device *dev)
static void ei_rx_overrun(struct device *dev)
{
int e8390_base = dev->base_addr;
- unsigned long wait_start_time;
unsigned char was_txing, must_resend = 0;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
@@ -629,9 +634,7 @@ static void ei_rx_overrun(struct device *dev)
* it "is not a reliable indicator and subsequently should be ignored."
* We wait at least 10ms.
*/
- wait_start_time = jiffies;
- while (jiffies - wait_start_time <= 1*HZ/100)
- barrier();
+ udelay(10*1000);
/*
* Reset RBCR[01] back to zero as per magic incantation.
diff --git a/drivers/net/CONFIG b/drivers/net/CONFIG
deleted file mode 100644
index 8ea48df1b..000000000
--- a/drivers/net/CONFIG
+++ /dev/null
@@ -1,102 +0,0 @@
-#
-# This file is used for selecting non-standard netcard options, and
-# need not be modified for typical use.
-#
-# Drivers are *not* selected in this file, but rather with files
-# automatically generated during the top-level kernel configuration.
-#
-# Special options supported, indexed by their 'config' name:
-#
-# CONFIG_WD80x3 The Western Digital (SMC) WD80x3 driver
-# WD_SHMEM=xxx Forces the address of the shared memory
-# CONFIG_NE2000 The NE-[12]000 clone driver.
-# PACKETBUF_MEMSIZE Allows an extra-large packet buffer to be
-# used. Usually pointless under Linux.
-# show_all_SAPROM Show the entire address PROM, not just the
-# ethernet address, during boot.
-# CONFIG_NE_RW_BUGFIX Patch an obscure bug with a version of the 8390.
-# CONFIG_NE_SANITY Double check the internal card xfer address
-# against the driver's value. Useful for debugging.
-# CONFIG_HPLAN The HP-LAN driver (for 8390-based boards only).
-# rw_bugfix Fix the same obscure bug.
-# CONFIG_EL2 The 3c503 EtherLink II driver
-# EL2_AUI Default to the AUI port instead of the BNC port
-# no_probe_nonshared_memory Don't probe for programmed-I/O boards.
-# EL2MEMTEST Test shared memory at boot-time.
-# CONFIG_PLIP The Crynwr-protocol PL/IP driver
-# INITIALTIMEOUTFACTOR Timing parameters.
-# MAXTIMEOUTFACTOR
-# DE600 The D-Link DE-600 Portable Ethernet Adaptor.
-# DE600_IO The DE600 I/O-port address (0x378 == default)
-# DE600_IRQ The DE600 IRQ number to use (IRQ7 == default)
-# DE600_DEBUG Enable or disable DE600 debugging (default off)
-# DE620 The D-Link DE-600 Portable Ethernet Adaptor.
-# DE620_IO The DE620 I/O-port address (0x378 == default)
-# DE620_IRQ The DE620 IRQ number to use (IRQ7 == default)
-# DE620_DEBUG Enable or disable DE600 debugging (default off)
-# DEPCA The DIGITAL series of LANCE based Ethernet Cards
-# (DEPCA, DE100, DE200/1/2, DE210, DE422 (EISA))
-# EWRK3 The DIGITAL series of AT Ethernet Cards (DE203/4/5)
-# EWRK3_DEBUG Set the desired debug level
-#
-# DE4x5 The DIGITAL series of PCI/EISA Ethernet Cards,
-# DE425, DE434, DE435, DE450, DE500
-# DE4X5_DEBUG Set the desired debug level
-# DEC_ONLY Allows driver to work with DIGITAL cards only -
-# see linux/drivers/net/README.de4x5
-# DE4X5_AUTOSENSE (Default) auto media/mode selection
-# If you want at least one board to not autosense then
-# no board can autosense. For a board mix of several
-# types, OR the manual values [eg for a DE500 (100M) with
-# a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(_100Mb|AUI)']
-# For full auto media/mode selection = AUTO
-# For manual TP media selection = TP
-# For manual TP/Nway media selection (DC21041) = TP_NW
-# For manual BNC media selection = BNC
-# For manual AUI media selection = AUI
-# For manual BNC/AUI media selection (DC21040) = BNC_AUI
-# For manual 10Mb/s mode selection (DC21140) = _10Mb
-# For manual 100Mb/s mode selection (DC21140) = _100Mb
-# The DC21040 will default to TP if TP_NW is specified
-# The DC21041 will default to BNC if BNC_AUI is specified
-# DE4X5_DO_MEMCPY Forces the Intels to use memory copies into sk_buffs
-# rather than straight DMA.
-#
-# DEFXX The DIGITAL series of FDDI EISA (DEFEA) and PCI (DEFPA)
-# controllers
-# DEFXX_DEBUG Set the desired debug level
-#
-# TULIP Tulip (dc21040/dc21041/ds21140) driver
-# TULIP_PORT specify default if_port
-# 0: 10TP
-# 1: 100Tx(ds21140)/AUI(dc2104x)
-# 2: BNC(dc2104x)
-# TULIP_FIX_PORT don't change if_port automatically if defined
-# TULIP_MAX_CARDS maximum number of probed card
-#
-
-# The following options exist, but cannot be set in this file.
-# lance.c
-# LANCE_DMA Change the default DMA to other than DMA5.
-# 8390.c
-# NO_PINGPONG Disable ping-pong transmit buffers.
-
-
-# Most drivers also have a *_DEBUG setting that may be adjusted.
-# The 8390 drivers share the EI_DEBUG setting.
-
-# General options for Space.c
-OPTS = # -DETH0_ADDR=0x300 -DETH0_IRQ=11
-
-WD_OPTS = #-DWD_SHMEM=0xDD000
-EL2_OPTS = #-DEL2_AUI
-NE_OPTS =
-HP_OPTS =
-PLIP_OPTS =
-DEPCA_OPTS =
-EWRK3_OPTS =
-DE4X5_OPTS = -DDE4X5_AUTOSENSE=AUTO
-DEFXX_OPTS =
-ELP_OPTS =
-TULIP_OPTS =
-CS89x0_OPTS =
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index f53d758d2..ea97a5bc1 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -15,7 +15,9 @@ fi
tristate 'Dummy net driver support' CONFIG_DUMMY
tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Ethertap network tap' CONFIG_ETHERTAP
+ if [ "$CONFIG_NETLINK" = "y" ]; then
+ tristate 'Ethertap network tap' CONFIG_ETHERTAP
+ fi
fi
#
# Ethernet
@@ -51,6 +53,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
else
tristate 'SMC Ultra support' CONFIG_ULTRA
fi
+ tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32
tristate 'SMC 9194 support' CONFIG_SMC9194
fi
bool 'Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
@@ -137,7 +140,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Dayna firmware support' CONFIG_COPS_DAYNA
bool 'Tangent firmware support' CONFIG_COPS_TANGENT
fi
- dep_tristate 'IP-over-DDP driver support' CONFIG_IPDDP $CONFIG_ATALK
+ tristate 'Appletalk-IP driver support' CONFIG_IPDDP
+ if [ "$CONFIG_IPDDP" != "n" ]; then
+ bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+ bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+ fi
fi
fi
@@ -157,8 +164,11 @@ if [ "$CONFIG_SLIP" != "n" ]; then
bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
fi
-tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
-tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
+if [ "$CONFIG_NET_RADIO" = "y" ]; then
+ tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
+ tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+fi
bool 'Token Ring driver support' CONFIG_TR
if [ "$CONFIG_TR" = "y" ]; then
@@ -175,7 +185,7 @@ if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
bool 'WAN drivers' CONFIG_WAN_DRIVERS
if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS
- if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then
+ if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1
bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index dfdc5327f..5856b0f35 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -3,10 +3,6 @@
# Makefile for the Linux network (ethercard) device drivers.
#
-# This will go away in some future future: hidden configuration files
-# are difficult for users to deal with.
-include CONFIG
-
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) hamradio
@@ -34,7 +30,7 @@ else
ifeq ($(CONFIG_ISDN),m)
ifeq ($(CONFIG_ISDN_PPP),y)
CONFIG_SLHC_MODULE = y
- CONFIG_PPPDEF_BUILTIN = y
+ CONFIG_PPPDEF_MODULE = y
endif
endif
endif
@@ -92,6 +88,22 @@ else
endif
endif
+ifeq ($(CONFIG_ARM_AM79C961A),y)
+L_OBJS += am79c961a.o
+else
+ ifeq ($(CONFIG_ARM_AM79C961A),m)
+ M_OBJS += am79c961a.o
+ endif
+endif
+
+ifeq ($(CONFIG_ARM_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ARM_ETHERH),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
+
ifeq ($(CONFIG_WD80x3),y)
L_OBJS += wd.o
@@ -156,6 +168,16 @@ else
endif
endif
+ifeq ($(CONFIG_ULTRA32),y)
+L_OBJS += smc-ultra32.o
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ULTRA32),m)
+ CONFIG_8390_MODULE = y
+ M_OBJS += smc-ultra32.o
+ endif
+endif
+
ifeq ($(CONFIG_E2100),y)
L_OBJS += e2100.o
CONFIG_8390_BUILTIN = y
@@ -185,8 +207,11 @@ else
endif
endif
+# bsd_comp.o is *always* a module, for some undocumented reason
+# (perhaps licensing).
ifeq ($(CONFIG_PPP),y)
LX_OBJS += ppp.o
+M_OBJS += bsd_comp.o
CONFIG_SLHC_BUILTIN = y
CONFIG_PPPDEF_BUILTIN = y
else
@@ -194,11 +219,8 @@ else
CONFIG_SLHC_MODULE = y
CONFIG_PPPDEF_MODULE = y
MX_OBJS += ppp.o
- endif
-endif
-
-ifdef CONFIG_PPP
M_OBJS += bsd_comp.o
+ endif
endif
ifeq ($(CONFIG_SLIP),y)
@@ -563,9 +585,11 @@ else
endif
# if anything built-in uses ppp_deflate, then build it into the kernel also.
-# If not, but a module uses it, build as a module:
+# If not, but a module uses it, build as a module.
+# ... NO!!! ppp_deflate.o does not work as resident;
+# it works only as a module!
ifdef CONFIG_PPPDEF_BUILTIN
-LX_OBJS += ppp_deflate.o
+MX_OBJS += ppp_deflate.o
else
ifdef CONFIG_PPPDEF_MODULE
MX_OBJS += ppp_deflate.o
@@ -735,80 +759,5 @@ include $(TOPDIR)/Rules.make
clean:
rm -f core *.o *.a *.s
-wd.o: wd.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
-
-3c503.o: 3c503.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $<
-
-3c505.o: 3c505.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(ELP_OPTS) -c $<
-
-de4x5.o: de4x5.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
-
-ewrk3.o: ewrk3.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
-
-depca.o: depca.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
-
-Space.o: Space.c ../../include/linux/autoconf.h CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) -c $<
-
-net_init.o: ../../include/linux/autoconf.h
-
-ne.o: ne.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $<
-
-hp.o: hp.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $<
-
-plip.o: plip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
-
-slip.o: slip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
-
-strip.o: strip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
-
-dummy.o: dummy.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
-
-de600.o: de600.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DE600_OPTS) -c $<
-
-de620.o: de620.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $<
-
-lance.o: lance.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(LANCE_OPTS) -c $<
-
-8390.o: 8390.c 8390.h CONFIG
-
-sdla.o: sdla.c CONFIG
-
-dlci.o: dlci.c CONFIG
-
-sdladrv.o: sdladrv.c CONFIG
-
wanpipe.o: $(WANPIPE_OBJS)
ld -r -o $@ $(WANPIPE_OBJS)
-
-sdlamain.o: sdlamain.c CONFIG
-
-sdla_x25.o: sdla_x25.c CONFIG
-
-sdla_fr.o: sdla_fr.c CONFIG
-
-sdla_ppp.o: sdla_ppp.c CONFIG
-
-dgrs.o: dgrs.c dgrs.h CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
-
-ltpc.o: ltpc.c ltpc.h CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
-
-tulip.o: tulip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(TULIP_OPTS) -c $<
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 81fbe3e46..e5a98378b 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -138,6 +138,9 @@ __initfunc(static int ethif_probe(struct device *dev))
#if defined(CONFIG_MCA)
&& ultramca_probe(dev)
#endif
+#if defined(CONFIG_ULTRA32)
+ && ultra32_probe(dev)
+#endif
#endif
#if defined(CONFIG_SMC9194)
&& smc_init(dev)
@@ -277,6 +280,12 @@ __initfunc(static int ethif_probe(struct device *dev))
#ifdef CONFIG_MIPS_JAZZ_SONIC
&& sonic_probe(dev)
#endif
+#ifdef CONFIG_ARCH_ACORN
+ && acorn_ethif_probe(dev)
+#endif
+#ifdef CONFIG_ARM_AM79C961A
+ && am79c961_probe(dev)
+#endif
&& 1 ) {
return 1; /* -ENODEV or -EAGAIN would be more accurate. */
}
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 66e784b6f..c9d2d5eca 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -630,7 +630,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
/* Kick the lance: transmit now */
ll->rdp = LE_C0_INEA | LE_C0_TDMD;
dev->trans_start = jiffies;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
if (TX_BUFFS_AVAIL)
dev->tbusy = 0;
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 524dc6475..584446c61 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -366,12 +366,12 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
struct device *dev = &dev_ac32[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
/* Someday free_irq may be in ac_close_card() */
free_irq(dev->irq, dev);
release_region(dev->base_addr, AC_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
new file mode 100644
index 000000000..a2e91505e
--- /dev/null
+++ b/drivers/net/am79c961a.c
@@ -0,0 +1,638 @@
+/*
+ * linux/drivers/net/am79c961.c
+ *
+ * Derived from various things including skeleton.c
+ *
+ * R.M.King 1995.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/delay.h>
+
+#define TX_BUFFERS 15
+#define RX_BUFFERS 25
+
+#include "am79c961a.h"
+
+static unsigned int net_debug = NET_DEBUG;
+static void am79c961_setmulticastlist (struct device *dev);
+
+static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n";
+
+static void write_rreg (unsigned long base, unsigned int reg, unsigned short val)
+{
+ __asm__("
+ strh %1, [%2] @ NET_RAP
+ strh %0, [%2, #-4] @ NET_RDP
+ " : : "r" (val), "r" (reg), "r" (0xf0000464));
+}
+
+static inline void
+write_ireg (unsigned long base, unsigned int reg, unsigned short val)
+{
+ __asm__("
+ strh %1, [%2] @ NET_RAP
+ strh %0, [%2, #8] @ NET_RDP
+ " : : "r" (val), "r" (reg), "r" (0xf0000464));
+}
+
+#define am_writeword(dev,off,val)\
+ __asm__("\
+ strh %0, [%1]\
+ " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+
+static inline void am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+{
+ offset = 0xe0000000 + (offset << 1);
+ length = (length + 1) & ~1;
+ if ((int)buf & 2) {
+ __asm__ __volatile__("
+ strh %2, [%0], #4
+ " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ buf += 2;
+ length -= 2;
+ }
+ while (length > 8)
+ {
+ unsigned int tmp, tmp2;
+ __asm__ __volatile__("
+ ldmia %1!, {%2, %3}
+ strh %2, [%0], #4
+ mov %2, %2, lsr #16
+ strh %2, [%0], #4
+ strh %3, [%0], #4
+ mov %3, %3, lsr #16
+ strh %3, [%0], #4
+ " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
+ : "0" (offset), "1" (buf));
+ length -= 8;
+ }
+ while (length > 0) {
+ __asm__ __volatile__("
+ strh %2, [%0], #4
+ " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+ buf += 2;
+ length -= 2;
+ }
+}
+
+static inline unsigned short
+read_rreg (unsigned int base_addr, unsigned int reg)
+{
+ unsigned short v;
+ __asm__("
+ strh %1, [%2] @ NET_RAP
+ ldrh %0, [%2, #-4] @ NET_IDP
+ " : "=r" (v): "r" (reg), "r" (0xf0000464));
+ return v;
+}
+
+static inline unsigned short am_readword (struct device *dev, unsigned long off)
+{
+ unsigned long address = 0xe0000000 + (off << 1);
+ unsigned short val;
+
+ __asm__("
+ ldrh %0, [%1]
+ " : "=r" (val): "r" (address));
+ return val;
+}
+
+static inline void am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length)
+{
+ offset = 0xe0000000 + (offset << 1);
+ length = (length + 1) & ~1;
+ if ((int)buf & 2) {
+ unsigned int tmp;
+ __asm__ __volatile__("
+ ldrh %2, [%0], #4
+ strb %2, [%1], #1
+ mov %2, %2, lsr #8
+ strb %2, [%1], #1
+ " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
+ length -= 2;
+ }
+ while (length > 8) {
+ unsigned int tmp, tmp2, tmp3;
+ __asm__ __volatile__("
+ ldrh %2, [%0], #4
+ ldrh %3, [%0], #4
+ orr %2, %2, %3, lsl #16
+ ldrh %3, [%0], #4
+ ldrh %4, [%0], #4
+ orr %3, %3, %4, lsl #16
+ stmia %1!, {%2, %3}
+ " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
+ : "0" (offset), "1" (buf));
+ length -= 8;
+ }
+ while (length > 0) {
+ unsigned int tmp;
+ __asm__ __volatile__("
+ ldrh %2, [%0], #4
+ strb %2, [%1], #1
+ mov %2, %2, lsr #8
+ strb %2, [%1], #1
+ " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
+ length -= 2;
+ }
+}
+
+/*
+ * From here on is mostly non ARM specific. Watch the fact it knows
+ * the chip can hit all memory (kmalloc).
+ */
+
+static int am79c961_ramtest(struct device *dev, unsigned int val)
+{
+ unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
+ int i, error = 0, errorcount = 0;
+
+ if (!buffer)
+ return 0;
+ memset (buffer, val, 65536);
+ am_writebuffer(dev, 0, buffer, 65536);
+ memset (buffer, val ^ 255, 65536);
+ am_readbuffer(dev, 0, buffer, 65536);
+ for (i = 0; i < 65536; i++) {
+ if (buffer[i] != val && !error) {
+ printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
+ error = 1;
+ errorcount ++;
+ } else if (error && buffer[i] == val) {
+ printk ("%05X\n", i);
+ error = 0;
+ }
+ }
+ if (error)
+ printk ("10000\n");
+ kfree (buffer);
+ return errorcount;
+}
+
+static void am79c961_init_for_open(struct device *dev)
+{
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ unsigned long hdr_addr, first_free_addr;
+ unsigned long flags;
+ unsigned char *p;
+ int i;
+
+ save_flags_cli (flags);
+
+ write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
+ write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
+
+ restore_flags (flags);
+
+ first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
+ hdr_addr = 0;
+
+ priv->rxhead = 0;
+ priv->rxtail = 0;
+ priv->rxhdr = hdr_addr;
+
+ for (i = 0; i < RX_BUFFERS; i++)
+ {
+ priv->rxbuffer[i] = first_free_addr;
+ am_writeword (dev, hdr_addr, first_free_addr);
+ am_writeword (dev, hdr_addr + 2, RMD_OWN);
+ am_writeword (dev, hdr_addr + 4, (-1600));
+ am_writeword (dev, hdr_addr + 6, 0);
+ first_free_addr += 1600;
+ hdr_addr += 8;
+ }
+ priv->txhead = 0;
+ priv->txtail = 0;
+ priv->txhdr = hdr_addr;
+ for (i = 0; i < TX_BUFFERS; i++)
+ {
+ priv->txbuffer[i] = first_free_addr;
+ am_writeword (dev, hdr_addr, first_free_addr);
+ am_writeword (dev, hdr_addr + 2, 0);
+ am_writeword (dev, hdr_addr + 4, 0);
+ am_writeword (dev, hdr_addr + 6, 0);
+ first_free_addr += 1600;
+ hdr_addr += 8;
+ }
+
+ for (i = LADRL; i <= LADRH; i++)
+ write_rreg (dev->base_addr, i, 0);
+
+ for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
+ write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
+
+ i = MODE_PORT0;
+ if (dev->flags & IFF_PROMISC)
+ i |= MODE_PROMISC;
+
+ write_rreg (dev->base_addr, MODE, i);
+ write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
+ write_rreg (dev->base_addr, BASERXH, 0);
+ write_rreg (dev->base_addr, BASETXL, priv->txhdr);
+ write_rreg (dev->base_addr, BASERXH, 0);
+ write_rreg (dev->base_addr, POLLINT, 0);
+ write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
+ write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
+ write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+ write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM);
+ write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
+}
+
+static int am79c961_init(struct device *dev)
+{
+ unsigned long flags;
+
+ am79c961_ramtest(dev, 0x66);
+ am79c961_ramtest(dev, 0x99);
+
+ save_flags_cli (flags);
+
+ write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */
+ write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+ write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+
+ restore_flags (flags);
+
+ return 0;
+}
+
+/*
+ * This is the real probe routine.
+ */
+
+static int am79c961_probe1(struct device *dev)
+{
+ static unsigned version_printed = 0;
+ struct dev_priv *priv;
+ int i;
+
+ if (!dev->priv)
+ {
+ dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL);
+ if (!dev->priv)
+ return -ENOMEM;
+ }
+
+ priv = (struct dev_priv *) dev->priv;
+ memset (priv, 0, sizeof(struct dev_priv));
+
+ /*
+ * The PNP initialisation should have been done by the ether bootp loader.
+ */
+
+ inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */
+
+ udelay (5);
+
+ if (inb (dev->base_addr >> 1) != 0x08 ||
+ inb ((dev->base_addr >> 1) + 1) != 00 ||
+ inb ((dev->base_addr >> 1) + 2) != 0x2b)
+ {
+ kfree (dev->priv);
+ dev->priv = NULL;
+ return -ENODEV;
+ }
+
+ /*
+ * Ok, we've found a valid hw ID
+ */
+
+ if (net_debug && version_printed++ == 0)
+ printk (KERN_INFO "%s", version);
+
+ printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq);
+ request_region (dev->base_addr, 0x18, "am79c961");
+
+ /* Retrive and print the ethernet address. */
+ for (i = 0; i < 6; i++)
+ {
+ dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff;
+ printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+ }
+
+ if (am79c961_init(dev))
+ {
+ kfree (dev->priv);
+ dev->priv = NULL;
+ return -ENODEV;
+ }
+
+ dev->open = am79c961_open;
+ dev->stop = am79c961_close;
+ dev->hard_start_xmit = am79c961_sendpacket;
+ dev->get_stats = am79c961_getstats;
+ dev->set_multicast_list = am79c961_setmulticastlist;
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+ return 0;
+}
+
+int am79c961_probe(struct device *dev)
+{
+ static int initialised = 0;
+
+ if (initialised)
+ return -ENODEV;
+ initialised = 1;
+
+ dev->base_addr = 0x220;
+ dev->irq = 3;
+
+ return am79c961_probe1(dev);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int am79c961_open(struct device *dev)
+{
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+
+ MOD_INC_USE_COUNT;
+
+ memset (&priv->stats, 0, sizeof (priv->stats));
+
+ if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev))
+ return -EAGAIN;
+
+ am79c961_init_for_open(dev);
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ return 0;
+}
+
+/*
+ * The inverse routine to am79c961_open().
+ */
+
+static int am79c961_close(struct device *dev)
+{
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ am79c961_init(dev);
+ free_irq (dev->irq, dev);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * Get the current statistics. This may be called with the card open or
+ * closed.
+ */
+
+static struct enet_statistics *am79c961_getstats (struct device *dev)
+{
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ return &priv->stats;
+}
+
+/*
+ * Set or clear promiscuous/multicast mode filter for this adaptor.
+ *
+ * We don't attempt any packet filtering. The card may have a SEEQ 8004
+ * in which does not have the other ethernet address registers present...
+ */
+
+static void am79c961_setmulticastlist (struct device *dev)
+{
+ unsigned long flags;
+ int i;
+
+ dev->flags &= ~IFF_ALLMULTI;
+
+ i = MODE_PORT0;
+ if (dev->flags & IFF_PROMISC)
+ i |= MODE_PROMISC;
+
+ save_flags_cli (flags);
+ write_rreg (dev->base_addr, MODE, i);
+ restore_flags (flags);
+}
+
+/*
+ * Transmit a packet
+ */
+
+static int am79c961_sendpacket(struct sk_buff *skb, struct device *dev)
+{
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+
+ if (!dev->tbusy)
+ {
+again:
+ if (!test_and_set_bit(0, (void*)&dev->tbusy))
+ {
+ unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned int hdraddr, bufaddr;
+ unsigned long flags;
+
+ hdraddr = priv->txhdr + (priv->txhead << 3);
+ bufaddr = priv->txbuffer[priv->txhead];
+ priv->txhead ++;
+ if (priv->txhead >= TX_BUFFERS)
+ priv->txhead = 0;
+
+ am_writebuffer (dev, bufaddr, skb->data, length);
+ am_writeword (dev, hdraddr + 4, -length);
+ am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+
+ save_flags_cli (flags);
+ write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
+ dev->trans_start = jiffies;
+ restore_flags (flags);
+
+ if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN))
+ dev->tbusy = 0;
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
+ }
+ else
+ {
+ printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
+ return 1;
+ }
+ }
+ else
+ {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name);
+ /* Try to restart the adaptor. */
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ goto again;
+ }
+}
+
+static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *)dev_id;
+ struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ unsigned int status;
+
+#if NET_DEBUG > 1
+ if(net_debug & DEBUG_INT)
+ printk(KERN_DEBUG "am79c961irq: %d ", irq);
+#endif
+
+ dev->interrupt = 1;
+ status = read_rreg (dev->base_addr, CSR0);
+ write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
+
+ if (status & CSR0_RINT) /* Got a packet(s). */
+ am79c961_rx (dev, priv);
+ if (status & CSR0_TINT) /* Packets transmitted */
+ am79c961_tx (dev, priv);
+ if (status & CSR0_MISS)
+ priv->stats.rx_dropped ++;
+
+ dev->interrupt = 0;
+
+#if NET_DEBUG > 1
+ if(net_debug & DEBUG_INT)
+ printk("done\n");
+#endif
+}
+
+/*
+ * If we have a good packet(s), get it/them out of the buffers.
+ */
+
+static void am79c961_rx(struct device *dev, struct dev_priv *priv)
+{
+ unsigned long hdraddr;
+ unsigned long pktaddr;
+
+ do
+ {
+ unsigned long status;
+ struct sk_buff *skb;
+ int len;
+
+ hdraddr = priv->rxhdr + (priv->rxtail << 3);
+ pktaddr = priv->rxbuffer[priv->rxtail];
+
+ status = am_readword (dev, hdraddr + 2);
+ if (status & RMD_OWN) /* do we own it? */
+ break;
+
+ priv->rxtail ++;
+ if (priv->rxtail >= RX_BUFFERS)
+ priv->rxtail = 0;
+
+ if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP))
+ {
+ am_writeword (dev, hdraddr + 2, RMD_OWN);
+ priv->stats.rx_errors ++;
+ if (status & RMD_ERR)
+ {
+ if (status & RMD_FRAM)
+ priv->stats.rx_frame_errors ++;
+ if (status & RMD_CRC)
+ priv->stats.rx_crc_errors ++;
+ }
+ else if (status & RMD_STP)
+ priv->stats.rx_length_errors ++;
+ continue;
+ }
+
+ len = am_readword (dev, hdraddr + 6);
+ skb = dev_alloc_skb (len + 2);
+
+ if (skb) {
+ unsigned char *buf;
+
+ skb->dev = dev;
+ skb_reserve (skb, 2);
+ buf = skb_put (skb, len);
+
+ am_readbuffer (dev, pktaddr, buf, len);
+ am_writeword (dev, hdraddr + 2, RMD_OWN);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx (skb);
+ priv->stats.rx_packets ++;
+ } else {
+ am_writeword (dev, hdraddr + 2, RMD_OWN);
+ printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
+ priv->stats.rx_dropped ++;
+ break;
+ }
+ } while (1);
+}
+
+/*
+ * Update stats for the transmitted packet
+ */
+
+static void am79c961_tx(struct device *dev, struct dev_priv *priv)
+{
+ do {
+ unsigned long hdraddr;
+ unsigned long status;
+
+ hdraddr = priv->txhdr + (priv->txtail << 3);
+ status = am_readword (dev, hdraddr + 2);
+ if (status & TMD_OWN)
+ break;
+
+ priv->txtail ++;
+ if (priv->txtail >= TX_BUFFERS)
+ priv->txtail = 0;
+
+ if (status & TMD_ERR) {
+ unsigned long status2;
+
+ priv->stats.tx_errors ++;
+
+ status2 = am_readword (dev, hdraddr + 6);
+ am_writeword (dev, hdraddr + 6, 0);
+
+ if (status2 & TST_RTRY)
+ priv->stats.collisions += 1;
+ if (status2 & TST_LCOL)
+ priv->stats.tx_window_errors ++;
+ if (status2 & TST_LCAR)
+ priv->stats.tx_carrier_errors ++;
+ if (status2 & TST_UFLO)
+ priv->stats.tx_fifo_errors ++;
+ continue;
+ }
+ priv->stats.tx_packets ++;
+ } while (priv->txtail != priv->txhead);
+
+ dev->tbusy = 0;
+ mark_bh (NET_BH);
+}
+
diff --git a/drivers/net/am79c961a.h b/drivers/net/am79c961a.h
new file mode 100644
index 000000000..4c15f8a8a
--- /dev/null
+++ b/drivers/net/am79c961a.h
@@ -0,0 +1,128 @@
+/*
+ * linux/drivers/net/am79c961.h
+ */
+
+#ifndef _LINUX_am79c961a_H
+#define _LINUX_am79c961a_H
+
+/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
+#define DEBUG_TX 2
+#define DEBUG_RX 4
+#define DEBUG_INT 8
+#define DEBUG_IC 16
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+#define NET_UID 0
+#define NET_RDP 0x10
+#define NET_RAP 0x12
+#define NET_RESET 0x14
+#define NET_IDP 0x16
+
+/*
+ * RAP registers
+ */
+#define CSR0 0
+#define CSR0_INIT 0x0001
+#define CSR0_STRT 0x0002
+#define CSR0_STOP 0x0004
+#define CSR0_TDMD 0x0008
+#define CSR0_TXON 0x0010
+#define CSR0_RXON 0x0020
+#define CSR0_IENA 0x0040
+#define CSR0_INTR 0x0080
+#define CSR0_IDON 0x0100
+#define CSR0_TINT 0x0200
+#define CSR0_RINT 0x0400
+#define CSR0_MERR 0x0800
+#define CSR0_MISS 0x1000
+#define CSR0_CERR 0x2000
+#define CSR0_BABL 0x4000
+#define CSR0_ERR 0x8000
+
+#define CSR3 3
+#define CSR3_EMBA 0x0008
+#define CSR3_DXMT2PD 0x0010
+#define CSR3_LAPPEN 0x0020
+#define CSR3_IDONM 0x0100
+#define CSR3_TINTM 0x0200
+#define CSR3_RINTM 0x0400
+#define CSR3_MERRM 0x0800
+#define CSR3_MISSM 0x1000
+#define CSR3_BABLM 0x4000
+#define CSR3_MASKALL 0x5F00
+
+#define LADRL 8
+#define LADRM1 9
+#define LADRM2 10
+#define LADRH 11
+#define PADRL 12
+#define PADRM 13
+#define PADRH 14
+
+#define MODE 15
+#define MODE_DISRX 0x0001
+#define MODE_DISTX 0x0002
+#define MODE_LOOP 0x0004
+#define MODE_DTCRC 0x0008
+#define MODE_COLL 0x0010
+#define MODE_DRETRY 0x0020
+#define MODE_INTLOOP 0x0040
+#define MODE_PORT0 0x0080
+#define MODE_DRXPA 0x2000
+#define MODE_DRXBA 0x4000
+#define MODE_PROMISC 0x8000
+
+#define BASERXL 24
+#define BASERXH 25
+#define BASETXL 30
+#define BASETXH 31
+
+#define POLLINT 47
+
+#define SIZERXR 76
+#define SIZETXR 78
+
+#define RMD_ENP 0x0100
+#define RMD_STP 0x0200
+#define RMD_CRC 0x0800
+#define RMD_FRAM 0x2000
+#define RMD_ERR 0x4000
+#define RMD_OWN 0x8000
+
+#define TMD_ENP 0x0100
+#define TMD_STP 0x0200
+#define TMD_MORE 0x1000
+#define TMD_ERR 0x4000
+#define TMD_OWN 0x8000
+
+#define TST_RTRY 0x0200
+#define TST_LCAR 0x0400
+#define TST_LCOL 0x1000
+#define TST_UFLO 0x4000
+
+struct dev_priv {
+ struct enet_statistics stats;
+ unsigned long rxbuffer[RX_BUFFERS];
+ unsigned long txbuffer[TX_BUFFERS];
+ unsigned char txhead;
+ unsigned char txtail;
+ unsigned char rxhead;
+ unsigned char rxtail;
+ unsigned long rxhdr;
+ unsigned long txhdr;
+};
+
+extern int am79c961_probe (struct device *dev);
+static int am79c961_probe1 (struct device *dev);
+static int am79c961_open (struct device *dev);
+static int am79c961_sendpacket (struct sk_buff *skb, struct device *dev);
+static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static void am79c961_rx (struct device *dev, struct dev_priv *priv);
+static void am79c961_tx (struct device *dev, struct dev_priv *priv);
+static int am79c961_close (struct device *dev);
+static struct enet_statistics *am79c961_getstats (struct device *dev);
+static void am79c961_setmulticastlist (struct device *dev);
+
+#endif
diff --git a/drivers/net/apricot.c b/drivers/net/apricot.c
index 9ddc79ba7..94188da73 100644
--- a/drivers/net/apricot.c
+++ b/drivers/net/apricot.c
@@ -407,7 +407,7 @@ i596_cleanup_cmd(struct i596_private *lp)
struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
@@ -615,7 +615,7 @@ i596_start_xmit(struct sk_buff *skb, struct device *dev)
printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
lp->stats.tx_dropped++;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
else
{
@@ -790,7 +790,7 @@ i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
if ((ptr->status) & STAT_OK)
{
diff --git a/drivers/net/arc-rimi.c b/drivers/net/arc-rimi.c
index c4ce91c4f..e260d0e58 100644
--- a/drivers/net/arc-rimi.c
+++ b/drivers/net/arc-rimi.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -479,7 +478,7 @@ arcrimi_inthandler(struct device *dev)
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
}
out->skb=NULL;
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index c4c14d1cc..8a731a6e3 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -636,7 +636,7 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
if (lp->outgoing.skb)
{
- dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
+ dev_kfree_skb(lp->outgoing.skb);
lp->stats.tx_dropped++;
}
lp->outgoing.skb=NULL;
@@ -748,7 +748,7 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
/* done right away */
lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
out->skb=NULL;
if (arcnet_go_tx(dev,1))
@@ -797,7 +797,7 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
if (out->skb)
{
lp->stats.tx_bytes += skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
}
out->skb=NULL;
}
@@ -1101,7 +1101,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
lp->aborted_seq=arcsoft->sequence;
- kfree_skb(in->skb,FREE_WRITE);
+ kfree_skb(in->skb);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
in->skb=NULL;
@@ -1198,7 +1198,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
saddr,in->sequence,arcsoft->sequence,
arcsoft->split_flag);
- kfree_skb(in->skb,FREE_WRITE);
+ kfree_skb(in->skb);
in->skb=NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
@@ -1216,7 +1216,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
arcsoft->sequence);
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
- kfree_skb(in->skb,FREE_WRITE);
+ kfree_skb(in->skb);
}
in->sequence=arcsoft->sequence;
@@ -1288,7 +1288,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
lp->aborted_seq=arcsoft->sequence;
- kfree_skb(in->skb,FREE_WRITE);
+ kfree_skb(in->skb);
in->skb=NULL;
lp->stats.rx_errors++;
lp->stats.rx_missed_errors++;
@@ -1434,7 +1434,9 @@ static int arcnetA_rebuild_header(struct sk_buff *skb)
struct ClientData *head = (struct ClientData *)skb->data;
struct device *dev=skb->dev;
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
+#ifdef CONFIG_INET
int status;
+#endif
/*
* Only ARP and IP are currently supported
@@ -1583,7 +1585,7 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
length);
BUGMSG(D_NORMAL,"transmit aborted.\n");
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
lp->intx--;
return 0;
}
@@ -1613,7 +1615,7 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
(*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0,
offset);
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
if (arcnet_go_tx(dev,1))
{
@@ -1740,7 +1742,7 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
hdr->daddr,0,0);
/* done right away */
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
if (arcnet_go_tx(dev,1))
{
@@ -1752,7 +1754,7 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
{
BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
length);
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
lp->stats.tx_dropped++;
arcnet_tx_done(lp->adev, lp);
}
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 667bd75fc..232b714a8 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -655,7 +655,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1&0xff00)|TF_OWN|TF_STP|TF_ENP;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
priv->cur_tx++;
if ((priv->cur_tx >= TX_RING_SIZE) && (priv->dirty_tx >= TX_RING_SIZE)) {
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 19b0dc7ed..3751b4336 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -424,7 +424,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Turn on Tx interrupts back on. */
outb(0x82, ioaddr + TX_INTR);
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index dc761ab7c..23c8054e3 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -465,7 +465,7 @@ bionet_send_packet(struct sk_buff *skb, struct device *dev) {
lp->stats.tx_packets++;
lp->stats.tx_bytes+=length;
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index bcf91beda..794b4e4d5 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -730,7 +730,7 @@ pamsnet_send_packet(struct sk_buff *skb, struct device *dev) {
lp->stats.tx_packets++;
lp->stats.tx_bytes+=length;
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 3d7b5d288..c79fd581e 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -817,8 +817,9 @@ static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
head->misc = 0;
lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
- dev_kfree_skb( skb, FREE_WRITE );
+ dev_kfree_skb( skb );
lp->cur_tx++;
+ lp->stats.tx_bytes += skb->len;
while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
lp->cur_tx -= TX_RING_SIZE;
lp->dirty_tx -= TX_RING_SIZE;
@@ -1027,6 +1028,7 @@ static int lance_rx( struct device *dev )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
}
}
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 578a5253a..0e5b92b7f 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -467,7 +467,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
write_reg_high(ioaddr, IMR, ISRh_RxErr);
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/com20020.c b/drivers/net/com20020.c
index cd02f0035..5c9ac32ab 100644
--- a/drivers/net/com20020.c
+++ b/drivers/net/com20020.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -720,7 +719,7 @@ arc20020_inthandler(struct device *dev)
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
}
out->skb=NULL;
diff --git a/drivers/net/com90io.c b/drivers/net/com90io.c
index bb88552b1..46f5d6f2e 100644
--- a/drivers/net/com90io.c
+++ b/drivers/net/com90io.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -611,7 +610,7 @@ arc90io_inthandler(struct device *dev)
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
}
out->skb=NULL;
diff --git a/drivers/net/com90xx.c b/drivers/net/com90xx.c
index 4a5b0d70c..659eb7ad9 100644
--- a/drivers/net/com90xx.c
+++ b/drivers/net/com90xx.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -886,7 +885,7 @@ arc90xx_inthandler(struct device *dev)
if (out->skb)
{
lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
+ dev_kfree_skb(out->skb);
}
out->skb=NULL;
diff --git a/drivers/net/cops.c b/drivers/net/cops.c
index 2560139b9..1231d6b36 100644
--- a/drivers/net/cops.c
+++ b/drivers/net/cops.c
@@ -47,7 +47,6 @@ static const char *version =
#include <linux/version.h>
#endif
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -114,8 +113,8 @@ static int irq = 0; /* Default IRQ */
* the same and just have different names or only have minor differences
* such as more IO ports. As this driver is tested it will
* become more clear on exactly what cards are supported. The driver
- * defaults to using Dayna mode. To change the drivers mode adjust
- * drivers/net/CONFIG, and the line COPS_OPTS = -DDAYNA to -DTANGENT.
+ * defaults to using Dayna mode. To change the drivers mode, simply
+ * select Dayna or Tangent mode when configuring the kernel.
*
* This driver should support:
* TANGENT driver mode:
@@ -747,7 +746,7 @@ static void cops_rx(struct device *dev)
{
printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len);
lp->stats.tx_errors++;
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return;
}
@@ -755,7 +754,7 @@ static void cops_rx(struct device *dev)
if(rsp_type == LAP_INIT_RSP)
{
lp->node_acquire = skb->data[0]; /* Nodeid taken from received packet. */
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return;
}
@@ -764,7 +763,7 @@ static void cops_rx(struct device *dev)
{
printk("%s: Bad packet type %d.\n", dev->name, rsp_type);
lp->stats.tx_errors++;
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return;
}
@@ -856,7 +855,7 @@ static int cops_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
dev->tbusy = 0;
return 0;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 14224bff0..e83c8faf9 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -44,7 +44,6 @@ static char *version =
/* Always include 'config.h' first in case the user wants to turn on
or override something. */
-#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
@@ -782,7 +781,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
restore_flags(flags);
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
@@ -1078,11 +1077,11 @@ cleanup_module(void)
if (dev_cs89x0.priv != NULL) {
/* Free up the private structure, or leak memory :-) */
+ unregister_netdev(&dev_cs89x0);
kfree(dev_cs89x0.priv);
dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */
/* If we don't do this, we can't re-insmod it later. */
release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT);
- unregister_netdev(&dev_cs89x0);
}
}
#endif /* MODULE */
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 246355b2e..ed2652b96 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -1,45 +1,45 @@
/* de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500
- ethernet driver for Linux.
+ ethernet driver for Linux.
- Copyright 1994, 1995 Digital Equipment Corporation.
+ Copyright 1994, 1995 Digital Equipment Corporation.
- Testing resources for this driver have been made available
- in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
+ Testing resources for this driver have been made available
+ in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
- The author may be reached at davies@maniac.ultranet.com.
+ The author may be reached at davies@maniac.ultranet.com.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 675 Mass Ave, Cambridge, MA 02139, USA.
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 675 Mass Ave, Cambridge, MA 02139, USA.
- Originally, this driver was written for the Digital Equipment
- Corporation series of EtherWORKS ethernet cards:
+ Originally, this driver was written for the Digital Equipment
+ Corporation series of EtherWORKS ethernet cards:
- DE425 TP/COAX EISA
- DE434 TP PCI
- DE435 TP/COAX/AUI PCI
- DE450 TP/COAX/AUI PCI
- DE500 10/100 PCI Fasternet
+ DE425 TP/COAX EISA
+ DE434 TP PCI
+ DE435 TP/COAX/AUI PCI
+ DE450 TP/COAX/AUI PCI
+ DE500 10/100 PCI Fasternet
- but it will now attempt to support all cards which conform to the
- Digital Semiconductor SROM Specification. The driver currently
- recognises the following chips:
+ but it will now attempt to support all cards which conform to the
+ Digital Semiconductor SROM Specification. The driver currently
+ recognises the following chips:
DC21040 (no SROM)
DC21041[A]
@@ -49,136 +49,136 @@
So far the driver is known to work with the following cards:
- KINGSTON
- Linksys
- ZNYX342
- SMC8432
- SMC9332 (w/new SROM)
- ZNYX31[45]
- ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
-
- The driver has been tested on a relatively busy network using the DE425,
- DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
- 16M of data to a DECstation 5000/200 as follows:
-
- TCP UDP
- TX RX TX RX
- DE425 1030k 997k 1170k 1128k
- DE434 1063k 995k 1170k 1125k
- DE435 1063k 995k 1170k 1125k
- DE500 1063k 998k 1170k 1125k in 10Mb/s mode
-
- All values are typical (in kBytes/sec) from a sample of 4 for each
- measurement. Their error is +/-20k on a quiet (private) network and also
- depend on what load the CPU has.
-
- =========================================================================
- This driver has been written substantially from scratch, although its
- inheritance of style and stack interface from 'ewrk3.c' and in turn from
- Donald Becker's 'lance.c' should be obvious. With the module autoload of
- every usable DECchip board, I pinched Donald's 'next_module' field to
- link my modules together.
-
- Upto 15 EISA cards can be supported under this driver, limited primarily
- by the available IRQ lines. I have checked different configurations of
- multiple depca, EtherWORKS 3 cards and de4x5 cards and have not found a
- problem yet (provided you have at least depca.c v0.38) ...
-
- PCI support has been added to allow the driver to work with the DE434,
- DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due
- to the differences in the EISA and PCI CSR address offsets from the base
- address.
-
- The ability to load this driver as a loadable module has been included
- and used extensively during the driver development (to save those long
- reboot sequences). Loadable module support under PCI and EISA has been
- achieved by letting the driver autoprobe as if it were compiled into the
- kernel. Do make sure you're not sharing interrupts with anything that
- cannot accommodate interrupt sharing!
-
- To utilise this ability, you have to do 8 things:
-
- 0) have a copy of the loadable modules code installed on your system.
- 1) copy de4x5.c from the /linux/drivers/net directory to your favourite
- temporary directory.
- 2) for fixed autoprobes (not recommended), edit the source code near
- line 5539 to reflect the I/O address you're using, or assign these when
- loading by:
-
- insmod de4x5 io=0xghh where g = bus number
- hh = device number
-
- NB: autoprobing for modules is now supported by default. You may just
- use:
-
- insmod de4x5
-
- to load all available boards. For a specific board, still use
- the 'io=?' above.
- 3) compile de4x5.c, but include -DMODULE in the command line to ensure
- that the correct bits are compiled (see end of source code).
- 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
- kernel with the de4x5 configuration turned off and reboot.
- 5) insmod de4x5 [io=0xghh]
- 6) run the net startup bits for your new eth?? interface(s) manually
- (usually /etc/rc.inet[12] at boot time).
- 7) enjoy!
-
- To unload a module, turn off the associated interface(s)
- 'ifconfig eth?? down' then 'rmmod de4x5'.
-
- Automedia detection is included so that in principal you can disconnect
- from, e.g. TP, reconnect to BNC and things will still work (after a
- pause whilst the driver figures out where its media went). My tests
- using ping showed that it appears to work....
-
- By default, the driver will now autodetect any DECchip based card.
- Should you have a need to restrict the driver to DIGITAL only cards, you
- can compile with a DEC_ONLY define, or if loading as a module, use the
- 'dec_only=1' parameter.
-
- I've changed the timing routines to use the kernel timer and scheduling
- functions so that the hangs and other assorted problems that occurred
- while autosensing the media should be gone. A bonus for the DC21040
- auto media sense algorithm is that it can now use one that is more in
- line with the rest (the DC21040 chip doesn't have a hardware timer).
- The downside is the 1 'jiffies' (10ms) resolution.
-
- IEEE 802.3u MII interface code has been added in anticipation that some
- products may use it in the future.
-
- The SMC9332 card has a non-compliant SROM which needs fixing - I have
- patched this driver to detect it because the SROM format used complies
- to a previous DEC-STD format.
-
- I have removed the buffer copies needed for receive on Intels. I cannot
- remove them for Alphas since the Tulip hardware only does longword
- aligned DMA transfers and the Alphas get alignment traps with non
- longword aligned data copies (which makes them really slow). No comment.
-
- I have added SROM decoding routines to make this driver work with any
- card that supports the Digital Semiconductor SROM spec. This will help
- all cards running the dc2114x series chips in particular. Cards using
- the dc2104x chips should run correctly with the basic driver. I'm in
- debt to <mjacob@feral.com> for the testing and feedback that helped get
- this feature working. So far we have tested KINGSTON, SMC8432, SMC9332
- (with the latest SROM complying with the SROM spec V3: their first was
- broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315
- (quad 21041 MAC) cards also appear to work despite their incorrectly
- wired IRQs.
-
- I have added a temporary fix for interrupt problems when some SCSI cards
- share the same interrupt as the DECchip based cards. The problem occurs
- because the SCSI card wants to grab the interrupt as a fast interrupt
- (runs the service routine with interrupts turned off) vs. this card
- which really needs to run the service routine with interrupts turned on.
- This driver will now add the interrupt service routine as a fast
- interrupt if it is bounced from the slow interrupt. THIS IS NOT A
- RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time
- until people sort out their compatibility issues and the kernel
- interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST
- INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
- run on the same interrupt. PCMCIA/CardBus is another can of worms...
+ KINGSTON
+ Linksys
+ ZNYX342
+ SMC8432
+ SMC9332 (w/new SROM)
+ ZNYX31[45]
+ ZNYX346 10/100 4 port (can act as a 10/100 bridge!)
+
+ The driver has been tested on a relatively busy network using the DE425,
+ DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
+ 16M of data to a DECstation 5000/200 as follows:
+
+ TCP UDP
+ TX RX TX RX
+ DE425 1030k 997k 1170k 1128k
+ DE434 1063k 995k 1170k 1125k
+ DE435 1063k 995k 1170k 1125k
+ DE500 1063k 998k 1170k 1125k in 10Mb/s mode
+
+ All values are typical (in kBytes/sec) from a sample of 4 for each
+ measurement. Their error is +/-20k on a quiet (private) network and also
+ depend on what load the CPU has.
+
+ =========================================================================
+ This driver has been written substantially from scratch, although its
+ inheritance of style and stack interface from 'ewrk3.c' and in turn from
+ Donald Becker's 'lance.c' should be obvious. With the module autoload of
+ every usable DECchip board, I pinched Donald's 'next_module' field to
+ link my modules together.
+
+ Upto 15 EISA cards can be supported under this driver, limited primarily
+ by the available IRQ lines. I have checked different configurations of
+ multiple depca, EtherWORKS 3 cards and de4x5 cards and have not found a
+ problem yet (provided you have at least depca.c v0.38) ...
+
+ PCI support has been added to allow the driver to work with the DE434,
+ DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due
+ to the differences in the EISA and PCI CSR address offsets from the base
+ address.
+
+ The ability to load this driver as a loadable module has been included
+ and used extensively during the driver development (to save those long
+ reboot sequences). Loadable module support under PCI and EISA has been
+ achieved by letting the driver autoprobe as if it were compiled into the
+ kernel. Do make sure you're not sharing interrupts with anything that
+ cannot accommodate interrupt sharing!
+
+ To utilise this ability, you have to do 8 things:
+
+ 0) have a copy of the loadable modules code installed on your system.
+ 1) copy de4x5.c from the /linux/drivers/net directory to your favourite
+ temporary directory.
+ 2) for fixed autoprobes (not recommended), edit the source code near
+ line 5594 to reflect the I/O address you're using, or assign these when
+ loading by:
+
+ insmod de4x5 io=0xghh where g = bus number
+ hh = device number
+
+ NB: autoprobing for modules is now supported by default. You may just
+ use:
+
+ insmod de4x5
+
+ to load all available boards. For a specific board, still use
+ the 'io=?' above.
+ 3) compile de4x5.c, but include -DMODULE in the command line to ensure
+ that the correct bits are compiled (see end of source code).
+ 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
+ kernel with the de4x5 configuration turned off and reboot.
+ 5) insmod de4x5 [io=0xghh]
+ 6) run the net startup bits for your new eth?? interface(s) manually
+ (usually /etc/rc.inet[12] at boot time).
+ 7) enjoy!
+
+ To unload a module, turn off the associated interface(s)
+ 'ifconfig eth?? down' then 'rmmod de4x5'.
+
+ Automedia detection is included so that in principal you can disconnect
+ from, e.g. TP, reconnect to BNC and things will still work (after a
+ pause whilst the driver figures out where its media went). My tests
+ using ping showed that it appears to work....
+
+ By default, the driver will now autodetect any DECchip based card.
+ Should you have a need to restrict the driver to DIGITAL only cards, you
+ can compile with a DEC_ONLY define, or if loading as a module, use the
+ 'dec_only=1' parameter.
+
+ I've changed the timing routines to use the kernel timer and scheduling
+ functions so that the hangs and other assorted problems that occurred
+ while autosensing the media should be gone. A bonus for the DC21040
+ auto media sense algorithm is that it can now use one that is more in
+ line with the rest (the DC21040 chip doesn't have a hardware timer).
+ The downside is the 1 'jiffies' (10ms) resolution.
+
+ IEEE 802.3u MII interface code has been added in anticipation that some
+ products may use it in the future.
+
+ The SMC9332 card has a non-compliant SROM which needs fixing - I have
+ patched this driver to detect it because the SROM format used complies
+ to a previous DEC-STD format.
+
+ I have removed the buffer copies needed for receive on Intels. I cannot
+ remove them for Alphas since the Tulip hardware only does longword
+ aligned DMA transfers and the Alphas get alignment traps with non
+ longword aligned data copies (which makes them really slow). No comment.
+
+ I have added SROM decoding routines to make this driver work with any
+ card that supports the Digital Semiconductor SROM spec. This will help
+ all cards running the dc2114x series chips in particular. Cards using
+ the dc2104x chips should run correctly with the basic driver. I'm in
+ debt to <mjacob@feral.com> for the testing and feedback that helped get
+ this feature working. So far we have tested KINGSTON, SMC8432, SMC9332
+ (with the latest SROM complying with the SROM spec V3: their first was
+ broken), ZNYX342 and LinkSys. ZYNX314 (dual 21041 MAC) and ZNYX 315
+ (quad 21041 MAC) cards also appear to work despite their incorrectly
+ wired IRQs.
+
+ I have added a temporary fix for interrupt problems when some SCSI cards
+ share the same interrupt as the DECchip based cards. The problem occurs
+ because the SCSI card wants to grab the interrupt as a fast interrupt
+ (runs the service routine with interrupts turned off) vs. this card
+ which really needs to run the service routine with interrupts turned on.
+ This driver will now add the interrupt service routine as a fast
+ interrupt if it is bounced from the slow interrupt. THIS IS NOT A
+ RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time
+ until people sort out their compatibility issues and the kernel
+ interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST
+ INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+ run on the same interrupt. PCMCIA/CardBus is another can of worms...
Finally, I think I have really fixed the module loading problem with
more than one DECchip based card. As a side effect, I don't mess with
@@ -188,137 +188,163 @@
is the preferred way to use this driver, since it doesn't have this
limitation.
- Where SROM media detection is used and full duplex is specified in the
- SROM, the feature is ignored unless de4x5_full_duplex is set at compile
- time OR during a module load (insmod de4x5 de4x5_full_duplex=1). This
- is because there is no way to automatically detect full duplex links
- except through autonegotiation. When I include the autonegotiation
- feature in the SROM autoconf code, this detection will occur
- automatically.
+ Where SROM media detection is used and full duplex is specified in the
+ SROM, the feature is ignored unless lp->params.fdx is set at compile
+ time OR during a module load (insmod de4x5 args='eth??:fdx' [see
+ below]). This is because there is no way to automatically detect full
+ duplex links except through autonegotiation. When I include the
+ autonegotiation feature in the SROM autoconf code, this detection will
+ occur automatically for that case.
- TO DO:
- ------
+ Command line arguments are now allowed, similar to passing arguments
+ through LILO. This will allow a per adapter board set up of full duplex
+ and media. The only lexical constraints are: the board name (dev->name)
+ appears in the list before its parameters. The list of parameters ends
+ either at the end of the parameter list or with another board name. The
+ following parameters are allowed:
+
+ fdx for full duplex
+ autosense to set the media/speed; with the following
+ sub-parameters:
+ TP, TP_NW, BNC, AUI, BNC_AUI, 100Mb, 10Mb, AUTO
+
+ Case sensitivity is important for the sub-parameters. They *must* be
+ upper case. Examples:
+
+ insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+
+ For a compiled in driver, somewhere in this file, place e.g.
+ #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
+
+ Yes, I know full duplex isn't permissible on BNC or AUI; they're just
+ examples. By default, full duplex is turned off and AUTO is the default
+ autosense setting. In reality, I expect only the full duplex option to
+ be used. Note the use of single quotes in the two examples above and the
+ lack of commas to separate items.
+
+ TO DO:
+ ------
o check what revision numbers the 21142 and 21143 have
o
- Revision History
- ----------------
-
- Version Date Description
-
- 0.1 17-Nov-94 Initial writing. ALPHA code release.
- 0.2 13-Jan-95 Added PCI support for DE435's.
- 0.21 19-Jan-95 Added auto media detection.
- 0.22 10-Feb-95 Fix interrupt handler call <chris@cosy.sbg.ac.at>.
- Fix recognition bug reported by <bkm@star.rl.ac.uk>.
- Add request/release_region code.
- Add loadable modules support for PCI.
- Clean up loadable modules support.
- 0.23 28-Feb-95 Added DC21041 and DC21140 support.
- Fix missed frame counter value and initialisation.
- Fixed EISA probe.
- 0.24 11-Apr-95 Change delay routine to use <linux/udelay>.
- Change TX_BUFFS_AVAIL macro.
- Change media autodetection to allow manual setting.
- Completed DE500 (DC21140) support.
- 0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm.
- 0.242 10-May-95 Minor changes.
- 0.30 12-Jun-95 Timer fix for DC21140.
- Portability changes.
- Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
- Add DE500 semi automatic autosense.
- Add Link Fail interrupt TP failure detection.
- Add timer based link change detection.
- Plugged a memory leak in de4x5_queue_pkt().
- 0.31 13-Jun-95 Fixed PCI stuff for 1.3.1.
- 0.32 26-Jun-95 Added verify_area() calls in de4x5_ioctl() from a
- suggestion by <heiko@colossus.escape.de>.
- 0.33 8-Aug-95 Add shared interrupt support (not released yet).
- 0.331 21-Aug-95 Fix de4x5_open() with fast CPUs.
- Fix de4x5_interrupt().
- Fix dc21140_autoconf() mess.
- No shared interrupt support.
- 0.332 11-Sep-95 Added MII management interface routines.
- 0.40 5-Mar-96 Fix setup frame timeout <maartenb@hpkuipc.cern.ch>.
- Add kernel timer code (h/w is too flaky).
- Add MII based PHY autosense.
- Add new multicasting code.
- Add new autosense algorithms for media/mode
- selection using kernel scheduling/timing.
- Re-formatted.
- Made changes suggested by <jeff@router.patch.net>:
- Change driver to detect all DECchip based cards
- with DEC_ONLY restriction a special case.
- Changed driver to autoprobe as a module. No irq
- checking is done now - assume BIOS is good!
- Added SMC9332 detection <manabe@Roy.dsl.tutics.ac.jp>
- 0.41 21-Mar-96 Don't check for get_hw_addr checksum unless DEC card
- only <niles@axp745gsfc.nasa.gov>
- Fix for multiple PCI cards reported by <jos@xos.nl>
- Duh, put the SA_SHIRQ flag into request_interrupt().
- Fix SMC ethernet address in enet_det[].
- Print chip name instead of "UNKNOWN" during boot.
- 0.42 26-Apr-96 Fix MII write TA bit error.
- Fix bug in dc21040 and dc21041 autosense code.
- Remove buffer copies on receive for Intels.
- Change sk_buff handling during media disconnects to
- eliminate DUP packets.
- Add dynamic TX thresholding.
- Change all chips to use perfect multicast filtering.
- Fix alloc_device() bug <jari@markkus2.fimr.fi>
- 0.43 21-Jun-96 Fix unconnected media TX retry bug.
- Add Accton to the list of broken cards.
- Fix TX under-run bug for non DC21140 chips.
- Fix boot command probe bug in alloc_device() as
- reported by <koen.gadeyne@barco.com> and
- <orava@nether.tky.hut.fi>.
- Add cache locks to prevent a race condition as
- reported by <csd@microplex.com> and
- <baba@beckman.uiuc.edu>.
- Upgraded alloc_device() code.
- 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion
- with <csd@microplex.com>
- 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips.
- Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
- and <michael@compurex.com>.
- 0.441 9-Sep-96 Change dc21041_autoconf() to probe quiet BNC media
- with a loopback packet.
- 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported
- by <bhat@mundook.cs.mu.OZ.AU>
- 0.45 8-Dec-96 Include endian functions for PPC use, from work
- by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
- 0.451 28-Dec-96 Added fix to allow autoprobe for modules after
- suggestion from <mjacob@feral.com>.
- 0.5 30-Jan-97 Added SROM decoding functions.
- Updated debug flags.
- Fix sleep/wakeup calls for PCI cards, bug reported
- by <cross@gweep.lkg.dec.com>.
- Added multi-MAC, one SROM feature from discussion
- with <mjacob@feral.com>.
- Added full module autoprobe capability.
- Added attempt to use an SMC9332 with broken SROM.
- Added fix for ZYNX multi-mac cards that didn't
- get their IRQs wired correctly.
- 0.51 13-Feb-97 Added endian fixes for the SROM accesses from
- <paubert@iram.es>
- Fix init_connection() to remove extra device reset.
- Fix MAC/PHY reset ordering in dc21140m_autoconf().
- Fix initialisation problem with lp->timeout in
- typeX_infoblock() from <paubert@iram.es>.
- Fix MII PHY reset problem from work done by
- <paubert@iram.es>.
- 0.52 26-Apr-97 Some changes may not credit the right people -
- a disk crash meant I lost some mail.
- Change RX interrupt routine to drop rather than
- defer packets to avoid hang reported by
- <g.thomas@opengroup.org>.
- Fix srom_exec() to return for COMPACT and type 1
- infoblocks.
- Added DC21142 and DC21143 functions.
- Added byte counters from <phil@tazenda.demon.co.uk>
- Added SA_INTERRUPT temporary fix from
- <mjacob@feral.com>.
+ Revision History
+ ----------------
+
+ Version Date Description
+
+ 0.1 17-Nov-94 Initial writing. ALPHA code release.
+ 0.2 13-Jan-95 Added PCI support for DE435's.
+ 0.21 19-Jan-95 Added auto media detection.
+ 0.22 10-Feb-95 Fix interrupt handler call <chris@cosy.sbg.ac.at>.
+ Fix recognition bug reported by <bkm@star.rl.ac.uk>.
+ Add request/release_region code.
+ Add loadable modules support for PCI.
+ Clean up loadable modules support.
+ 0.23 28-Feb-95 Added DC21041 and DC21140 support.
+ Fix missed frame counter value and initialisation.
+ Fixed EISA probe.
+ 0.24 11-Apr-95 Change delay routine to use <linux/udelay>.
+ Change TX_BUFFS_AVAIL macro.
+ Change media autodetection to allow manual setting.
+ Completed DE500 (DC21140) support.
+ 0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm.
+ 0.242 10-May-95 Minor changes.
+ 0.30 12-Jun-95 Timer fix for DC21140.
+ Portability changes.
+ Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
+ Add DE500 semi automatic autosense.
+ Add Link Fail interrupt TP failure detection.
+ Add timer based link change detection.
+ Plugged a memory leak in de4x5_queue_pkt().
+ 0.31 13-Jun-95 Fixed PCI stuff for 1.3.1.
+ 0.32 26-Jun-95 Added verify_area() calls in de4x5_ioctl() from a
+ suggestion by <heiko@colossus.escape.de>.
+ 0.33 8-Aug-95 Add shared interrupt support (not released yet).
+ 0.331 21-Aug-95 Fix de4x5_open() with fast CPUs.
+ Fix de4x5_interrupt().
+ Fix dc21140_autoconf() mess.
+ No shared interrupt support.
+ 0.332 11-Sep-95 Added MII management interface routines.
+ 0.40 5-Mar-96 Fix setup frame timeout <maartenb@hpkuipc.cern.ch>.
+ Add kernel timer code (h/w is too flaky).
+ Add MII based PHY autosense.
+ Add new multicasting code.
+ Add new autosense algorithms for media/mode
+ selection using kernel scheduling/timing.
+ Re-formatted.
+ Made changes suggested by <jeff@router.patch.net>:
+ Change driver to detect all DECchip based cards
+ with DEC_ONLY restriction a special case.
+ Changed driver to autoprobe as a module. No irq
+ checking is done now - assume BIOS is good!
+ Added SMC9332 detection <manabe@Roy.dsl.tutics.ac.jp>
+ 0.41 21-Mar-96 Don't check for get_hw_addr checksum unless DEC card
+ only <niles@axp745gsfc.nasa.gov>
+ Fix for multiple PCI cards reported by <jos@xos.nl>
+ Duh, put the SA_SHIRQ flag into request_interrupt().
+ Fix SMC ethernet address in enet_det[].
+ Print chip name instead of "UNKNOWN" during boot.
+ 0.42 26-Apr-96 Fix MII write TA bit error.
+ Fix bug in dc21040 and dc21041 autosense code.
+ Remove buffer copies on receive for Intels.
+ Change sk_buff handling during media disconnects to
+ eliminate DUP packets.
+ Add dynamic TX thresholding.
+ Change all chips to use perfect multicast filtering.
+ Fix alloc_device() bug <jari@markkus2.fimr.fi>
+ 0.43 21-Jun-96 Fix unconnected media TX retry bug.
+ Add Accton to the list of broken cards.
+ Fix TX under-run bug for non DC21140 chips.
+ Fix boot command probe bug in alloc_device() as
+ reported by <koen.gadeyne@barco.com> and
+ <orava@nether.tky.hut.fi>.
+ Add cache locks to prevent a race condition as
+ reported by <csd@microplex.com> and
+ <baba@beckman.uiuc.edu>.
+ Upgraded alloc_device() code.
+ 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion
+ with <csd@microplex.com>
+ 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips.
+ Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
+ and <michael@compurex.com>.
+ 0.441 9-Sep-96 Change dc21041_autoconf() to probe quiet BNC media
+ with a loopback packet.
+ 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported
+ by <bhat@mundook.cs.mu.OZ.AU>
+ 0.45 8-Dec-96 Include endian functions for PPC use, from work
+ by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
+ 0.451 28-Dec-96 Added fix to allow autoprobe for modules after
+ suggestion from <mjacob@feral.com>.
+ 0.5 30-Jan-97 Added SROM decoding functions.
+ Updated debug flags.
+ Fix sleep/wakeup calls for PCI cards, bug reported
+ by <cross@gweep.lkg.dec.com>.
+ Added multi-MAC, one SROM feature from discussion
+ with <mjacob@feral.com>.
+ Added full module autoprobe capability.
+ Added attempt to use an SMC9332 with broken SROM.
+ Added fix for ZYNX multi-mac cards that didn't
+ get their IRQs wired correctly.
+ 0.51 13-Feb-97 Added endian fixes for the SROM accesses from
+ <paubert@iram.es>
+ Fix init_connection() to remove extra device reset.
+ Fix MAC/PHY reset ordering in dc21140m_autoconf().
+ Fix initialisation problem with lp->timeout in
+ typeX_infoblock() from <paubert@iram.es>.
+ Fix MII PHY reset problem from work done by
+ <paubert@iram.es>.
+ 0.52 26-Apr-97 Some changes may not credit the right people -
+ a disk crash meant I lost some mail.
+ Change RX interrupt routine to drop rather than
+ defer packets to avoid hang reported by
+ <g.thomas@opengroup.org>.
+ Fix srom_exec() to return for COMPACT and type 1
+ infoblocks.
+ Added DC21142 and DC21143 functions.
+ Added byte counters from <phil@tazenda.demon.co.uk>
+ Added SA_INTERRUPT temporary fix from
+ <mjacob@feral.com>.
0.53 12-Nov-97 Fix the *_probe() to include 'eth??' name during
module load: bug reported by
<Piete.Brooks@cl.cam.ac.uk>
@@ -327,11 +353,29 @@
Make above search independent of BIOS device scan
direction.
Completed DC2114[23] autosense functions.
+ 0.531 21-Dec-97 Fix DE500-XA 100Mb/s bug reported by
+ <robin@intercore.com
+ Fix type1_infoblock() bug introduced in 0.53, from
+ problem reports by
+ <parmee@postecss.ncrfran.france.ncr.com> and
+ <jo@ice.dillingen.baynet.de>.
+ Added argument list to set up each board from either
+ a module's command line or a compiled in #define.
+ Added generic MII PHY functionality to deal with
+ newer PHY chips.
+ Fix the mess in 2.1.67.
+ 0.532 5-Jan-98 Fix bug in mii_get_phy() reported by
+ <redhat@cococo.net>.
+ Fix bug in pci_probe() for 64 bit systems reported
+ by <belliott@accessone.com>.
+ 0.533 9-Jan-98 Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
+ 0.534 24-Jan-98 Fix last (?) endian bug from
+ <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+
+ =========================================================================
+*/
- =========================================================================
- */
-
-static const char *version = "de4x5.c:V0.53 1997/11/12 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.534 1998/1/24 davies@maniac.ultranet.com\n";
#include <linux/module.h>
@@ -388,77 +432,81 @@ static const char *version = "de4x5.c:V0.53 1997/11/12 davies@maniac.ultranet.co
#else
# include <asm/uaccess.h>
# include <linux/init.h>
-#endif /* LINUX_VERSION_CODE */
+#endif /* LINUX_VERSION_CODE */
#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
/*
** MII Information
*/
struct phy_table {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
- int ta; /* One cycle TA time - 802.3u is confusing here */
- struct { /* Non autonegotiation (parallel) speed det. */
- int reg;
- int mask;
- int value;
- } spd;
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
+ int ta; /* One cycle TA time - 802.3u is confusing here */
+ struct { /* Non autonegotiation (parallel) speed det. */
+ int reg;
+ int mask;
+ int value;
+ } spd;
};
struct mii_phy {
- int reset; /* Hard reset required? */
- int id; /* IEEE OUI */
- int ta; /* One cycle TA time */
- struct { /* Non autonegotiation (parallel) speed det. */
- int reg;
- int mask;
- int value;
- } spd;
- int addr; /* MII address for the PHY */
- u_char *gep; /* Start of GEP sequence block in SROM */
- u_char *rst; /* Start of reset sequence in SROM */
- u_int mc; /* Media Capabilities */
- u_int ana; /* NWay Advertisement */
- u_int fdx; /* Full DupleX capabilites for each media */
- u_int ttm; /* Transmit Threshold Mode for each media */
- u_int mci; /* 21142 MII Connector Interrupt info */
+ int reset; /* Hard reset required? */
+ int id; /* IEEE OUI */
+ int ta; /* One cycle TA time */
+ struct { /* Non autonegotiation (parallel) speed det. */
+ int reg;
+ int mask;
+ int value;
+ } spd;
+ int addr; /* MII address for the PHY */
+ u_char *gep; /* Start of GEP sequence block in SROM */
+ u_char *rst; /* Start of reset sequence in SROM */
+ u_int mc; /* Media Capabilities */
+ u_int ana; /* NWay Advertisement */
+ u_int fdx; /* Full DupleX capabilites for each media */
+ u_int ttm; /* Transmit Threshold Mode for each media */
+ u_int mci; /* 21142 MII Connector Interrupt info */
};
-#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */
+#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */
struct sia_phy {
- u_char mc; /* Media Code */
- u_char ext; /* csr13-15 valid when set */
- int csr13; /* SIA Connectivity Register */
- int csr14; /* SIA TX/RX Register */
- int csr15; /* SIA General Register */
- int gepc; /* SIA GEP Control Information */
- int gep; /* SIA GEP Data */
+ u_char mc; /* Media Code */
+ u_char ext; /* csr13-15 valid when set */
+ int csr13; /* SIA Connectivity Register */
+ int csr14; /* SIA TX/RX Register */
+ int csr15; /* SIA General Register */
+ int gepc; /* SIA GEP Control Information */
+ int gep; /* SIA GEP Data */
};
/*
** Define the know universe of PHY devices that can be
-** recognised by this driver
+** recognised by this driver.
*/
-static struct phy_table phy_info[] =
-{
- {0, NATIONAL_TX, 1,
- {0x19, 0x40, 0x00}}, /* National TX */
- {1, BROADCOM_T4, 1,
- {0x10, 0x02, 0x02}}, /* Broadcom T4 */
- {0, SEEQ_T4, 1,
- {0x12, 0x10, 0x10}}, /* SEEQ T4 */
- {0, CYPRESS_T4, 1,
- {0x05, 0x20, 0x20}} /* Cypress T4 */
+static struct phy_table phy_info[] = {
+ {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */
+ {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */
+ {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */
+ {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}}, /* Cypress T4 */
+ {0, 0x7810 , 1, {0x05, 0x0380, 0x0380}} /* Level One? */
};
/*
+** These GENERIC values assumes that the PHY devices follow 802.3u and
+** allow parallel detection to set the link partner ability register.
+** Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported.
+*/
+#define GENERIC_REG 0x05 /* Autoneg. Link Partner Advertisement Reg. */
+#define GENERIC_MASK MII_ANLPA_100M /* All 100Mb/s Technologies */
+#define GENERIC_VALUE MII_ANLPA_100M /* 100B-TX, 100B-TX FDX, 100B-T4 */
+
+/*
** Define special SROM detection cases
*/
-static c_char enet_det[][ETH_ALEN] =
-{
- {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00}
+static c_char enet_det[][ETH_ALEN] = {
+ {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00}
};
#define SMC 1
@@ -469,14 +517,14 @@ static c_char enet_det[][ETH_ALEN] =
** use this information to help figure out what to do. This is a
** "stab in the dark" and so far for SMC9332's only.
*/
-static c_char srom_repair_info[][100] =
-{
- {0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, /* SMC9332 */
- 0x1f, 0x01, 0x8f, 0x01, 0x00, 0x01, 0x00, 0x02,
- 0x01, 0x00, 0x00, 0x78, 0xe0, 0x01, 0x00, 0x50,
- 0x00, 0x18,}
+static c_char srom_repair_info[][100] = {
+ {0x00,0x1e,0x00,0x00,0x00,0x08, /* SMC9332 */
+ 0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02,
+ 0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50,
+ 0x00,0x18,}
};
+
#ifdef DE4X5_DEBUG
static int de4x5_debug = DE4X5_DEBUG;
#else
@@ -484,20 +532,29 @@ static int de4x5_debug = DE4X5_DEBUG;
static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
#endif
-#ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */
-static int de4x5_autosense = DE4X5_AUTOSENSE;
+/*
+** Allow per adapter set up. For modules this is simply a command line
+** parameter, e.g.:
+** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+**
+** For a compiled in driver, place e.g.
+** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
+** somewhere in this file above this point.
+*/
+#ifdef DE4X5_PARM
+static char *args = DE4X5_PARM;
#else
-static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */
+static char *args = NULL;
#endif
-#define DE4X5_AUTOSENSE_MS 250 /* msec autosense tick (DE500) */
-#ifdef DE4X5_FULL_DUPLEX /* Should be done on a per adapter basis */
-static s32 de4x5_full_duplex = 1;
-#else
-static s32 de4x5_full_duplex = 0;
-#endif
+struct parameters {
+ int fdx;
+ int autosense;
+};
+
+#define DE4X5_AUTOSENSE_MS 250 /* msec autosense tick (DE500) */
-#define DE4X5_NDA 0xffe0 /* No Device (I/O) Address */
+#define DE4X5_NDA 0xffe0 /* No Device (I/O) Address */
/*
** Ethernet PROM defines
@@ -508,24 +565,24 @@ static s32 de4x5_full_duplex = 0;
/*
** Ethernet Info
*/
-#define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */
-#define IEEE802_3_SZ 1518 /* Packet + CRC */
-#define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */
-#define MAX_DAT_SZ 1500 /* Maximum ethernet data length */
-#define MIN_DAT_SZ 1 /* Minimum ethernet data length */
-#define PKT_HDR_LEN 14 /* Addresses and data length info */
+#define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */
+#define IEEE802_3_SZ 1518 /* Packet + CRC */
+#define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */
+#define MAX_DAT_SZ 1500 /* Maximum ethernet data length */
+#define MIN_DAT_SZ 1 /* Minimum ethernet data length */
+#define PKT_HDR_LEN 14 /* Addresses and data length info */
#define FAKE_FRAME_LEN (MAX_PKT_SZ + 1)
-#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */
+#define QUEUE_PKT_TIMEOUT (3*HZ) /* 3 second timeout */
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
/*
** EISA bus defines
*/
-#define DE4X5_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-#define DE4X5_EISA_TOTAL_SIZE 0x100 /* I/O address extent */
+#define DE4X5_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
+#define DE4X5_EISA_TOTAL_SIZE 0x100 /* I/O address extent */
#define MAX_EISA_SLOTS 16
#define EISA_SLOT_INC 0x1000
@@ -538,8 +595,8 @@ static s32 de4x5_full_duplex = 0;
** PCI Bus defines
*/
#define PCI_MAX_BUS_NUM 8
-#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */
-#define DE4X5_CLASS_CODE 0x00020000 /* Network controller, Ethernet */
+#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */
+#define DE4X5_CLASS_CODE 0x00020000 /* Network controller, Ethernet */
#define NO_MORE_PCI -2 /* PCI bus search all done */
/*
@@ -548,20 +605,20 @@ static s32 de4x5_full_duplex = 0;
** DESC_ALIGN. ALIGN aligns the start address of the private memory area
** and hence the RX descriptor ring's first entry.
*/
-#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
-#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */
-#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */
-#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */
-#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */
-#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */
-
-#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
+#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
+#define ALIGN8 ((u_long)8 - 1) /* 2 longword align */
+#define ALIGN16 ((u_long)16 - 1) /* 4 longword align */
+#define ALIGN32 ((u_long)32 - 1) /* 8 longword align */
+#define ALIGN64 ((u_long)64 - 1) /* 16 longword align */
+#define ALIGN128 ((u_long)128 - 1) /* 32 longword align */
+
+#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
#define CACHE_ALIGN CAL_16LONG
-#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */
+#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */
/*#define DESC_ALIGN u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */
#define DESC_ALIGN
-#ifndef DEC_ONLY /* See README.de4x5 for using this */
+#ifndef DEC_ONLY /* See README.de4x5 for using this */
static int dec_only = 0;
#else
static int dec_only = 1;
@@ -610,7 +667,7 @@ static int dec_only = 1;
/*
** DE4X5 SIA RESET
*/
-#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */
+#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */
/*
** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
@@ -621,18 +678,17 @@ static int dec_only = 1;
** SROM Structure
*/
struct de4x5_srom {
- char sub_vendor_id[2];
- char sub_system_id[2];
- char reserved[12];
- char id_block_crc;
- char reserved2;
- char version;
- char num_controllers;
- char ieee_addr[6];
- char info[100];
- short chksum;
+ char sub_vendor_id[2];
+ char sub_system_id[2];
+ char reserved[12];
+ char id_block_crc;
+ char reserved2;
+ char version;
+ char num_controllers;
+ char ieee_addr[6];
+ char info[100];
+ short chksum;
};
-
#define SUB_VENDOR_ID 0x500a
/*
@@ -643,106 +699,107 @@ struct de4x5_srom {
** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
** descriptors are needed for machines with an ALPHA CPU.
*/
-#define NUM_RX_DESC 8 /* Number of RX descriptors */
-#define NUM_TX_DESC 32 /* Number of TX descriptors */
-#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */
- /* Multiple of 4 for DC21040 */
- /* Allows 512 byte alignment */
+#define NUM_RX_DESC 8 /* Number of RX descriptors */
+#define NUM_TX_DESC 32 /* Number of TX descriptors */
+#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */
+ /* Multiple of 4 for DC21040 */
+ /* Allows 512 byte alignment */
struct de4x5_desc {
- volatile s32 status;
- u32 des1;
- u32 buf;
- u32 next;
- DESC_ALIGN
+ volatile s32 status;
+ u32 des1;
+ u32 buf;
+ u32 next;
+ DESC_ALIGN
};
/*
** The DE4X5 private structure
*/
#define DE4X5_PKT_STAT_SZ 16
-#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you
- increase DE4X5_PKT_STAT_SZ */
+#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you
+ increase DE4X5_PKT_STAT_SZ */
struct de4x5_private {
- char adapter_name[80]; /* Adapter name */
- struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
- struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
- struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */
- struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */
- int rx_new, rx_old; /* RX descriptor ring pointers */
- int tx_new, tx_old; /* TX descriptor ring pointers */
- char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
- char frame[64]; /* Min sized packet for loopback */
- struct net_device_stats stats; /* Public stats */
- struct {
- u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
- u_int unicast;
- u_int multicast;
- u_int broadcast;
- u_int excessive_collisions;
- u_int tx_underruns;
- u_int excessive_underruns;
- u_int rx_runt_frames;
- u_int rx_collision;
- u_int rx_dribble;
- u_int rx_overflow;
- } pktStats;
- char rxRingSize;
- char txRingSize;
- int bus; /* EISA or PCI */
- int bus_num; /* PCI Bus number */
- int device; /* Device number on PCI bus */
- int state; /* Adapter OPENED or CLOSED */
- int chipset; /* DC21040, DC21041 or DC21140 */
- s32 irq_mask; /* Interrupt Mask (Enable) bits */
- s32 irq_en; /* Summary interrupt bits */
- int media; /* Media (eg TP), mode (eg 100B) */
- int c_media; /* Remember the last media conn */
- int fdx; /* media full duplex flag */
- int linkOK; /* Link is OK */
- int autosense; /* Allow/disallow autosensing */
- int tx_enable; /* Enable descriptor polling */
- int setup_f; /* Setup frame filtering type */
- int local_state; /* State within a 'media' state */
- struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */
- struct sia_phy sia; /* SIA PHY Information */
- int active; /* Index to active PHY device */
- int mii_cnt; /* Number of attached PHY's */
- int timeout; /* Scheduling counter */
- struct timer_list timer; /* Timer info for kernel */
- int tmp; /* Temporary global per card */
- struct {
- void *priv; /* Original kmalloc'd mem addr */
- void *buf; /* Original kmalloc'd mem addr */
- unsigned long lock; /* Lock the cache accesses */
- s32 csr0; /* Saved Bus Mode Register */
- s32 csr6; /* Saved Operating Mode Reg. */
- s32 csr7; /* Saved IRQ Mask Register */
- s32 gep; /* Saved General Purpose Reg. */
- s32 gepc; /* Control info for GEP */
- s32 csr13; /* Saved SIA Connectivity Reg. */
- s32 csr14; /* Saved SIA TX/RX Register */
- s32 csr15; /* Saved SIA General Register */
- int save_cnt; /* Flag if state already saved */
- struct sk_buff *skb; /* Save the (re-ordered) skb's */
- } cache;
- struct de4x5_srom srom; /* A copy of the SROM */
- struct device *next_module; /* Link to the next module */
- int rx_ovf; /* Check for 'RX overflow' tag */
- int useSROM; /* For non-DEC card use SROM */
- int useMII; /* Infoblock using the MII */
- int asBitValid; /* Autosense bits in GEP? */
- int asPolarity; /* 0 => asserted high */
- int asBit; /* Autosense bit number in GEP */
- int defMedium; /* SROM default medium */
- int tcount; /* Last infoblock number */
- int infoblock_init; /* Initialised this infoblock? */
- int infoleaf_offset; /* SROM infoleaf for controller */
- s32 infoblock_csr6; /* csr6 value in SROM infoblock */
- int infoblock_media; /* infoblock media */
- int (*infoleaf_fn) (struct device *); /* Pointer to infoleaf function */
- u_char *rst; /* Pointer to Type 5 reset info */
- u_char ibn; /* Infoblock number */
+ char adapter_name[80]; /* Adapter name */
+ struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
+ struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
+ struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */
+ struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */
+ int rx_new, rx_old; /* RX descriptor ring pointers */
+ int tx_new, tx_old; /* TX descriptor ring pointers */
+ char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
+ char frame[64]; /* Min sized packet for loopback*/
+ struct net_device_stats stats; /* Public stats */
+ struct {
+ u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+ u_int unicast;
+ u_int multicast;
+ u_int broadcast;
+ u_int excessive_collisions;
+ u_int tx_underruns;
+ u_int excessive_underruns;
+ u_int rx_runt_frames;
+ u_int rx_collision;
+ u_int rx_dribble;
+ u_int rx_overflow;
+ } pktStats;
+ char rxRingSize;
+ char txRingSize;
+ int bus; /* EISA or PCI */
+ int bus_num; /* PCI Bus number */
+ int device; /* Device number on PCI bus */
+ int state; /* Adapter OPENED or CLOSED */
+ int chipset; /* DC21040, DC21041 or DC21140 */
+ s32 irq_mask; /* Interrupt Mask (Enable) bits */
+ s32 irq_en; /* Summary interrupt bits */
+ int media; /* Media (eg TP), mode (eg 100B)*/
+ int c_media; /* Remember the last media conn */
+ int fdx; /* media full duplex flag */
+ int linkOK; /* Link is OK */
+ int autosense; /* Allow/disallow autosensing */
+ int tx_enable; /* Enable descriptor polling */
+ int setup_f; /* Setup frame filtering type */
+ int local_state; /* State within a 'media' state */
+ struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */
+ struct sia_phy sia; /* SIA PHY Information */
+ int active; /* Index to active PHY device */
+ int mii_cnt; /* Number of attached PHY's */
+ int timeout; /* Scheduling counter */
+ struct timer_list timer; /* Timer info for kernel */
+ int tmp; /* Temporary global per card */
+ struct {
+ void *priv; /* Original kmalloc'd mem addr */
+ void *buf; /* Original kmalloc'd mem addr */
+ u_long lock; /* Lock the cache accesses */
+ s32 csr0; /* Saved Bus Mode Register */
+ s32 csr6; /* Saved Operating Mode Reg. */
+ s32 csr7; /* Saved IRQ Mask Register */
+ s32 gep; /* Saved General Purpose Reg. */
+ s32 gepc; /* Control info for GEP */
+ s32 csr13; /* Saved SIA Connectivity Reg. */
+ s32 csr14; /* Saved SIA TX/RX Register */
+ s32 csr15; /* Saved SIA General Register */
+ int save_cnt; /* Flag if state already saved */
+ struct sk_buff *skb; /* Save the (re-ordered) skb's */
+ } cache;
+ struct de4x5_srom srom; /* A copy of the SROM */
+ struct device *next_module; /* Link to the next module */
+ int rx_ovf; /* Check for 'RX overflow' tag */
+ int useSROM; /* For non-DEC card use SROM */
+ int useMII; /* Infoblock using the MII */
+ int asBitValid; /* Autosense bits in GEP? */
+ int asPolarity; /* 0 => asserted high */
+ int asBit; /* Autosense bit number in GEP */
+ int defMedium; /* SROM default medium */
+ int tcount; /* Last infoblock number */
+ int infoblock_init; /* Initialised this infoblock? */
+ int infoleaf_offset; /* SROM infoleaf for controller */
+ s32 infoblock_csr6; /* csr6 value in SROM infoblock */
+ int infoblock_media; /* infoblock media */
+ int (*infoleaf_fn)(struct device *); /* Pointer to infoleaf function */
+ u_char *rst; /* Pointer to Type 5 reset info */
+ u_char ibn; /* Infoblock number */
+ struct parameters params; /* Command line/ #defined params */
};
/*
@@ -751,13 +808,13 @@ struct de4x5_private {
** PROM is accessed differently.
*/
static struct bus_type {
- int bus;
- int bus_num;
- int device;
- int chipset;
- struct de4x5_srom srom;
- int autosense;
- int useSROM;
+ int bus;
+ int bus_num;
+ int device;
+ int chipset;
+ struct de4x5_srom srom;
+ int autosense;
+ int useSROM;
} bus;
/*
@@ -773,14 +830,11 @@ static struct bus_type {
** can't follow the PCI to PCI Bridge Architecture spec.
*/
static struct {
- int chipset;
- int bus;
- int irq;
- u_char addr[ETH_ALEN];
-} last = {
-
- 0,
-};
+ int chipset;
+ int bus;
+ int irq;
+ u_char addr[ETH_ALEN];
+} last = {0,};
/*
** The transmit ring full condition is described by the tx_old and tx_new
@@ -798,143 +852,143 @@ static struct {
/*
** Public Functions
*/
-static int de4x5_open(struct device *dev);
-static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
-static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int de4x5_close(struct device *dev);
-static struct net_device_stats *de4x5_get_stats(struct device *dev);
-static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len);
-static void set_multicast_list(struct device *dev);
-static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static int de4x5_open(struct device *dev);
+static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev);
+static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int de4x5_close(struct device *dev);
+static struct net_device_stats *de4x5_get_stats(struct device *dev);
+static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len);
+static void set_multicast_list(struct device *dev);
+static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd);
/*
** Private functions
*/
-static int de4x5_hw_init(struct device *dev, u_long iobase);
-static int de4x5_init(struct device *dev);
-static int de4x5_sw_reset(struct device *dev);
-static int de4x5_rx(struct device *dev);
-static int de4x5_tx(struct device *dev);
-static int de4x5_ast(struct device *dev);
-static int de4x5_txur(struct device *dev);
-static int de4x5_rx_ovfc(struct device *dev);
-
-static int autoconf_media(struct device *dev);
-static void create_packet(struct device *dev, char *frame, int len);
-static void de4x5_us_delay(u32 usec);
-static void de4x5_ms_delay(u32 msec);
-static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb);
-static int dc21040_autoconf(struct device *dev);
-static int dc21041_autoconf(struct device *dev);
-static int dc21140m_autoconf(struct device *dev);
-static int dc2114x_autoconf(struct device *dev);
-static int srom_autoconf(struct device *dev);
-static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn) (struct device *, int), int (*asfn) (struct device *));
-static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn) (struct device *, int));
-static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-static int test_for_100Mb(struct device *dev, int msec);
-static int wait_for_link(struct device *dev);
-static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
-static int is_spd_100(struct device *dev);
-static int is_100_up(struct device *dev);
-static int is_10_up(struct device *dev);
-static int is_anc_capable(struct device *dev);
-static int ping_media(struct device *dev, int msec);
+static int de4x5_hw_init(struct device *dev, u_long iobase);
+static int de4x5_init(struct device *dev);
+static int de4x5_sw_reset(struct device *dev);
+static int de4x5_rx(struct device *dev);
+static int de4x5_tx(struct device *dev);
+static int de4x5_ast(struct device *dev);
+static int de4x5_txur(struct device *dev);
+static int de4x5_rx_ovfc(struct device *dev);
+
+static int autoconf_media(struct device *dev);
+static void create_packet(struct device *dev, char *frame, int len);
+static void de4x5_us_delay(u32 usec);
+static void de4x5_ms_delay(u32 msec);
+static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb);
+static int dc21040_autoconf(struct device *dev);
+static int dc21041_autoconf(struct device *dev);
+static int dc21140m_autoconf(struct device *dev);
+static int dc2114x_autoconf(struct device *dev);
+static int srom_autoconf(struct device *dev);
+static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
+static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
+static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
+static int test_for_100Mb(struct device *dev, int msec);
+static int wait_for_link(struct device *dev);
+static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
+static int is_spd_100(struct device *dev);
+static int is_100_up(struct device *dev);
+static int is_10_up(struct device *dev);
+static int is_anc_capable(struct device *dev);
+static int ping_media(struct device *dev, int msec);
static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len);
-static void de4x5_free_rx_buffs(struct device *dev);
-static void de4x5_free_tx_buffs(struct device *dev);
-static void de4x5_save_skbs(struct device *dev);
-static void de4x5_restore_skbs(struct device *dev);
-static void de4x5_cache_state(struct device *dev, int flag);
-static void de4x5_put_cache(struct device *dev, struct sk_buff *skb);
-static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb);
-static struct sk_buff *de4x5_get_cache(struct device *dev);
-static void de4x5_setup_intr(struct device *dev);
-static void de4x5_init_connection(struct device *dev);
-static int de4x5_reset_phy(struct device *dev);
-static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr);
-static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec);
-static int test_tp(struct device *dev, s32 msec);
-static int EISA_signature(char *name, s32 eisa_id);
-static int PCI_signature(char *name, struct bus_type *lp);
-static void DevicePresent(u_long iobase);
-static int de4x5_bad_srom(struct bus_type *lp);
-static short srom_rd(u_long address, u_char offset);
-static void srom_latch(u_int command, u_long address);
-static void srom_command(u_int command, u_long address);
-static void srom_address(u_int command, u_long address, u_char offset);
-static short srom_data(u_int command, u_long address);
-/*static void srom_busy(u_int command, u_long address); */
-static void sendto_srom(u_int command, u_long addr);
-static int getfrom_srom(u_long addr);
-static int srom_map_media(struct device *dev);
-static int srom_infoleaf_info(struct device *dev);
-static void srom_init(struct device *dev);
-static void srom_exec(struct device *dev, u_char * p);
-static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
-static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
-static int mii_rdata(u_long ioaddr);
-static void mii_wdata(int data, int len, u_long ioaddr);
-static void mii_ta(u_long rw, u_long ioaddr);
-static int mii_swap(int data, int len);
-static void mii_address(u_char addr, u_long ioaddr);
-static void sendto_mii(u32 command, int data, u_long ioaddr);
-static int getfrom_mii(u32 command, u_long ioaddr);
-static int mii_get_oui(u_char phyaddr, u_long ioaddr);
-static int mii_get_phy(struct device *dev);
-static void SetMulticastFilter(struct device *dev);
-static int get_hw_addr(struct device *dev);
-static void srom_repair(struct device *dev, int card);
-static int test_bad_enet(struct device *dev, int status);
-
+static void de4x5_free_rx_buffs(struct device *dev);
+static void de4x5_free_tx_buffs(struct device *dev);
+static void de4x5_save_skbs(struct device *dev);
+static void de4x5_rst_desc_ring(struct device *dev);
+static void de4x5_cache_state(struct device *dev, int flag);
+static void de4x5_put_cache(struct device *dev, struct sk_buff *skb);
+static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb);
+static struct sk_buff *de4x5_get_cache(struct device *dev);
+static void de4x5_setup_intr(struct device *dev);
+static void de4x5_init_connection(struct device *dev);
+static int de4x5_reset_phy(struct device *dev);
+static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr);
+static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec);
+static int test_tp(struct device *dev, s32 msec);
+static int EISA_signature(char *name, s32 eisa_id);
+static int PCI_signature(char *name, struct bus_type *lp);
+static void DevicePresent(u_long iobase);
+static int de4x5_bad_srom(struct bus_type *lp);
+static short srom_rd(u_long address, u_char offset);
+static void srom_latch(u_int command, u_long address);
+static void srom_command(u_int command, u_long address);
+static void srom_address(u_int command, u_long address, u_char offset);
+static short srom_data(u_int command, u_long address);
+/*static void srom_busy(u_int command, u_long address);*/
+static void sendto_srom(u_int command, u_long addr);
+static int getfrom_srom(u_long addr);
+static int srom_map_media(struct device *dev);
+static int srom_infoleaf_info(struct device *dev);
+static void srom_init(struct device *dev);
+static void srom_exec(struct device *dev, u_char *p);
+static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
+static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
+static int mii_rdata(u_long ioaddr);
+static void mii_wdata(int data, int len, u_long ioaddr);
+static void mii_ta(u_long rw, u_long ioaddr);
+static int mii_swap(int data, int len);
+static void mii_address(u_char addr, u_long ioaddr);
+static void sendto_mii(u32 command, int data, u_long ioaddr);
+static int getfrom_mii(u32 command, u_long ioaddr);
+static int mii_get_oui(u_char phyaddr, u_long ioaddr);
+static int mii_get_phy(struct device *dev);
+static void SetMulticastFilter(struct device *dev);
+static int get_hw_addr(struct device *dev);
+static void srom_repair(struct device *dev, int card);
+static int test_bad_enet(struct device *dev, int status);
#ifndef __sparc_v9__
-static void eisa_probe(struct device *dev, u_long iobase);
+static void eisa_probe(struct device *dev, u_long iobase);
#endif
-static void pci_probe(struct device *dev, u_long iobase);
-static void srom_search(int index);
-static char *build_setup_frame(struct device *dev, int mode);
-static void disable_ast(struct device *dev);
-static void enable_ast(struct device *dev, u32 time_out);
-static long de4x5_switch_mac_port(struct device *dev);
-static int gep_rd(struct device *dev);
-static void gep_wr(s32 data, struct device *dev);
-static void timeout(struct device *dev, void (*fn) (u_long data), u_long data, u_long msec);
-static void yawn(struct device *dev, int state);
-static void link_modules(struct device *dev, struct device *tmp);
-static void de4x5_dbg_open(struct device *dev);
-static void de4x5_dbg_mii(struct device *dev, int k);
-static void de4x5_dbg_media(struct device *dev);
-static void de4x5_dbg_srom(struct de4x5_srom *p);
-static void de4x5_dbg_rx(struct sk_buff *skb, int len);
-static int de4x5_strncmp(char *a, char *b, int n);
-static int dc21041_infoleaf(struct device *dev);
-static int dc21140_infoleaf(struct device *dev);
-static int dc21142_infoleaf(struct device *dev);
-static int dc21143_infoleaf(struct device *dev);
-static int type0_infoblock(struct device *dev, u_char count, u_char * p);
-static int type1_infoblock(struct device *dev, u_char count, u_char * p);
-static int type2_infoblock(struct device *dev, u_char count, u_char * p);
-static int type3_infoblock(struct device *dev, u_char count, u_char * p);
-static int type4_infoblock(struct device *dev, u_char count, u_char * p);
-static int type5_infoblock(struct device *dev, u_char count, u_char * p);
-static int compact_infoblock(struct device *dev, u_char count, u_char * p);
+static void pci_probe(struct device *dev, u_long iobase);
+static void srom_search(int index);
+static char *build_setup_frame(struct device *dev, int mode);
+static void disable_ast(struct device *dev);
+static void enable_ast(struct device *dev, u32 time_out);
+static long de4x5_switch_mac_port(struct device *dev);
+static int gep_rd(struct device *dev);
+static void gep_wr(s32 data, struct device *dev);
+static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
+static void yawn(struct device *dev, int state);
+static void link_modules(struct device *dev, struct device *tmp);
+static void de4x5_parse_params(struct device *dev);
+static void de4x5_dbg_open(struct device *dev);
+static void de4x5_dbg_mii(struct device *dev, int k);
+static void de4x5_dbg_media(struct device *dev);
+static void de4x5_dbg_srom(struct de4x5_srom *p);
+static void de4x5_dbg_rx(struct sk_buff *skb, int len);
+static int de4x5_strncmp(char *a, char *b, int n);
+static int dc21041_infoleaf(struct device *dev);
+static int dc21140_infoleaf(struct device *dev);
+static int dc21142_infoleaf(struct device *dev);
+static int dc21143_infoleaf(struct device *dev);
+static int type0_infoblock(struct device *dev, u_char count, u_char *p);
+static int type1_infoblock(struct device *dev, u_char count, u_char *p);
+static int type2_infoblock(struct device *dev, u_char count, u_char *p);
+static int type3_infoblock(struct device *dev, u_char count, u_char *p);
+static int type4_infoblock(struct device *dev, u_char count, u_char *p);
+static int type5_infoblock(struct device *dev, u_char count, u_char *p);
+static int compact_infoblock(struct device *dev, u_char count, u_char *p);
#ifdef MODULE
-int init_module(void);
+int init_module(void);
void cleanup_module(void);
-static struct device *unlink_modules(struct device *p);
+static struct device *unlink_modules(struct device *p);
static struct device *insert_device(struct device *dev, u_long iobase,
int (*init)(struct device *));
static int count_adapters(void);
static int loading_module = 1;
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
MODULE_PARM(de4x5_debug, "i");
-MODULE_PARM(de4x5_full_duplex, "i");
MODULE_PARM(dec_only, "i");
+MODULE_PARM(args, "s");
#endif /* LINUX_VERSION_CODE */
-#else
+# else
static int loading_module = 0;
-#endif /* MODULE */
+#endif /* MODULE */
static char name[DE4X5_NAME_LENGTH + 1];
#ifndef __sparc_v9__
@@ -949,29 +1003,28 @@ static struct device *lastModule = NULL;
** List the SROM infoleaf functions and chipsets
*/
struct InfoLeaf {
- int chipset;
- int (*fn) (struct device *);
+ int chipset;
+ int (*fn)(struct device *);
};
-static struct InfoLeaf infoleaf_array[] =
-{
- {DC21041, dc21041_infoleaf},
- {DC21140, dc21140_infoleaf},
- {DC21142, dc21142_infoleaf},
- {DC21143, dc21143_infoleaf}
+static struct InfoLeaf infoleaf_array[] = {
+ {DC21041, dc21041_infoleaf},
+ {DC21140, dc21140_infoleaf},
+ {DC21142, dc21142_infoleaf},
+ {DC21143, dc21143_infoleaf}
};
#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
/*
** List the SROM info block functions
*/
-static int (*dc_infoblock[]) (struct device * dev, u_char, u_char *) = {
- type0_infoblock,
- type1_infoblock,
- type2_infoblock,
- type3_infoblock,
- type4_infoblock,
- type5_infoblock,
- compact_infoblock
+static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
+ type0_infoblock,
+ type1_infoblock,
+ type2_infoblock,
+ type3_infoblock,
+ type4_infoblock,
+ type5_infoblock,
+ compact_infoblock
};
#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
@@ -997,300 +1050,316 @@ static int (*dc_infoblock[]) (struct device * dev, u_char, u_char *) = {
outl(0x00, DE4X5_GEP);\
udelay(2000); /* Wait for 2ms */\
}
-
+
/*
** Autoprobing in modules is allowed here. See the top of the file for
** more info.
*/
-__initfunc(int de4x5_probe(struct device *dev))
+__initfunc(int
+de4x5_probe(struct device *dev))
{
- u_long iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
#ifndef __sparc_v9__
- eisa_probe(dev, iobase);
+ eisa_probe(dev, iobase);
#endif
- pci_probe(dev, iobase);
-
- return (dev->priv ? 0 : -ENODEV);
+ pci_probe(dev, iobase);
+
+ return (dev->priv ? 0 : -ENODEV);
}
__initfunc(static int
- de4x5_hw_init(struct device *dev, u_long iobase))
+de4x5_hw_init(struct device *dev, u_long iobase))
{
- struct bus_type *lp = &bus;
- int i, status = 0;
- char *tmp;
-
- /* Ensure we're not sleeping */
- if (lp->bus == EISA) {
- outb(WAKEUP, PCI_CFPM);
- } else {
- pcibios_write_config_byte(lp->bus_num, lp->device << 3,
- PCI_CFDA_PSM, WAKEUP);
- }
- de4x5_ms_delay(10);
-
- RESET_DE4X5;
-
- if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
- return -ENXIO; /* Hardware could not reset */
- }
+ struct bus_type *lp = &bus;
+ int i, status=0;
+ char *tmp;
+
+ /* Ensure we're not sleeping */
+ if (lp->bus == EISA) {
+ outb(WAKEUP, PCI_CFPM);
+ } else {
+ pcibios_write_config_byte(lp->bus_num, lp->device << 3,
+ PCI_CFDA_PSM, WAKEUP);
+ }
+ de4x5_ms_delay(10);
+
+ RESET_DE4X5;
+
+ if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
+ return -ENXIO; /* Hardware could not reset */
+ }
+
+ /*
+ ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
+ */
+ useSROM = FALSE;
+ if (lp->bus == PCI) {
+ PCI_signature(name, lp);
+ } else {
+ EISA_signature(name, EISA_ID0);
+ }
+
+ if (*name == '\0') { /* Not found a board signature */
+ return -ENXIO;
+ }
+
+ dev->base_addr = iobase;
+ if (lp->bus == EISA) {
+ printk("%s: %s at 0x%04lx (EISA slot %ld)",
+ dev->name, name, iobase, ((iobase>>12)&0x0f));
+ } else { /* PCI port address */
+ printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
+ iobase, lp->bus_num, lp->device);
+ }
+
+ printk(", h/w address ");
+ status = get_hw_addr(dev);
+ for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x,\n", dev->dev_addr[i]);
+
+ if (status != 0) {
+ printk(" which has an Ethernet PROM CRC error.\n");
+ return -ENXIO;
+ } else {
+ struct de4x5_private *lp;
+
/*
- ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
+ ** Reserve a section of kernel memory for the adapter
+ ** private area and the TX/RX descriptor rings.
*/
- useSROM = FALSE;
- if (lp->bus == PCI) {
- PCI_signature(name, lp);
- } else {
- EISA_signature(name, EISA_ID0);
- }
-
- if (*name == '\0') { /* Not found a board signature */
- return -ENXIO;
- }
- dev->base_addr = iobase;
- if (lp->bus == EISA) {
- printk("%s: %s at 0x%04lx (EISA slot %ld)",
- dev->name, name, iobase, ((iobase >> 12) & 0x0f));
- } else { /* PCI port address */
- printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
- iobase, lp->bus_num, lp->device);
+ dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN,
+ GFP_KERNEL);
+ if (dev->priv == NULL) {
+ return -ENOMEM;
}
+
+ /*
+ ** Align to a longword boundary
+ */
+ tmp = dev->priv;
+ dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
+ lp = (struct de4x5_private *)dev->priv;
+ memset(dev->priv, 0, sizeof(struct de4x5_private));
+ lp->bus = bus.bus;
+ lp->bus_num = bus.bus_num;
+ lp->device = bus.device;
+ lp->chipset = bus.chipset;
+ lp->cache.priv = tmp;
+ lp->cache.gepc = GEP_INIT;
+ lp->asBit = GEP_SLNK;
+ lp->asPolarity = GEP_SLNK;
+ lp->asBitValid = TRUE;
+ lp->timeout = -1;
+ lp->useSROM = useSROM;
+ memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
+ de4x5_parse_params(dev);
- printk(", h/w address ");
- status = get_hw_addr(dev);
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x,\n", dev->dev_addr[i]);
-
- if (status != 0) {
- printk(" which has an Ethernet PROM CRC error.\n");
- return -ENXIO;
+ /*
+ ** Choose correct autosensing in case someone messed up
+ */
+ if ((lp->params.autosense & AUTO) || lp->useSROM) {
+ lp->autosense = AUTO;
} else {
- struct de4x5_private *lp;
-
- /*
- ** Reserve a section of kernel memory for the adapter
- ** private area and the TX/RX descriptor rings.
- */
- dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN,
- GFP_KERNEL);
- if (dev->priv == NULL) {
- return -ENOMEM;
+ if (lp->chipset != DC21140) {
+ if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
+ lp->params.autosense = TP;
}
- /*
- ** Align to a longword boundary
- */
- tmp = dev->priv;
- dev->priv = (void *) (((u_long) dev->priv + ALIGN) & ~ALIGN);
- lp = (struct de4x5_private *) dev->priv;
- memset(dev->priv, 0, sizeof(struct de4x5_private));
- lp->bus = bus.bus;
- lp->bus_num = bus.bus_num;
- lp->device = bus.device;
- lp->chipset = bus.chipset;
- lp->cache.priv = tmp;
- lp->cache.gepc = GEP_INIT;
- lp->asBit = GEP_SLNK;
- lp->asPolarity = GEP_SLNK;
- lp->asBitValid = TRUE;
- lp->timeout = -1;
- lp->useSROM = useSROM;
- memcpy((char *) &lp->srom, (char *) &bus.srom, sizeof(struct de4x5_srom));
-
- /*
- ** Choose correct autosensing in case someone messed up
- */
- if ((de4x5_autosense & AUTO) || lp->useSROM) {
- lp->autosense = AUTO;
- } else {
- if (lp->chipset != DC21140) {
- if ((lp->chipset == DC21040) && (de4x5_autosense & TP_NW)) {
- de4x5_autosense = TP;
- }
- if ((lp->chipset == DC21041) && (de4x5_autosense & BNC_AUI)) {
- de4x5_autosense = BNC;
- }
- lp->autosense = de4x5_autosense & 0x001f;
- } else {
- lp->autosense = de4x5_autosense & 0x00c0;
- }
+ if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
+ lp->params.autosense = BNC;
}
- lp->fdx = de4x5_full_duplex;
- sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
-
- /*
- ** Set up the RX descriptor ring (Intels)
- ** Allocate contiguous receive buffers, long word aligned (Alphas)
- */
+ lp->autosense = lp->params.autosense & 0x001f;
+ } else {
+ lp->autosense = lp->params.autosense & 0x00c0;
+ }
+ }
+ lp->fdx = lp->params.fdx;
+ sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+
+ /*
+ ** Set up the RX descriptor ring (Intels)
+ ** Allocate contiguous receive buffers, long word aligned (Alphas)
+ */
#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
- for (i = 0; i < NUM_RX_DESC; i++) {
- lp->rx_ring[i].status = 0;
- lp->rx_ring[i].des1 = RX_BUFF_SZ;
- lp->rx_ring[i].buf = 0;
- lp->rx_ring[i].next = 0;
- lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
- }
+ for (i=0; i<NUM_RX_DESC; i++) {
+ lp->rx_ring[i].status = 0;
+ lp->rx_ring[i].des1 = RX_BUFF_SZ;
+ lp->rx_ring[i].buf = 0;
+ lp->rx_ring[i].next = 0;
+ lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
+ }
#else
- if ((tmp = (void *) kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
- GFP_KERNEL)) == NULL) {
- kfree(lp->cache.priv);
- return -ENOMEM;
- }
- lp->cache.buf = tmp;
- tmp = (char *) (((u_long) tmp + ALIGN) & ~ALIGN);
- for (i = 0; i < NUM_RX_DESC; i++) {
- lp->rx_ring[i].status = 0;
- lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
- lp->rx_ring[i].buf = cpu_to_le32(virt_to_bus(tmp + i * RX_BUFF_SZ));
- lp->rx_ring[i].next = 0;
- lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
- }
-#endif
-
- barrier();
-
- request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
- DE4X5_EISA_TOTAL_SIZE),
- lp->adapter_name);
-
- lp->rxRingSize = NUM_RX_DESC;
- lp->txRingSize = NUM_TX_DESC;
-
- /* Write the end of list marker to the descriptor lists */
- lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
- lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
-
- /* Tell the adapter where the TX/RX rings are located. */
- outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
- outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
- /* Initialise the IRQ mask and Enable/Disable */
- lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
- lp->irq_en = IMR_NIM | IMR_AIM;
-
- /* Create a loopback packet frame for later media probing */
- create_packet(dev, lp->frame, sizeof(lp->frame));
-
- /* Check if the RX overflow bug needs testing for */
- i = cfrv & 0x000000fe;
- if ((lp->chipset == DC21140) && (i == 0x20)) {
- lp->rx_ovf = 1;
- }
- /* Initialise the SROM pointers if possible */
- if (lp->useSROM) {
- lp->state = INITIALISED;
- if (srom_infoleaf_info(dev)) {
- return -ENXIO;
- }
- srom_init(dev);
- }
- lp->state = CLOSED;
-
- /*
- ** Check for an MII interface
- */
- if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
- mii_get_phy(dev);
- }
- printk(" and requires IRQ %x (provided by %s).\n", dev->irq,
- ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
+ if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
+ GFP_KERNEL)) == NULL) {
+ kfree(lp->cache.priv);
+ return -ENOMEM;
}
- if (de4x5_debug & DEBUG_VERSION) {
- printk(version);
+ lp->cache.buf = tmp;
+ tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
+ for (i=0; i<NUM_RX_DESC; i++) {
+ lp->rx_ring[i].status = 0;
+ lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+ lp->rx_ring[i].buf = cpu_to_le32(virt_to_bus(tmp+i*RX_BUFF_SZ));
+ lp->rx_ring[i].next = 0;
+ lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
}
- /* The DE4X5-specific entries in the device structure. */
- dev->open = &de4x5_open;
- dev->hard_start_xmit = &de4x5_queue_pkt;
- dev->stop = &de4x5_close;
- dev->get_stats = &de4x5_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->do_ioctl = &de4x5_ioctl;
-
- dev->mem_start = 0;
-
- /* Fill in the generic fields of the device structure. */
- ether_setup(dev);
+#endif
- /* Let the adapter sleep to save power */
- yawn(dev, SLEEP);
+ barrier();
+
+ request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE),
+ lp->adapter_name);
+
+ lp->rxRingSize = NUM_RX_DESC;
+ lp->txRingSize = NUM_TX_DESC;
+
+ /* Write the end of list marker to the descriptor lists */
+ lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
+ lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
+
+ /* Tell the adapter where the TX/RX rings are located. */
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ /* Initialise the IRQ mask and Enable/Disable */
+ lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
+ lp->irq_en = IMR_NIM | IMR_AIM;
- return status;
-}
-
+ /* Create a loopback packet frame for later media probing */
+ create_packet(dev, lp->frame, sizeof(lp->frame));
-static int de4x5_open(struct device *dev)
-{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int i, status = 0;
- s32 omr;
+ /* Check if the RX overflow bug needs testing for */
+ i = cfrv & 0x000000fe;
+ if ((lp->chipset == DC21140) && (i == 0x20)) {
+ lp->rx_ovf = 1;
+ }
- /* Allocate the RX buffers */
- for (i = 0; i < lp->rxRingSize; i++) {
- if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
- de4x5_free_rx_buffs(dev);
- return -EAGAIN;
- }
+ /* Initialise the SROM pointers if possible */
+ if (lp->useSROM) {
+ lp->state = INITIALISED;
+ if (srom_infoleaf_info(dev)) {
+ return -ENXIO;
+ }
+ srom_init(dev);
}
- /*
- ** Wake up the adapter
- */
- yawn(dev, WAKEUP);
+ lp->state = CLOSED;
- /*
- ** Re-initialize the DE4X5...
+ /*
+ ** Check for an MII interface
*/
- status = de4x5_init(dev);
-
- lp->state = OPEN;
- de4x5_dbg_open(dev);
-
- if (request_irq(dev->irq, (void *) de4x5_interrupt, SA_SHIRQ,
- lp->adapter_name, dev)) {
- printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
- if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
- lp->adapter_name, dev)) {
- printk("\n Cannot get IRQ- reconfigure your hardware.\n");
- disable_ast(dev);
- de4x5_free_rx_buffs(dev);
- de4x5_free_tx_buffs(dev);
- yawn(dev, SLEEP);
- lp->state = CLOSED;
- return -EAGAIN;
- } else {
- printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n");
- printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
- }
+ if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
+ mii_get_phy(dev);
}
+
+#ifndef __sparc_v9__
+ printk(" and requires IRQ%d (provided by %s).\n", dev->irq,
+#else
+ printk(" and requires IRQ%x (provided by %s).\n", dev->irq,
+#endif
+ ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
+ }
+
+ if (de4x5_debug & DEBUG_VERSION) {
+ printk(version);
+ }
+
+ /* The DE4X5-specific entries in the device structure. */
+ dev->open = &de4x5_open;
+ dev->hard_start_xmit = &de4x5_queue_pkt;
+ dev->stop = &de4x5_close;
+ dev->get_stats = &de4x5_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = &de4x5_ioctl;
+
+ dev->mem_start = 0;
+
+ /* Fill in the generic fields of the device structure. */
+ ether_setup(dev);
+
+ /* Let the adapter sleep to save power */
+ yawn(dev, SLEEP);
+
+ return status;
+}
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = UNMASK_INTERRUPTS;
- dev->trans_start = jiffies;
-
- START_DE4X5;
-
- de4x5_setup_intr(dev);
-
- if (de4x5_debug & DEBUG_OPEN) {
- printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
- printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR));
- printk("\timr: 0x%08x\n", inl(DE4X5_IMR));
- printk("\tomr: 0x%08x\n", inl(DE4X5_OMR));
- printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR));
- printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR));
- printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
- printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
+
+static int
+de4x5_open(struct device *dev)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int i, status = 0;
+ s32 omr;
+
+ /* Allocate the RX buffers */
+ for (i=0; i<lp->rxRingSize; i++) {
+ if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
+ de4x5_free_rx_buffs(dev);
+ return -EAGAIN;
+ }
+ }
+
+ /*
+ ** Wake up the adapter
+ */
+ yawn(dev, WAKEUP);
+
+ /*
+ ** Re-initialize the DE4X5...
+ */
+ status = de4x5_init(dev);
+
+ lp->state = OPEN;
+ de4x5_dbg_open(dev);
+
+ if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
+ lp->adapter_name, dev)) {
+ printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+ if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ lp->adapter_name, dev)) {
+ printk("\n Cannot get IRQ- reconfigure your hardware.\n");
+ disable_ast(dev);
+ de4x5_free_rx_buffs(dev);
+ de4x5_free_tx_buffs(dev);
+ yawn(dev, SLEEP);
+ lp->state = CLOSED;
+ return -EAGAIN;
+ } else {
+ printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n");
+ printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
}
- MOD_INC_USE_COUNT;
+ }
- return status;
+ dev->tbusy = 0;
+ dev->start = 1;
+ dev->interrupt = UNMASK_INTERRUPTS;
+ dev->trans_start = jiffies;
+
+ START_DE4X5;
+
+ de4x5_setup_intr(dev);
+
+ if (de4x5_debug & DEBUG_OPEN) {
+ printk("\tsts: 0x%08x\n", inl(DE4X5_STS));
+ printk("\tbmr: 0x%08x\n", inl(DE4X5_BMR));
+ printk("\timr: 0x%08x\n", inl(DE4X5_IMR));
+ printk("\tomr: 0x%08x\n", inl(DE4X5_OMR));
+ printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR));
+ printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR));
+ printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
+ printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
+ }
+
+ MOD_INC_USE_COUNT;
+
+ return status;
}
/*
@@ -1301,157 +1370,163 @@ static int de4x5_open(struct device *dev)
** to be data corruption problems if it is larger (UDP errors seen from a
** ttcp source).
*/
-static int de4x5_init(struct device *dev)
-{
- /* Lock out other processes whilst setting up the hardware */
- test_and_set_bit(0, (void *)&dev->tbusy);
-
- de4x5_sw_reset(dev);
-
- /* Autoconfigure the connected port */
- autoconf_media(dev);
-
- return 0;
+static int
+de4x5_init(struct device *dev)
+{
+ /* Lock out other processes whilst setting up the hardware */
+ test_and_set_bit(0, (void *)&dev->tbusy);
+
+ de4x5_sw_reset(dev);
+
+ /* Autoconfigure the connected port */
+ autoconf_media(dev);
+
+ return 0;
}
-static int de4x5_sw_reset(struct device *dev)
+static int
+de4x5_sw_reset(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int i, j, status = 0;
- s32 bmr, omr;
-
- /* Select the MII or SRL port now and RESET the MAC */
- if (!lp->useSROM) {
- if (lp->phy[lp->active].id != 0) {
- lp->infoblock_csr6 = OMR_PS | OMR_HBD;
- } else {
- lp->infoblock_csr6 = OMR_TTM;
- }
- de4x5_switch_mac_port(dev);
- }
- /*
- ** Set the programmable burst length to 8 longwords for all the DC21140
- ** Fasternet chips and 4 longwords for all others: DMA errors result
- ** without these values. Cache align 16 long.
- */
- bmr = (lp->chipset == DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
- bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
- outl(bmr, DE4X5_BMR);
-
- omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */
- if (lp->chipset == DC21140) {
- omr |= (OMR_SDP | OMR_SB);
- }
- lp->setup_f = PERFECT;
- outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
- outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
- lp->rx_new = lp->rx_old = 0;
- lp->tx_new = lp->tx_old = 0;
-
- for (i = 0; i < lp->rxRingSize; i++) {
- lp->rx_ring[i].status = cpu_to_le32(R_OWN);
- }
-
- for (i = 0; i < lp->txRingSize; i++) {
- lp->tx_ring[i].status = cpu_to_le32(0);
- }
-
- barrier();
-
- /* Build the setup frame depending on filtering mode */
- SetMulticastFilter(dev);
-
- load_packet(dev, lp->setup_frame, PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL);
- outl(omr | OMR_ST, DE4X5_OMR);
-
- /* Poll for setup frame completion (adapter interrupts are disabled now) */
- sti(); /* Ensure timer interrupts */
- for (j = 0, i = 0; (i < 500) && (j == 0); i++) { /* Upto 500ms delay */
- udelay(1000);
- if ((s32) le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0)
- j = 1;
- }
- outl(omr, DE4X5_OMR); /* Stop everything! */
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int i, j, status = 0;
+ s32 bmr, omr;
+
+ /* Select the MII or SRL port now and RESET the MAC */
+ if (!lp->useSROM) {
+ if (lp->phy[lp->active].id != 0) {
+ lp->infoblock_csr6 = OMR_SDP | OMR_PS | OMR_HBD;
+ } else {
+ lp->infoblock_csr6 = OMR_SDP | OMR_TTM;
+ }
+ de4x5_switch_mac_port(dev);
+ }
+
+ /*
+ ** Set the programmable burst length to 8 longwords for all the DC21140
+ ** Fasternet chips and 4 longwords for all others: DMA errors result
+ ** without these values. Cache align 16 long.
+ */
+ bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
+ bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
+ outl(bmr, DE4X5_BMR);
+
+ omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */
+ if (lp->chipset == DC21140) {
+ omr |= (OMR_SDP | OMR_SB);
+ }
+ lp->setup_f = PERFECT;
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ lp->rx_new = lp->rx_old = 0;
+ lp->tx_new = lp->tx_old = 0;
+
+ for (i = 0; i < lp->rxRingSize; i++) {
+ lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+ }
+
+ for (i = 0; i < lp->txRingSize; i++) {
+ lp->tx_ring[i].status = cpu_to_le32(0);
+ }
+
+ barrier();
- if (j == 0) {
- printk("%s: Setup frame timed out, status %08x\n", dev->name,
- inl(DE4X5_STS));
- status = -EIO;
- }
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- lp->tx_old = lp->tx_new;
+ /* Build the setup frame depending on filtering mode */
+ SetMulticastFilter(dev);
+
+ load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
+ outl(omr|OMR_ST, DE4X5_OMR);
+
+ /* Poll for setup frame completion (adapter interrupts are disabled now) */
+ sti(); /* Ensure timer interrupts */
+ for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */
+ udelay(1000);
+ if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
+ }
+ outl(omr, DE4X5_OMR); /* Stop everything! */
+
+ if (j == 0) {
+ printk("%s: Setup frame timed out, status %08x\n", dev->name,
+ inl(DE4X5_STS));
+ status = -EIO;
+ }
+
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ lp->tx_old = lp->tx_new;
- return status;
+ return status;
}
/*
** Writes a socket buffer address to the next available transmit descriptor
*/
-static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
+static int
+de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int status = 0;
-
- test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */
- if (lp->tx_enable == NO) { /* Cannot send for now */
- return -1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int status = 0;
+
+ test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */
+ if (lp->tx_enable == NO) { /* Cannot send for now */
+ return -1;
+ }
+
+ /*
+ ** Clean out the TX ring asynchronously to interrupts - sometimes the
+ ** interrupts are lost by delayed descriptor status updates relative to
+ ** the irq assertion, especially with a busy PCI bus.
+ */
+ cli();
+ de4x5_tx(dev);
+ sti();
+
+ /* Test if cache is already locked - requeue skb if so */
+ if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt)
+ return -1;
+
+ /* Transmit descriptor ring full or stale skb */
+ if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
+ if (dev->interrupt) {
+ de4x5_putb_cache(dev, skb); /* Requeue the buffer */
+ } else {
+ de4x5_put_cache(dev, skb);
+ }
+ if (de4x5_debug & DEBUG_TX) {
+ printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
+ }
+ } else if (skb->len > 0) {
+ /* If we already have stuff queued locally, use that first */
+ if (lp->cache.skb && !dev->interrupt) {
+ de4x5_put_cache(dev, skb);
+ skb = de4x5_get_cache(dev);
}
- /*
- ** Clean out the TX ring asynchronously to interrupts - sometimes the
- ** interrupts are lost by delayed descriptor status updates relative to
- ** the irq assertion, especially with a busy PCI bus.
- */
- cli();
- de4x5_tx(dev);
- sti();
-
- /* Test if cache is already locked - requeue skb if so */
- if (test_and_set_bit(0, (void *) &lp->cache.lock) && !dev->interrupt)
- return -1;
- /* Transmit descriptor ring full or stale skb */
- if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
- if (dev->interrupt) {
- de4x5_putb_cache(dev, skb); /* Requeue the buffer */
- } else {
- de4x5_put_cache(dev, skb);
- }
- if (de4x5_debug & DEBUG_TX) {
- printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n", dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
- }
- } else if (skb->len > 0) {
- /* If we already have stuff queued locally, use that first */
- if (lp->cache.skb && !dev->interrupt) {
- de4x5_put_cache(dev, skb);
- skb = de4x5_get_cache(dev);
- }
- while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
- cli();
- test_and_set_bit(0, (void*)&dev->tbusy);
- load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+ while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
+ cli();
+ test_and_set_bit(0, (void*)&dev->tbusy);
+ load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
- lp->stats.tx_bytes += skb->len;
+ lp->stats.tx_bytes += skb->len;
#endif
- outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
-
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- dev->trans_start = jiffies;
-
- if (TX_BUFFS_AVAIL) {
- dev->tbusy = 0; /* Another pkt may be queued */
- }
- skb = de4x5_get_cache(dev);
- sti();
- }
- if (skb)
- de4x5_putb_cache(dev, skb);
- }
- lp->cache.lock = 0;
+ outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
+
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ dev->trans_start = jiffies;
+
+ if (TX_BUFFS_AVAIL) {
+ dev->tbusy = 0; /* Another pkt may be queued */
+ }
+ skb = de4x5_get_cache(dev);
+ sti();
+ }
+ if (skb) de4x5_putb_cache(dev, skb);
+ }
+
+ lp->cache.lock = 0;
- return status;
+ return status;
}
/*
@@ -1465,389 +1540,395 @@ static int de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
** is high and descriptor status bits cannot be set before the associated
** interrupt is asserted and this routine entered.
*/
-static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void
+de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct device *dev = (struct device *) dev_id;
- struct de4x5_private *lp;
- s32 imr, omr, sts, limit;
- u_long iobase;
-
- if (dev == NULL) {
- printk("de4x5_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- lp = (struct de4x5_private *) dev->priv;
- iobase = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- DISABLE_IRQs; /* Ensure non re-entrancy */
+ struct device *dev = (struct device *)dev_id;
+ struct de4x5_private *lp;
+ s32 imr, omr, sts, limit;
+ u_long iobase;
+
+ if (dev == NULL) {
+ printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ lp = (struct de4x5_private *)dev->priv;
+ iobase = dev->base_addr;
+
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+ DISABLE_IRQs; /* Ensure non re-entrancy */
#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
- synchronize_irq();
+ synchronize_irq();
#endif
- dev->interrupt = MASK_INTERRUPTS;
-
- for (limit = 0; limit < 8; limit++) {
- sts = inl(DE4X5_STS); /* Read IRQ status */
- outl(sts, DE4X5_STS); /* Reset the board interrupts */
-
- if (!(sts & lp->irq_mask))
- break; /* All done */
-
- if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
- de4x5_rx(dev);
-
- if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
- de4x5_tx(dev);
-
- if (sts & STS_LNF) { /* TP Link has failed */
- lp->irq_mask &= ~IMR_LFM;
- }
- if (sts & STS_UNF) { /* Transmit underrun */
- de4x5_txur(dev);
- }
- if (sts & STS_SE) { /* Bus Error */
- STOP_DE4X5;
- printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
- dev->name, sts);
- return;
- }
+ dev->interrupt = MASK_INTERRUPTS;
+
+ for (limit=0; limit<8; limit++) {
+ sts = inl(DE4X5_STS); /* Read IRQ status */
+ outl(sts, DE4X5_STS); /* Reset the board interrupts */
+
+ if (!(sts & lp->irq_mask)) break;/* All done */
+
+ if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
+ de4x5_rx(dev);
+
+ if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
+ de4x5_tx(dev);
+
+ if (sts & STS_LNF) { /* TP Link has failed */
+ lp->irq_mask &= ~IMR_LFM;
+ }
+
+ if (sts & STS_UNF) { /* Transmit underrun */
+ de4x5_txur(dev);
+ }
+
+ if (sts & STS_SE) { /* Bus Error */
+ STOP_DE4X5;
+ printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
+ dev->name, sts);
+ return;
}
+ }
- /* Load the TX ring with any locally stored packets */
- if (!test_and_set_bit(0, (void *) &lp->cache.lock)) {
- while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
- de4x5_queue_pkt(de4x5_get_cache(dev), dev);
- }
- lp->cache.lock = 0;
+ /* Load the TX ring with any locally stored packets */
+ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
+ while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
+ de4x5_queue_pkt(de4x5_get_cache(dev), dev);
}
- dev->interrupt = UNMASK_INTERRUPTS;
- ENABLE_IRQs;
+ lp->cache.lock = 0;
+ }
- return;
+ dev->interrupt = UNMASK_INTERRUPTS;
+ ENABLE_IRQs;
+
+ return;
}
-static int de4x5_rx(struct device *dev)
+static int
+de4x5_rx(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int entry;
- s32 status;
-
- for (entry = lp->rx_new; (s32) le32_to_cpu(lp->rx_ring[entry].status) >= 0;
- entry = lp->rx_new) {
- status = (s32) le32_to_cpu(lp->rx_ring[entry].status);
-
- if (lp->rx_ovf) {
- if (inl(DE4X5_MFC) & MFC_FOCM) {
- de4x5_rx_ovfc(dev);
- break;
- }
- }
- if (status & RD_FS) { /* Remember the start of frame */
- lp->rx_old = entry;
- }
- if (status & RD_LS) { /* Valid frame status */
- if (lp->tx_enable)
- lp->linkOK++;
- if (status & RD_ES) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
- if (status & (RD_RF | RD_TL))
- lp->stats.rx_frame_errors++;
- if (status & RD_CE)
- lp->stats.rx_crc_errors++;
- if (status & RD_OF)
- lp->stats.rx_fifo_errors++;
- if (status & RD_TL)
- lp->stats.rx_length_errors++;
- if (status & RD_RF)
- lp->pktStats.rx_runt_frames++;
- if (status & RD_CS)
- lp->pktStats.rx_collision++;
- if (status & RD_DB)
- lp->pktStats.rx_dribble++;
- if (status & RD_OF)
- lp->pktStats.rx_overflow++;
- } else { /* A valid frame received */
- struct sk_buff *skb;
- short pkt_len = (short) (le32_to_cpu(lp->rx_ring[entry].status)
- >> 16) - 4;
-
- if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
- printk("%s: Insufficient memory; nuking packet.\n",
- dev->name);
- lp->stats.rx_dropped++;
- } else {
- de4x5_dbg_rx(skb, pkt_len);
-
- /* Push up the protocol stack */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
-
- /* Update stats */
- lp->stats.rx_packets++;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int entry;
+ s32 status;
+
+ for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
+ entry=lp->rx_new) {
+ status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
+
+ if (lp->rx_ovf) {
+ if (inl(DE4X5_MFC) & MFC_FOCM) {
+ de4x5_rx_ovfc(dev);
+ break;
+ }
+ }
+
+ if (status & RD_FS) { /* Remember the start of frame */
+ lp->rx_old = entry;
+ }
+
+ if (status & RD_LS) { /* Valid frame status */
+ if (lp->tx_enable) lp->linkOK++;
+ if (status & RD_ES) { /* There was an error. */
+ lp->stats.rx_errors++; /* Update the error stats. */
+ if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++;
+ if (status & RD_CE) lp->stats.rx_crc_errors++;
+ if (status & RD_OF) lp->stats.rx_fifo_errors++;
+ if (status & RD_TL) lp->stats.rx_length_errors++;
+ if (status & RD_RF) lp->pktStats.rx_runt_frames++;
+ if (status & RD_CS) lp->pktStats.rx_collision++;
+ if (status & RD_DB) lp->pktStats.rx_dribble++;
+ if (status & RD_OF) lp->pktStats.rx_overflow++;
+ } else { /* A valid frame received */
+ struct sk_buff *skb;
+ short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
+ >> 16) - 4;
+
+ if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
+ printk("%s: Insufficient memory; nuking packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ } else {
+ de4x5_dbg_rx(skb, pkt_len);
+
+ /* Push up the protocol stack */
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+
+ /* Update stats */
+ lp->stats.rx_packets++;
#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
- lp->stats.rx_bytes += pkt_len;
+ lp->stats.rx_bytes += pkt_len;
#endif
- de4x5_local_stats(dev, skb->data, pkt_len);
- }
- }
-
- /* Change buffer ownership for this frame, back to the adapter */
- for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) % lp->rxRingSize) {
- lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
- barrier();
- }
- lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
- barrier();
+ de4x5_local_stats(dev, skb->data, pkt_len);
}
- /*
- ** Update entry information
- */
- lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
+ }
+
+ /* Change buffer ownership for this frame, back to the adapter */
+ for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
+ lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
+ barrier();
+ }
+ lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
+ barrier();
}
-
- return 0;
+
+ /*
+ ** Update entry information
+ */
+ lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
+ }
+
+ return 0;
}
/*
** Buffer sent - check for TX buffer errors.
*/
-static int de4x5_tx(struct device *dev)
+static int
+de4x5_tx(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int entry;
- s32 status;
-
- for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
- status = (s32) le32_to_cpu(lp->tx_ring[entry].status);
- if (status < 0) { /* Buffer not sent yet */
- break;
- } else if (status != 0x7fffffff) { /* Not setup frame */
- if (status & TD_ES) { /* An error happened */
- lp->stats.tx_errors++;
- if (status & TD_NC)
- lp->stats.tx_carrier_errors++;
- if (status & TD_LC)
- lp->stats.tx_window_errors++;
- if (status & TD_UF)
- lp->stats.tx_fifo_errors++;
- if (status & TD_EC)
- lp->pktStats.excessive_collisions++;
- if (status & TD_DE)
- lp->stats.tx_aborted_errors++;
-
- if (TX_PKT_PENDING) {
- outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */
- }
- } else { /* Packet sent */
- lp->stats.tx_packets++;
- if (lp->tx_enable)
- lp->linkOK++;
- }
- /* Update the collision counter */
- lp->stats.collisions += ((status & TD_EC) ? 16 :
- ((status & TD_CC) >> 3));
-
- /* Free the buffer. */
- if (lp->tx_skb[entry] != NULL) {
- dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE);
- lp->tx_skb[entry] = NULL;
- }
- }
- /* Update all the pointers */
- lp->tx_old = (++lp->tx_old) % lp->txRingSize;
- }
-
- if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */
- dev->tbusy = 0; /* Clear TX busy flag */
- if (dev->interrupt)
- mark_bh(NET_BH);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int entry;
+ s32 status;
+
+ for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+ status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
+ if (status < 0) { /* Buffer not sent yet */
+ break;
+ } else if (status != 0x7fffffff) { /* Not setup frame */
+ if (status & TD_ES) { /* An error happened */
+ lp->stats.tx_errors++;
+ if (status & TD_NC) lp->stats.tx_carrier_errors++;
+ if (status & TD_LC) lp->stats.tx_window_errors++;
+ if (status & TD_UF) lp->stats.tx_fifo_errors++;
+ if (status & TD_EC) lp->pktStats.excessive_collisions++;
+ if (status & TD_DE) lp->stats.tx_aborted_errors++;
+
+ if (TX_PKT_PENDING) {
+ outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
+ }
+ } else { /* Packet sent */
+ lp->stats.tx_packets++;
+ if (lp->tx_enable) lp->linkOK++;
+ }
+ /* Update the collision counter */
+ lp->stats.collisions += ((status & TD_EC) ? 16 :
+ ((status & TD_CC) >> 3));
+
+ /* Free the buffer. */
+ if (lp->tx_skb[entry] != NULL) {
+ dev_kfree_skb(lp->tx_skb[entry]);
+ lp->tx_skb[entry] = NULL;
+ }
}
- return 0;
+
+ /* Update all the pointers */
+ lp->tx_old = (++lp->tx_old) % lp->txRingSize;
+ }
+
+ if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */
+ dev->tbusy = 0; /* Clear TX busy flag */
+ if (dev->interrupt) mark_bh(NET_BH);
+ }
+
+ return 0;
}
-static int de4x5_ast(struct device *dev)
+static int
+de4x5_ast(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- disable_ast(dev);
-
- if (lp->useSROM) {
- next_tick = srom_autoconf(dev);
- } else if (lp->chipset == DC21140) {
- next_tick = dc21140m_autoconf(dev);
- } else if (lp->chipset == DC21041) {
- next_tick = dc21041_autoconf(dev);
- } else if (lp->chipset == DC21040) {
- next_tick = dc21040_autoconf(dev);
- }
- lp->linkOK = 0;
- enable_ast(dev, next_tick);
-
- return 0;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ disable_ast(dev);
+
+ if (lp->useSROM) {
+ next_tick = srom_autoconf(dev);
+ } else if (lp->chipset == DC21140) {
+ next_tick = dc21140m_autoconf(dev);
+ } else if (lp->chipset == DC21041) {
+ next_tick = dc21041_autoconf(dev);
+ } else if (lp->chipset == DC21040) {
+ next_tick = dc21040_autoconf(dev);
+ }
+ lp->linkOK = 0;
+ enable_ast(dev, next_tick);
+
+ return 0;
}
-static int de4x5_txur(struct device *dev)
+static int
+de4x5_txur(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int omr;
-
- omr = inl(DE4X5_OMR);
- if (!(omr & OMR_SF) || (lp->chipset == DC21041) || (lp->chipset == DC21040)) {
- omr &= ~(OMR_ST | OMR_SR);
- outl(omr, DE4X5_OMR);
- while (inl(DE4X5_STS) & STS_TS);
- if ((omr & OMR_TR) < OMR_TR) {
- omr += 0x4000;
- } else {
- omr |= OMR_SF;
- }
- outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int omr;
+
+ omr = inl(DE4X5_OMR);
+ if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) {
+ omr &= ~(OMR_ST|OMR_SR);
+ outl(omr, DE4X5_OMR);
+ while (inl(DE4X5_STS) & STS_TS);
+ if ((omr & OMR_TR) < OMR_TR) {
+ omr += 0x4000;
+ } else {
+ omr |= OMR_SF;
}
- return 0;
+ outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+ }
+
+ return 0;
}
-static int de4x5_rx_ovfc(struct device *dev)
+static int
+de4x5_rx_ovfc(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int omr;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int omr;
- omr = inl(DE4X5_OMR);
- outl(omr & ~OMR_SR, DE4X5_OMR);
- while (inl(DE4X5_STS) & STS_RS);
+ omr = inl(DE4X5_OMR);
+ outl(omr & ~OMR_SR, DE4X5_OMR);
+ while (inl(DE4X5_STS) & STS_RS);
- for (; (s32) le32_to_cpu(lp->rx_ring[lp->rx_new].status) >= 0;) {
- lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN);
- lp->rx_new = (++lp->rx_new % lp->rxRingSize);
- }
-
- outl(omr, DE4X5_OMR);
+ for (; (s32)le32_to_cpu(lp->rx_ring[lp->rx_new].status)>=0;) {
+ lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN);
+ lp->rx_new = (++lp->rx_new % lp->rxRingSize);
+ }
- return 0;
+ outl(omr, DE4X5_OMR);
+
+ return 0;
}
-static int de4x5_close(struct device *dev)
+static int
+de4x5_close(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 imr, omr;
-
- disable_ast(dev);
- dev->start = 0;
- dev->tbusy = 1;
-
- if (de4x5_debug & DEBUG_CLOSE) {
- printk("%s: Shutting down ethercard, status was %8.8x.\n",
- dev->name, inl(DE4X5_STS));
- }
- /*
- ** We stop the DE4X5 here... mask interrupts and stop TX & RX
- */
- DISABLE_IRQs;
- STOP_DE4X5;
-
- /* Free the associated irq */
- free_irq(dev->irq, dev);
- lp->state = CLOSED;
-
- /* Free any socket buffers */
- de4x5_free_rx_buffs(dev);
- de4x5_free_tx_buffs(dev);
-
- MOD_DEC_USE_COUNT;
-
- /* Put the adapter to sleep to save power */
- yawn(dev, SLEEP);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 imr, omr;
+
+ disable_ast(dev);
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ if (de4x5_debug & DEBUG_CLOSE) {
+ printk("%s: Shutting down ethercard, status was %8.8x.\n",
+ dev->name, inl(DE4X5_STS));
+ }
+
+ /*
+ ** We stop the DE4X5 here... mask interrupts and stop TX & RX
+ */
+ DISABLE_IRQs;
+ STOP_DE4X5;
+
+ /* Free the associated irq */
+ free_irq(dev->irq, dev);
+ lp->state = CLOSED;
- return 0;
+ /* Free any socket buffers */
+ de4x5_free_rx_buffs(dev);
+ de4x5_free_tx_buffs(dev);
+
+ MOD_DEC_USE_COUNT;
+
+ /* Put the adapter to sleep to save power */
+ yawn(dev, SLEEP);
+
+ return 0;
}
static struct net_device_stats *
de4x5_get_stats(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
-
- return &lp->stats;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
+
+ return &lp->stats;
}
-static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len)
+static void
+de4x5_local_stats(struct device *dev, char *buf, int pkt_len)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i;
-
- for (i = 1; i < DE4X5_PKT_STAT_SZ - 1; i++) {
- if (pkt_len < (i * DE4X5_PKT_BIN_SZ)) {
- lp->pktStats.bins[i]++;
- i = DE4X5_PKT_STAT_SZ;
- }
- }
- if (buf[0] & 0x01) { /* Multicast/Broadcast */
- if ((*(s32 *) & buf[0] == -1) && (*(s16 *) & buf[4] == -1)) {
- lp->pktStats.broadcast++;
- } else {
- lp->pktStats.multicast++;
- }
- } else if ((*(s32 *) & buf[0] == *(s32 *) & dev->dev_addr[0]) &&
- (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) {
- lp->pktStats.unicast++;
- }
- lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
- if (lp->pktStats.bins[0] == 0) { /* Reset counters */
- memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
- }
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i;
+
+ for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
+ if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
+ lp->pktStats.bins[i]++;
+ i = DE4X5_PKT_STAT_SZ;
+ }
+ }
+ if (buf[0] & 0x01) { /* Multicast/Broadcast */
+ if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
+ lp->pktStats.broadcast++;
+ } else {
+ lp->pktStats.multicast++;
+ }
+ } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+ (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
+ lp->pktStats.unicast++;
+ }
+
+ lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
+ if (lp->pktStats.bins[0] == 0) { /* Reset counters */
+ memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
+ }
+
+ return;
}
-static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
+static void
+load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
-
- lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf));
- lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
- lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
- lp->tx_skb[lp->tx_new] = skb;
- barrier();
- lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
- barrier();
-
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+ lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf));
+ lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
+ lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
+ lp->tx_skb[lp->tx_new] = skb;
+ barrier();
+ lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
+ barrier();
+
+ return;
}
/*
** Set or clear the multicast filter for this adaptor.
*/
-static void set_multicast_list(struct device *dev)
+static void
+set_multicast_list(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- /* First, double check that the adapter is open */
- if (lp->state == OPEN) {
- if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
- u32 omr;
- omr = inl(DE4X5_OMR);
- omr |= OMR_PR;
- outl(omr, DE4X5_OMR);
- } else {
- SetMulticastFilter(dev);
- load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
- SETUP_FRAME_LEN, NULL);
-
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
- dev->trans_start = jiffies;
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ /* First, double check that the adapter is open */
+ if (lp->state == OPEN) {
+ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
+ u32 omr;
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PR;
+ outl(omr, DE4X5_OMR);
+ } else {
+ SetMulticastFilter(dev);
+ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+ SETUP_FRAME_LEN, NULL);
+
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
+ dev->trans_start = jiffies;
}
- return;
+ }
+
+ return;
}
/*
@@ -1855,61 +1936,61 @@ static void set_multicast_list(struct device *dev)
** from a list of ethernet multicast addresses.
** Little endian crc one liner from Matt Thomas, DEC.
*/
-static void SetMulticastFilter(struct device *dev)
+static void
+SetMulticastFilter(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct dev_mc_list *dmi = dev->mc_list;
- u_long iobase = dev->base_addr;
- int i, j, bit, byte;
- u16 hashcode;
- u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
- char *pa;
- unsigned char *addrs;
-
- omr = inl(DE4X5_OMR);
- omr &= ~(OMR_PR | OMR_PM);
- pa = build_setup_frame(dev, ALL); /* Build the basic frame */
-
- if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
- omr |= OMR_PM; /* Pass all multicasts */
- } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */
- for (i = 0; i < dev->mc_count; i++) { /* for each address in the list */
- addrs = dmi->dmi_addr;
- dmi = dmi->next;
- if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte = 0; byte < ETH_ALEN; byte++) { /* for each address byte */
- /* process each address bit */
- for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
- crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
- }
- }
- hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
-
- byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
- bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
-
- byte <<= 1; /* calc offset into setup frame */
- if (byte & 0x02) {
- byte -= 1;
- }
- lp->setup_frame[byte] |= bit;
- }
- }
- } else { /* Perfect filtering */
- for (j = 0; j < dev->mc_count; j++) {
- addrs = dmi->dmi_addr;
- dmi = dmi->next;
- for (i = 0; i < ETH_ALEN; i++) {
- *(pa + (i & 1)) = *addrs++;
- if (i & 0x01)
- pa += 4;
- }
- }
- }
- outl(omr, DE4X5_OMR);
-
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct dev_mc_list *dmi=dev->mc_list;
+ u_long iobase = dev->base_addr;
+ int i, j, bit, byte;
+ u16 hashcode;
+ u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
+ char *pa;
+ unsigned char *addrs;
+
+ omr = inl(DE4X5_OMR);
+ omr &= ~(OMR_PR | OMR_PM);
+ pa = build_setup_frame(dev, ALL); /* Build the basic frame */
+
+ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
+ omr |= OMR_PM; /* Pass all multicasts */
+ } else if (lp->setup_f == HASH_PERF) { /* Hash Filtering */
+ for (i=0;i<dev->mc_count;i++) { /* for each address in the list */
+ addrs=dmi->dmi_addr;
+ dmi=dmi->next;
+ if ((*addrs & 0x01) == 1) { /* multicast address? */
+ crc = 0xffffffff; /* init CRC for each address */
+ for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
+ /* process each address bit */
+ for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+ crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
+ }
+ }
+ hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */
+
+ byte = hashcode >> 3; /* bit[3-8] -> byte in filter */
+ bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
+
+ byte <<= 1; /* calc offset into setup frame */
+ if (byte & 0x02) {
+ byte -= 1;
+ }
+ lp->setup_frame[byte] |= bit;
+ }
+ }
+ } else { /* Perfect filtering */
+ for (j=0; j<dev->mc_count; j++) {
+ addrs=dmi->dmi_addr;
+ dmi=dmi->next;
+ for (i=0; i<ETH_ALEN; i++) {
+ *(pa + (i&1)) = *addrs++;
+ if (i & 0x01) pa += 4;
+ }
+ }
+ }
+ outl(omr, DE4X5_OMR);
+
+ return;
}
#ifndef __sparc_v9__
@@ -1918,73 +1999,69 @@ static void SetMulticastFilter(struct device *dev)
** the motherboard. Upto 15 EISA devices are supported.
*/
__initfunc(static void
- eisa_probe(struct device *dev, u_long ioaddr))
+eisa_probe(struct device *dev, u_long ioaddr))
{
- int i, maxSlots, status, device;
- u_char irq;
- u_short vendor;
- u32 cfid;
- u_long iobase;
- struct bus_type *lp = &bus;
- char name[DE4X5_STRLEN];
-
- if (lastEISA == MAX_EISA_SLOTS)
- return; /* No more EISA devices to search */
-
- lp->bus = EISA;
-
- if (ioaddr == 0) { /* Autoprobing */
- iobase = EISA_SLOT_INC; /* Get the first slot address */
- i = 1;
- maxSlots = MAX_EISA_SLOTS;
- } else { /* Probe a specific location */
- iobase = ioaddr;
- i = (ioaddr >> 12);
- maxSlots = i + 1;
- }
-
- for (status = -ENODEV; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
- if (EISA_signature(name, EISA_ID)) {
- cfid = (u32) inl(PCI_CFID);
- cfrv = (u_short) inl(PCI_CFRV);
- device = (cfid >> 8) & 0x00ffff00;
- vendor = (u_short) cfid;
-
- /* Read the EISA Configuration Registers */
- irq = inb(EISA_REG0);
- irq = de4x5_irq[(irq >> 1) & 0x03];
-
- if (is_DC2114x)
- device |= (cfrv & CFRV_RN);
- lp->chipset = device;
-
- /* Write the PCI Configuration Registers */
- outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
- outl(0x00006000, PCI_CFLT);
- outl(iobase, PCI_CBIO);
-
- DevicePresent(DE4X5_APROM);
- if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
- dev->irq = irq;
- if ((status = de4x5_hw_init(dev, iobase)) == 0) {
- num_de4x5s++;
- if (loading_module) link_modules(lastModule, dev);
- lastEISA = i;
- return;
- }
- } else if (ioaddr != 0) {
- printk("%s: region already allocated at 0x%04lx.\n",
- dev->name, iobase);
- }
+ int i, maxSlots, status, device;
+ u_char irq;
+ u_short vendor;
+ u32 cfid;
+ u_long iobase;
+ struct bus_type *lp = &bus;
+ char name[DE4X5_STRLEN];
+
+ if (lastEISA == MAX_EISA_SLOTS) return;/* No more EISA devices to search */
+
+ lp->bus = EISA;
+
+ if (ioaddr == 0) { /* Autoprobing */
+ iobase = EISA_SLOT_INC; /* Get the first slot address */
+ i = 1;
+ maxSlots = MAX_EISA_SLOTS;
+ } else { /* Probe a specific location */
+ iobase = ioaddr;
+ i = (ioaddr >> 12);
+ maxSlots = i + 1;
+ }
+
+ for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+ if (EISA_signature(name, EISA_ID)) {
+ cfid = (u32) inl(PCI_CFID);
+ cfrv = (u_short) inl(PCI_CFRV);
+ device = (cfid >> 8) & 0x00ffff00;
+ vendor = (u_short) cfid;
+
+ /* Read the EISA Configuration Registers */
+ irq = inb(EISA_REG0);
+ irq = de4x5_irq[(irq >> 1) & 0x03];
+
+ if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ lp->chipset = device;
+
+ /* Write the PCI Configuration Registers */
+ outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
+ outl(0x00006000, PCI_CFLT);
+ outl(iobase, PCI_CBIO);
+
+ DevicePresent(DE4X5_APROM);
+ if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
+ dev->irq = irq;
+ if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+ num_de4x5s++;
+ if (loading_module) link_modules(lastModule, dev);
+ lastEISA = i;
+ return;
}
+ } else if (ioaddr != 0) {
+ printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
+ }
}
+ }
- if (ioaddr == 0)
- lastEISA = i;
+ if (ioaddr == 0) lastEISA = i;
- return;
+ return;
}
-#endif /* !(__sparc_v9__) */
+#endif /* !(__sparc_v9__) */
/*
** PCI bus I/O device probe
@@ -2002,151 +2079,132 @@ __initfunc(static void
#define PCI_LAST_DEV 32
__initfunc(static void
- pci_probe(struct device *dev, u_long ioaddr))
+pci_probe(struct device *dev, u_long ioaddr))
{
- u_char pb, pbus, dev_num, dnum, dev_fn, timer;
- u_short dev_id, vendor, index, status;
- u_int irq;
- u_int class = DE4X5_CLASS_CODE;
- u_int device;
- u_long iobase;
- struct bus_type *lp = &bus;
-
- if (lastPCI == NO_MORE_PCI)
- return;
-
- if (!pcibios_present()) {
- lastPCI = NO_MORE_PCI;
- return; /* No PCI bus in this machine! */
- }
-
- lp->bus = PCI;
-
- if ((ioaddr < 0x1000) && loading_module) {
- pbus = (u_short) (ioaddr >> 8);
- dnum = (u_short) (ioaddr & 0xff);
- } else {
- pbus = 0;
- dnum = 0;
- }
-
- for (index = lastPCI+1;
- (pcibios_find_class(class, index, &pb, &dev_fn) != PCIBIOS_DEVICE_NOT_FOUND);
- index++) {
- dev_num = PCI_SLOT(dev_fn);
-
- if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
+ u_char pb, pbus, dev_num, dnum, dev_fn, timer, tirq;
+ u_short dev_id, vendor, index, status;
+ u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+ u_long iobase = 0; /* Clear upper 32 bits in Alphas */
+ struct bus_type *lp = &bus;
+
+ if (lastPCI == NO_MORE_PCI) return;
+
+ if (!pcibios_present()) {
+ lastPCI = NO_MORE_PCI;
+ return; /* No PCI bus in this machine! */
+ }
+
+ lp->bus = PCI;
+ lp->bus_num = 0;
+
+ if ((ioaddr < 0x1000) && loading_module) {
+ pbus = (u_short)(ioaddr >> 8);
+ dnum = (u_short)(ioaddr & 0xff);
+ } else {
+ pbus = 0;
+ dnum = 0;
+ }
+
+ for (index=lastPCI+1;
+ (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+ index++) {
+ dev_num = PCI_SLOT(dev_fn);
+ if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
#ifdef __sparc_v9__
- struct pci_dev *pdev;
-
- for (pdev = pci_devices; pdev; pdev = pdev->next)
- if (pdev->bus->number == pb &&
- pdev->devfn == dev_fn)
- break;
+ struct pci_dev *pdev;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
+ }
#endif
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
-
- /* Search for an SROM on this bus */
- if (lp->bus_num != pb) {
- lp->bus_num = pb;
- srom_search(index);
- }
-
- /* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ device = 0;
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+ device = dev_id;
+ device <<= 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+ continue;
+ }
+
+ /* Search for an SROM on this bus */
+ if (lp->bus_num != pb) {
+ lp->bus_num = pb;
+ srom_search(index);
+ }
- /* Set the device number information */
- lp->device = dev_num;
- lp->bus_num = pb;
+ /* Get the chip configuration revision register */
+ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
- /* Set the chipset information */
- if (is_DC2114x)
- device |= (cfrv & CFRV_RN);
- lp->chipset = device;
+ /* Set the device number information */
+ lp->device = dev_num;
+ lp->bus_num = pb;
+
+ /* Set the chipset information */
+ if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ lp->chipset = device;
- /* Get the board I/O address */
-#ifdef __sparc_v9__
- iobase = pdev->base_address[0];
+ /* Get the board I/O address (64 bits on sparc64) */
+#ifndef __sparc_v9__
+ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
+ iobase = tmp;
#else
- {
- unsigned int tmp;
- pcibios_read_config_dword(pb, PCI_DEVICE,
- PCI_BASE_ADDRESS_0, &tmp);
- iobase = tmp;
- }
+ iobase = pdev->base_address[0];
#endif
- iobase &= CBIO_MASK;
+ iobase &= CBIO_MASK;
- /* Fetch the IRQ to be used */
-#ifdef __sparc_v9__
- irq = pdev->irq;
+ /* Fetch the IRQ to be used */
+#ifndef __sparc_v9__
+ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
+ irq = tirq;
#else
- {
- unsigned char tmp;
- pcibios_read_config_byte(pb, PCI_DEVICE,
- PCI_INTERRUPT_LINE, &tmp);
- irq = tmp;
- }
- if ((irq == 0) || (irq == (u_char) 0xff))
- continue;
+ irq = pdev->irq;
#endif
-
- /* Check if I/O accesses and Bus Mastering are enabled */
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+
+ /* Check if I/O accesses and Bus Mastering are enabled */
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
#ifdef __powerpc__
- if (!(status & PCI_COMMAND_IO)) {
- status |= PCI_COMMAND_IO;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
+ if (!(status & PCI_COMMAND_IO)) {
+ status |= PCI_COMMAND_IO;
+ pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ }
#endif /* __powerpc__ */
- if (!(status & PCI_COMMAND_IO))
- continue;
- if (!(status & PCI_COMMAND_MASTER)) {
- status |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- }
- if (!(status & PCI_COMMAND_MASTER))
- continue;
-
- /* Check the latency timer for values > 0x60 */
- pcibios_read_config_byte(pb, PCI_DEVICE,
- PCI_LATENCY_TIMER, &timer);
- if (timer < 0x60) {
- pcibios_write_config_byte(pb, PCI_DEVICE,
- PCI_LATENCY_TIMER, 0x60);
- }
-
- DevicePresent(DE4X5_APROM);
- if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
- dev->irq = irq;
- if ((status = de4x5_hw_init(dev, iobase)) == 0) {
- num_de4x5s++;
- if (loading_module) {
- link_modules(lastModule, dev);
- lastPCI = index;
- }
- return;
- }
- } else if (ioaddr != 0) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name,
- (u_short) iobase);
- }
- }
- }
-
- if (loading_module)
- lastPCI = NO_MORE_PCI;
+ if (!(status & PCI_COMMAND_IO)) continue;
- return;
+ if (!(status & PCI_COMMAND_MASTER)) {
+ status |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ }
+ if (!(status & PCI_COMMAND_MASTER)) continue;
+
+ /* Check the latency timer for values >= 0x60 */
+ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
+ if (timer < 0x60) {
+ pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
+ }
+
+ DevicePresent(DE4X5_APROM);
+ if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+ dev->irq = irq;
+ if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+ num_de4x5s++;
+ if (loading_module) {
+ link_modules(lastModule, dev);
+ lastPCI = index;
+ }
+ return;
+ }
+ } else if (ioaddr != 0) {
+ printk("%s: region already allocated at 0x%04lx.\n", dev->name,
+ iobase);
+ }
+ }
+ }
+
+ if (loading_module) lastPCI = NO_MORE_PCI;
+
+ return;
}
/*
@@ -2156,95 +2214,106 @@ __initfunc(static void
** For single port cards this is a time waster...
*/
__initfunc(static void
- srom_search(int index))
+srom_search(int index))
{
- u_char irq, pb, dev_fn;
- u_short dev_id, dev_num, vendor, status;
- u_int class = DE4X5_CLASS_CODE;
- u_int device, iobase;
- int i, j;
- struct bus_type *lp = &bus;
-
- for (;
- (pcibios_find_class(class, index,
- &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
- index++) {
-
- if (lp->bus_num != pb)
- return;
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
- continue;
- }
+ u_char pb, dev_fn, tirq;
+ u_short dev_id, dev_num, vendor, status;
+ u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE;
+ u_long iobase = 0; /* Clear upper 32 bits in Alphas */
+ int i, j;
+ struct bus_type *lp = &bus;
+
+ for (;
+ (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+ index++) {
+
+ if (lp->bus_num != pb) return;
+ dev_num = PCI_SLOT(dev_fn);
+#ifdef __sparc_v9__
+ struct pci_dev *pdev;
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break;
+ }
+#endif
+ device = 0;
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+ device = dev_id;
+ device <<= 8;
+ if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+ continue;
+ }
- /* Get the chip configuration revision register */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
+ /* Get the chip configuration revision register */
+ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
- /* Set the device number information */
- lp->device = dev_num;
- lp->bus_num = pb;
-
- /* Set the chipset information */
- if (is_DC2114x)
- device |= (cfrv & CFRV_RN);
- lp->chipset = device;
-
- /* Get the board I/O address */
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
- iobase &= CBIO_MASK;
-
- /* Fetch the IRQ to be used */
- pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
- if ((irq == 0) || (irq == (u_char) 0xff))
- continue;
+ /* Set the device number information */
+ lp->device = dev_num;
+ lp->bus_num = pb;
- /* Check if I/O accesses are enabled */
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- if (!(status & PCI_COMMAND_IO))
- continue;
+ /* Set the chipset information */
+ if (is_DC2114x) device |= (cfrv & CFRV_RN);
+ lp->chipset = device;
- /* Search for a valid SROM attached to this DECchip */
- DevicePresent(DE4X5_APROM);
- for (j=0, i=0; i<ETH_ALEN; i++) {
- j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
- }
- if ((j != 0) && (j != 0x5fa)) {
- last.chipset = device;
- last.bus = pb;
- last.irq = irq;
- for (i=0; i<ETH_ALEN; i++) {
- last.addr[i] =
- (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
- }
- return;
- }
- }
+ /* Get the board I/O address (64 bits on sparc64) */
+#ifndef __sparc_v9__
+ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp);
+ iobase = tmp;
+#else
+ iobase = pdev->base_address[0];
+#endif
+ iobase &= CBIO_MASK;
- return;
+ /* Fetch the IRQ to be used */
+#ifndef __sparc_v9__
+ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq);
+ irq = tirq;
+#else
+ irq = pdev->irq;
+#endif
+ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+
+ /* Check if I/O accesses are enabled */
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ if (!(status & PCI_COMMAND_IO)) continue;
+
+ /* Search for a valid SROM attached to this DECchip */
+ DevicePresent(DE4X5_APROM);
+ for (j=0, i=0; i<ETH_ALEN; i++) {
+ j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
+ }
+ if ((j != 0) && (j != 0x5fa)) {
+ last.chipset = device;
+ last.bus = pb;
+ last.irq = irq;
+ for (i=0; i<ETH_ALEN; i++) {
+ last.addr[i] = (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
+ }
+ return;
+ }
+ }
+
+ return;
}
__initfunc(static void
- link_modules(struct device *dev, struct device *tmp))
+link_modules(struct device *dev, struct device *tmp))
{
- struct device *p = dev;
+ struct device *p=dev;
- if (p) {
- while (((struct de4x5_private *) (p->priv))->next_module) {
- p = ((struct de4x5_private *) (p->priv))->next_module;
- }
+ if (p) {
+ while (((struct de4x5_private *)(p->priv))->next_module) {
+ p = ((struct de4x5_private *)(p->priv))->next_module;
+ }
- if (dev != tmp) {
- ((struct de4x5_private *) (p->priv))->next_module = tmp;
- } else {
- ((struct de4x5_private *) (p->priv))->next_module = NULL;
- }
+ if (dev != tmp) {
+ ((struct de4x5_private *)(p->priv))->next_module = tmp;
+ } else {
+ ((struct de4x5_private *)(p->priv))->next_module = NULL;
}
- return;
+ }
+
+ return;
}
/*
@@ -2254,31 +2323,33 @@ __initfunc(static void
** [TP] or no recent receive activity) to check whether the user has been
** sneaky and changed the port on us.
*/
-static int autoconf_media(struct device *dev)
+static int
+autoconf_media(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- lp->linkOK = 0;
- lp->c_media = AUTO; /* Bogus last media */
- disable_ast(dev);
- inl(DE4X5_MFC); /* Zero the lost frames counter */
- lp->media = INIT;
- lp->tcount = 0;
-
- if (lp->useSROM) {
- next_tick = srom_autoconf(dev);
- } else if (lp->chipset == DC21040) {
- next_tick = dc21040_autoconf(dev);
- } else if (lp->chipset == DC21041) {
- next_tick = dc21041_autoconf(dev);
- } else if (lp->chipset == DC21140) {
- next_tick = dc21140m_autoconf(dev);
- }
- enable_ast(dev, next_tick);
-
- return (lp->media);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ lp->linkOK = 0;
+ lp->c_media = AUTO; /* Bogus last media */
+ disable_ast(dev);
+ inl(DE4X5_MFC); /* Zero the lost frames counter */
+ lp->media = INIT;
+ lp->tcount = 0;
+
+ if (lp->useSROM) {
+ next_tick = srom_autoconf(dev);
+ } else if (lp->chipset == DC21040) {
+ next_tick = dc21040_autoconf(dev);
+ } else if (lp->chipset == DC21041) {
+ next_tick = dc21041_autoconf(dev);
+ } else if (lp->chipset == DC21140) {
+ next_tick = dc21140m_autoconf(dev);
+ }
+
+ enable_ast(dev, next_tick);
+
+ return (lp->media);
}
/*
@@ -2293,146 +2364,149 @@ static int autoconf_media(struct device *dev)
** I may have to "age out" locally queued packets so that the higher layer
** timeouts don't effectively duplicate packets on the network.
*/
-static int dc21040_autoconf(struct device *dev)
+static int
+dc21040_autoconf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int next_tick = DE4X5_AUTOSENSE_MS;
- s32 imr;
-
- switch (lp->media) {
- case INIT:
- DISABLE_IRQs;
- lp->tx_enable = NO;
- lp->timeout = -1;
- de4x5_save_skbs(dev);
- if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
- lp->media = TP;
- } else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) {
- lp->media = BNC_AUI;
- } else if (lp->autosense == EXT_SIA) {
- lp->media = EXT_SIA;
- } else {
- lp->media = NC;
- }
- lp->local_state = 0;
- next_tick = dc21040_autoconf(dev);
- break;
-
- case TP:
- next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
- TP_SUSPECT, test_tp);
- break;
-
- case TP_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
- break;
-
- case BNC:
- case AUI:
- case BNC_AUI:
- next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
- BNC_AUI_SUSPECT, ping_media);
- break;
-
- case BNC_AUI_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
- break;
-
- case EXT_SIA:
- next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
- NC, EXT_SIA_SUSPECT, ping_media);
- break;
-
- case EXT_SIA_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
- break;
-
- case NC:
- /* default to TP for all */
- reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
- }
- lp->media = INIT;
- lp->tx_enable = NO;
- break;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+ s32 imr;
+
+ switch (lp->media) {
+ case INIT:
+ DISABLE_IRQs;
+ lp->tx_enable = NO;
+ lp->timeout = -1;
+ de4x5_save_skbs(dev);
+ if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
+ lp->media = TP;
+ } else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) {
+ lp->media = BNC_AUI;
+ } else if (lp->autosense == EXT_SIA) {
+ lp->media = EXT_SIA;
+ } else {
+ lp->media = NC;
}
-
- return next_tick;
+ lp->local_state = 0;
+ next_tick = dc21040_autoconf(dev);
+ break;
+
+ case TP:
+ next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI,
+ TP_SUSPECT, test_tp);
+ break;
+
+ case TP_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
+ break;
+
+ case BNC:
+ case AUI:
+ case BNC_AUI:
+ next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA,
+ BNC_AUI_SUSPECT, ping_media);
+ break;
+
+ case BNC_AUI_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
+ break;
+
+ case EXT_SIA:
+ next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000,
+ NC, EXT_SIA_SUSPECT, ping_media);
+ break;
+
+ case EXT_SIA_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
+ break;
+
+ case NC:
+ /* default to TP for all */
+ reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
+ }
+ lp->media = INIT;
+ lp->tx_enable = NO;
+ break;
+ }
+
+ return next_tick;
}
-static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
- int next_state, int suspect_state,
- int (*fn) (struct device *, int))
+static int
+dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout,
+ int next_state, int suspect_state,
+ int (*fn)(struct device *, int))
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int next_tick = DE4X5_AUTOSENSE_MS;
- int linkBad;
-
- switch (lp->local_state) {
- case 0:
- reset_init_sia(dev, csr13, csr14, csr15);
- lp->local_state++;
- next_tick = 500;
- break;
-
- case 1:
- if (!lp->tx_enable) {
- linkBad = fn(dev, timeout);
- if (linkBad < 0) {
- next_tick = linkBad & ~TIMER_CB;
- } else {
- if (linkBad && (lp->autosense == AUTO)) {
- lp->local_state = 0;
- lp->media = next_state;
- } else {
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = suspect_state;
- next_tick = 3000;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+ int linkBad;
+
+ switch (lp->local_state) {
+ case 0:
+ reset_init_sia(dev, csr13, csr14, csr15);
+ lp->local_state++;
+ next_tick = 500;
+ break;
+
+ case 1:
+ if (!lp->tx_enable) {
+ linkBad = fn(dev, timeout);
+ if (linkBad < 0) {
+ next_tick = linkBad & ~TIMER_CB;
+ } else {
+ if (linkBad && (lp->autosense == AUTO)) {
+ lp->local_state = 0;
+ lp->media = next_state;
+ } else {
+ de4x5_init_connection(dev);
}
- break;
+ }
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = suspect_state;
+ next_tick = 3000;
}
-
- return next_tick;
+ break;
+ }
+
+ return next_tick;
}
-static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
- int (*fn) (struct device *, int),
- int (*asfn) (struct device *))
+static int
+de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
+ int (*fn)(struct device *, int),
+ int (*asfn)(struct device *))
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int next_tick = DE4X5_AUTOSENSE_MS;
- int linkBad;
-
- switch (lp->local_state) {
- case 1:
- if (lp->linkOK) {
- lp->media = prev_state;
- } else {
- lp->local_state++;
- next_tick = asfn(dev);
- }
- break;
-
- case 2:
- linkBad = fn(dev, timeout);
- if (linkBad < 0) {
- next_tick = linkBad & ~TIMER_CB;
- } else if (!linkBad) {
- lp->local_state--;
- lp->media = prev_state;
- } else {
- lp->media = INIT;
- lp->tcount++;
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+ int linkBad;
+
+ switch (lp->local_state) {
+ case 1:
+ if (lp->linkOK) {
+ lp->media = prev_state;
+ } else {
+ lp->local_state++;
+ next_tick = asfn(dev);
+ }
+ break;
+
+ case 2:
+ linkBad = fn(dev, timeout);
+ if (linkBad < 0) {
+ next_tick = linkBad & ~TIMER_CB;
+ } else if (!linkBad) {
+ lp->local_state--;
+ lp->media = prev_state;
+ } else {
+ lp->media = INIT;
+ lp->tcount++;
}
+ }
- return next_tick;
+ return next_tick;
}
/*
@@ -2444,200 +2518,201 @@ static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state,
** any more packets to be queued to the hardware. Re-enable everything only
** when the media is found.
*/
-static int dc21041_autoconf(struct device *dev)
+static int
+dc21041_autoconf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 sts, irqs, irq_mask, imr, omr;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- switch (lp->media) {
- case INIT:
- DISABLE_IRQs;
- lp->tx_enable = NO;
- lp->timeout = -1;
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
- if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
- lp->media = TP; /* On chip auto negotiation is broken */
- } else if (lp->autosense == TP) {
- lp->media = TP;
- } else if (lp->autosense == BNC) {
- lp->media = BNC;
- } else if (lp->autosense == AUI) {
- lp->media = AUI;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 sts, irqs, irq_mask, imr, omr;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ switch (lp->media) {
+ case INIT:
+ DISABLE_IRQs;
+ lp->tx_enable = NO;
+ lp->timeout = -1;
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
+ lp->media = TP; /* On chip auto negotiation is broken */
+ } else if (lp->autosense == TP) {
+ lp->media = TP;
+ } else if (lp->autosense == BNC) {
+ lp->media = BNC;
+ } else if (lp->autosense == AUI) {
+ lp->media = AUI;
+ } else {
+ lp->media = NC;
+ }
+ lp->local_state = 0;
+ next_tick = dc21041_autoconf(dev);
+ break;
+
+ case TP_NW:
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
+ outl(omr | OMR_FDX, DE4X5_OMR);
+ }
+ irqs = STS_LNF | STS_LNP;
+ irq_mask = IMR_LFM | IMR_LPM;
+ sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (sts & STS_LNP) {
+ lp->media = ANS;
+ } else {
+ lp->media = AUI;
+ }
+ next_tick = dc21041_autoconf(dev);
+ }
+ break;
+
+ case ANS:
+ if (!lp->tx_enable) {
+ irqs = STS_LNP;
+ irq_mask = IMR_LPM;
+ sts = test_ans(dev, irqs, irq_mask, 3000);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+ lp->media = TP;
+ next_tick = dc21041_autoconf(dev);
} else {
- lp->media = NC;
+ lp->local_state = 1;
+ de4x5_init_connection(dev);
}
- lp->local_state = 0;
- next_tick = dc21041_autoconf(dev);
- break;
-
- case TP_NW:
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
- outl(omr | OMR_FDX, DE4X5_OMR);
- }
- irqs = STS_LNF | STS_LNP;
- irq_mask = IMR_LFM | IMR_LPM;
- sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
+ }
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = ANS_SUSPECT;
+ next_tick = 3000;
+ }
+ break;
+
+ case ANS_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
+ break;
+
+ case TP:
+ if (!lp->tx_enable) {
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR); /* Set up half duplex for TP */
+ outl(omr & ~OMR_FDX, DE4X5_OMR);
+ }
+ irqs = STS_LNF | STS_LNP;
+ irq_mask = IMR_LFM | IMR_LPM;
+ sts = test_media(dev,irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+ if (inl(DE4X5_SISR) & SISR_NRA) {
+ lp->media = AUI; /* Non selected port activity */
+ } else {
+ lp->media = BNC;
+ }
+ next_tick = dc21041_autoconf(dev);
} else {
- if (sts & STS_LNP) {
- lp->media = ANS;
- } else {
- lp->media = AUI;
- }
- next_tick = dc21041_autoconf(dev);
- }
- break;
-
- case ANS:
- if (!lp->tx_enable) {
- irqs = STS_LNP;
- irq_mask = IMR_LPM;
- sts = test_ans(dev, irqs, irq_mask, 3000);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
- lp->media = TP;
- next_tick = dc21041_autoconf(dev);
- } else {
- lp->local_state = 1;
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = ANS_SUSPECT;
- next_tick = 3000;
+ lp->local_state = 1;
+ de4x5_init_connection(dev);
}
- break;
-
- case ANS_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
- break;
-
- case TP:
- if (!lp->tx_enable) {
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for TP */
- outl(omr & ~OMR_FDX, DE4X5_OMR);
- }
- irqs = STS_LNF | STS_LNP;
- irq_mask = IMR_LFM | IMR_LPM;
- sts = test_media(dev, irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
- if (inl(DE4X5_SISR) & SISR_NRA) {
- lp->media = AUI; /* Non selected port activity */
- } else {
- lp->media = BNC;
- }
- next_tick = dc21041_autoconf(dev);
- } else {
- lp->local_state = 1;
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = TP_SUSPECT;
- next_tick = 3000;
- }
- break;
-
- case TP_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
- break;
-
- case AUI:
- if (!lp->tx_enable) {
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
- outl(omr & ~OMR_FDX, DE4X5_OMR);
- }
- irqs = 0;
- irq_mask = 0;
- sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
- lp->media = BNC;
- next_tick = dc21041_autoconf(dev);
- } else {
- lp->local_state = 1;
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = AUI_SUSPECT;
- next_tick = 3000;
- }
- break;
-
- case AUI_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
- break;
-
- case BNC:
- switch (lp->local_state) {
- case 0:
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
- outl(omr & ~OMR_FDX, DE4X5_OMR);
- }
- irqs = 0;
- irq_mask = 0;
- sts = test_media(dev, irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- lp->local_state++; /* Ensure media connected */
- next_tick = dc21041_autoconf(dev);
- }
- break;
-
- case 1:
- if (!lp->tx_enable) {
- if ((sts = ping_media(dev, 3000)) < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (sts) {
- lp->local_state = 0;
- lp->media = NC;
- } else {
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = BNC_SUSPECT;
- next_tick = 3000;
- }
- break;
+ }
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = TP_SUSPECT;
+ next_tick = 3000;
+ }
+ break;
+
+ case TP_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
+ break;
+
+ case AUI:
+ if (!lp->tx_enable) {
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
+ outl(omr & ~OMR_FDX, DE4X5_OMR);
+ }
+ irqs = 0;
+ irq_mask = 0;
+ sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+ lp->media = BNC;
+ next_tick = dc21041_autoconf(dev);
+ } else {
+ lp->local_state = 1;
+ de4x5_init_connection(dev);
}
- break;
-
- case BNC_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
- break;
-
- case NC:
- omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
- outl(omr | OMR_FDX, DE4X5_OMR);
- reset_init_sia(dev, 0xef01, 0xffff, 0x0008); /* Initialise the SIA */
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
+ }
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = AUI_SUSPECT;
+ next_tick = 3000;
+ }
+ break;
+
+ case AUI_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
+ break;
+
+ case BNC:
+ switch (lp->local_state) {
+ case 0:
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
+ outl(omr & ~OMR_FDX, DE4X5_OMR);
+ }
+ irqs = 0;
+ irq_mask = 0;
+ sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ lp->local_state++; /* Ensure media connected */
+ next_tick = dc21041_autoconf(dev);
+ }
+ break;
+
+ case 1:
+ if (!lp->tx_enable) {
+ if ((sts = ping_media(dev, 3000)) < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (sts) {
+ lp->local_state = 0;
+ lp->media = NC;
+ } else {
+ de4x5_init_connection(dev);
+ }
}
- lp->media = INIT;
- lp->tx_enable = NO;
- break;
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = BNC_SUSPECT;
+ next_tick = 3000;
+ }
+ break;
}
-
- return next_tick;
+ break;
+
+ case BNC_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
+ break;
+
+ case NC:
+ omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */
+ outl(omr | OMR_FDX, DE4X5_OMR);
+ reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
+ }
+ lp->media = INIT;
+ lp->tx_enable = NO;
+ break;
+ }
+
+ return next_tick;
}
/*
@@ -2645,174 +2720,172 @@ static int dc21041_autoconf(struct device *dev)
** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
** register, except at the first power up negotiation.
*/
-static int dc21140m_autoconf(struct device *dev)
+static int
+dc21140m_autoconf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int ana, anlpa, cap, cr, slnk, sr;
- u_long iobase = dev->base_addr;
- int next_tick = DE4X5_AUTOSENSE_MS;
- u_long imr, omr;
-
- switch (lp->media) {
- case INIT:
- if (lp->timeout < 0) {
- DISABLE_IRQs;
- lp->tx_enable = FALSE;
- lp->linkOK = 0;
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
- }
- if ((next_tick = de4x5_reset_phy(dev)) < 0) {
- next_tick &= ~TIMER_CB;
- } else {
- if (lp->useSROM) {
- if (srom_map_media(dev) < 0) {
- lp->tcount++;
- return next_tick;
- }
- srom_exec(dev, lp->phy[lp->active].gep);
- if (lp->infoblock_media == ANS) {
- ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
- mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
- }
- } else {
- lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */
- SET_10Mb;
- if (lp->autosense == _100Mb) {
- lp->media = _100Mb;
- } else if (lp->autosense == _10Mb) {
- lp->media = _10Mb;
- } else if ((lp->autosense == AUTO) &&
- ((sr = is_anc_capable(dev)) & MII_SR_ANC)) {
- ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
- ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
- mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
- lp->media = ANS;
- } else if (lp->autosense == AUTO) {
- lp->media = SPD_DET;
- } else if (is_spd_100(dev) && is_100_up(dev)) {
- lp->media = _100Mb;
- } else {
- lp->media = NC;
- }
- }
- lp->local_state = 0;
- next_tick = dc21140m_autoconf(dev);
- }
- break;
-
- case ANS:
- switch (lp->local_state) {
- case 0:
- if (lp->timeout < 0) {
- mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
- }
- cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
- if (cr < 0) {
- next_tick = cr & ~TIMER_CB;
- } else {
- if (cr) {
- lp->local_state = 0;
- lp->media = SPD_DET;
- } else {
- lp->local_state++;
- }
- next_tick = dc21140m_autoconf(dev);
- }
- break;
-
- case 1:
- if ((sr = test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
- next_tick = sr & ~TIMER_CB;
- } else {
- lp->media = SPD_DET;
- lp->local_state = 0;
- if (sr) { /* Success! */
- lp->tmp = MII_SR_ASSC;
- anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
- ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
- if (!(anlpa & MII_ANLPA_RF) &&
- (cap = anlpa & MII_ANLPA_TAF & ana)) {
- if (cap & MII_ANA_100M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
- lp->media = _100Mb;
- } else if (cap & MII_ANA_10M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
-
- lp->media = _10Mb;
- }
- }
- } /* Auto Negotiation failed to finish */
- next_tick = dc21140m_autoconf(dev);
- } /* Auto Negotiation failed to start */
- break;
- }
- break;
-
- case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
- if (lp->timeout < 0) {
- lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
- (~gep_rd(dev) & GEP_LNP));
- SET_100Mb_PDET;
- }
- if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
- next_tick = slnk & ~TIMER_CB;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int ana, anlpa, cap, cr, slnk, sr;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+ u_long imr, omr, iobase = dev->base_addr;
+
+ switch(lp->media) {
+ case INIT:
+ if (lp->timeout < 0) {
+ DISABLE_IRQs;
+ lp->tx_enable = FALSE;
+ lp->linkOK = 0;
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ }
+ if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+ next_tick &= ~TIMER_CB;
+ } else {
+ if (lp->useSROM) {
+ if (srom_map_media(dev) < 0) {
+ lp->tcount++;
+ return next_tick;
+ }
+ srom_exec(dev, lp->phy[lp->active].gep);
+ if (lp->infoblock_media == ANS) {
+ ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+ mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ }
+ } else {
+ lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */
+ SET_10Mb;
+ if (lp->autosense == _100Mb) {
+ lp->media = _100Mb;
+ } else if (lp->autosense == _10Mb) {
+ lp->media = _10Mb;
+ } else if ((lp->autosense == AUTO) &&
+ ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+ ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+ ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+ mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ lp->media = ANS;
+ } else if (lp->autosense == AUTO) {
+ lp->media = SPD_DET;
+ } else if (is_spd_100(dev) && is_100_up(dev)) {
+ lp->media = _100Mb;
} else {
- if (is_spd_100(dev) && is_100_up(dev)) {
- lp->media = _100Mb;
- } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
- lp->media = _10Mb;
- } else {
- lp->media = NC;
- }
- next_tick = dc21140m_autoconf(dev);
+ lp->media = NC;
}
- break;
-
- case _100Mb: /* Set 100Mb/s */
- next_tick = 3000;
- if (!lp->tx_enable) {
- SET_100Mb;
- de4x5_init_connection(dev);
+ }
+ lp->local_state = 0;
+ next_tick = dc21140m_autoconf(dev);
+ }
+ break;
+
+ case ANS:
+ switch (lp->local_state) {
+ case 0:
+ if (lp->timeout < 0) {
+ mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+ }
+ cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+ if (cr < 0) {
+ next_tick = cr & ~TIMER_CB;
+ } else {
+ if (cr) {
+ lp->local_state = 0;
+ lp->media = SPD_DET;
} else {
- if (!lp->linkOK && (lp->autosense == AUTO)) {
- if (!is_100_up(dev) ||
- (!lp->useSROM && !is_spd_100(dev))) {
- lp->media = INIT;
- lp->tcount++;
- next_tick = DE4X5_AUTOSENSE_MS;
- }
- }
+ lp->local_state++;
}
- break;
-
- case _10Mb: /* Set 10Mb/s */
- next_tick = 3000;
- if (!lp->tx_enable) {
- SET_10Mb;
- de4x5_init_connection(dev);
- } else {
- if (!lp->linkOK && (lp->autosense == AUTO)) {
- if (!is_10_up(dev) ||
- (!lp->useSROM && is_spd_100(dev))) {
- lp->media = INIT;
- lp->tcount++;
- next_tick = DE4X5_AUTOSENSE_MS;
- }
+ next_tick = dc21140m_autoconf(dev);
+ }
+ break;
+
+ case 1:
+ if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+ next_tick = sr & ~TIMER_CB;
+ } else {
+ lp->media = SPD_DET;
+ lp->local_state = 0;
+ if (sr) { /* Success! */
+ lp->tmp = MII_SR_ASSC;
+ anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+ ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ if (!(anlpa & MII_ANLPA_RF) &&
+ (cap = anlpa & MII_ANLPA_TAF & ana)) {
+ if (cap & MII_ANA_100M) {
+ lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+ lp->media = _100Mb;
+ } else if (cap & MII_ANA_10M) {
+ lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+
+ lp->media = _10Mb;
}
+ }
+ } /* Auto Negotiation failed to finish */
+ next_tick = dc21140m_autoconf(dev);
+ } /* Auto Negotiation failed to start */
+ break;
+ }
+ break;
+
+ case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
+ if (lp->timeout < 0) {
+ lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
+ (~gep_rd(dev) & GEP_LNP));
+ SET_100Mb_PDET;
+ }
+ if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+ next_tick = slnk & ~TIMER_CB;
+ } else {
+ if (is_spd_100(dev) && is_100_up(dev)) {
+ lp->media = _100Mb;
+ } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
+ lp->media = _10Mb;
+ } else {
+ lp->media = NC;
+ }
+ next_tick = dc21140m_autoconf(dev);
+ }
+ break;
+
+ case _100Mb: /* Set 100Mb/s */
+ next_tick = 3000;
+ if (!lp->tx_enable) {
+ SET_100Mb;
+ de4x5_init_connection(dev);
+ } else {
+ if (!lp->linkOK && (lp->autosense == AUTO)) {
+ if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+ lp->media = INIT;
+ lp->tcount++;
+ next_tick = DE4X5_AUTOSENSE_MS;
}
- break;
-
- case NC:
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
+ }
+ }
+ break;
+
+ case _10Mb: /* Set 10Mb/s */
+ next_tick = 3000;
+ if (!lp->tx_enable) {
+ SET_10Mb;
+ de4x5_init_connection(dev);
+ } else {
+ if (!lp->linkOK && (lp->autosense == AUTO)) {
+ if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+ lp->media = INIT;
+ lp->tcount++;
+ next_tick = DE4X5_AUTOSENSE_MS;
}
- lp->media = INIT;
- lp->tx_enable = FALSE;
- break;
+ }
}
-
- return next_tick;
+ break;
+
+ case NC:
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
+ }
+ lp->media = INIT;
+ lp->tx_enable = FALSE;
+ break;
+ }
+
+ return next_tick;
}
/*
@@ -2832,241 +2905,231 @@ static int dc21140m_autoconf(struct device *dev)
static int
dc2114x_autoconf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- switch (lp->media) {
- case INIT:
- if (lp->timeout < 0) {
- DISABLE_IRQs;
- lp->tx_enable = FALSE;
- lp->linkOK = 0;
- lp->timeout = -1;
- de4x5_save_skbs(dev); /* Save non transmitted skb's */
- }
- if ((next_tick = de4x5_reset_phy(dev)) < 0) {
- next_tick &= ~TIMER_CB;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ switch (lp->media) {
+ case INIT:
+ if (lp->timeout < 0) {
+ DISABLE_IRQs;
+ lp->tx_enable = FALSE;
+ lp->linkOK = 0;
+ lp->timeout = -1;
+ de4x5_save_skbs(dev); /* Save non transmitted skb's */
+ }
+ if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+ next_tick &= ~TIMER_CB;
+ } else {
+ lp->media = SPD_DET;
+ if ((lp->infoblock_media == ANS) &&
+ ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+ ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+ ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+ mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ lp->media = ANS;
+ }
+ lp->local_state = 0;
+ next_tick = dc2114x_autoconf(dev);
+ }
+ break;
+
+ case ANS:
+ switch (lp->local_state) {
+ case 0:
+ if (lp->timeout < 0) {
+ mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+ }
+ cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+ if (cr < 0) {
+ next_tick = cr & ~TIMER_CB;
+ } else {
+ if (cr) {
+ lp->local_state = 0;
+ lp->media = SPD_DET;
} else {
- lp->media = SPD_DET;
- if ((lp->infoblock_media == ANS) &&
- ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
- ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
- ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
- mii_wr(ana, MII_ANA,
- lp->phy[lp->active].addr,
- DE4X5_MII);
- lp->media = ANS;
- }
- lp->local_state = 0;
- next_tick = dc2114x_autoconf(dev);
+ lp->local_state++;
}
- break;
-
- case ANS:
- switch (lp->local_state) {
- case 0:
- if (lp->timeout < 0) {
- mii_wr(MII_CR_ASSE | MII_CR_RAN,
- MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
- }
- cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
- if (cr < 0) {
- next_tick = cr & ~TIMER_CB;
- } else {
- if (cr) {
- lp->local_state = 0;
- lp->media = SPD_DET;
- } else {
- lp->local_state++;
- }
- next_tick = dc2114x_autoconf(dev);
- }
- break;
+ next_tick = dc2114x_autoconf(dev);
+ }
+ break;
- case 1:
- if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
- next_tick = sr & ~TIMER_CB;
- } else {
- lp->media = SPD_DET;
- lp->local_state = 0;
- if (sr) { /* Success! */
- lp->tmp = MII_SR_ASSC;
- anlpa = mii_rd(MII_ANLPA,
- lp->phy[lp->active].addr,
- DE4X5_MII);
- ana = mii_rd(MII_ANA,
- lp->phy[lp->active].addr,
- DE4X5_MII);
- if (!(anlpa & MII_ANLPA_RF) &&
- (cap = anlpa & MII_ANLPA_TAF & ana)) {
- if (cap & MII_ANA_100M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
- lp->media = _100Mb;
- } else if (cap & MII_ANA_10M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
- lp->media = _10Mb;
- }
- }
- } /* Auto Negotiation failed to finish */
- next_tick = dc2114x_autoconf(dev);
- } /* Auto Negotiation failed to start */
- break;
- }
- break;
-
- case AUI:
- if (!lp->tx_enable) {
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
- outl(omr & ~OMR_FDX, DE4X5_OMR);
- }
- irqs = 0;
- irq_mask = 0;
- sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
- lp->media = BNC;
- next_tick = dc2114x_autoconf(dev);
- } else {
- lp->local_state = 1;
- de4x5_init_connection(dev);
- }
+ case 1:
+ if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+ next_tick = sr & ~TIMER_CB;
+ } else {
+ lp->media = SPD_DET;
+ lp->local_state = 0;
+ if (sr) { /* Success! */
+ lp->tmp = MII_SR_ASSC;
+ anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+ ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+ if (!(anlpa & MII_ANLPA_RF) &&
+ (cap = anlpa & MII_ANLPA_TAF & ana)) {
+ if (cap & MII_ANA_100M) {
+ lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+ lp->media = _100Mb;
+ } else if (cap & MII_ANA_10M) {
+ lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+ lp->media = _10Mb;
}
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = AUI_SUSPECT;
- next_tick = 3000;
- }
- break;
-
- case AUI_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, AUI,
- ping_media, dc2114x_autoconf);
- break;
+ }
+ } /* Auto Negotiation failed to finish */
+ next_tick = dc2114x_autoconf(dev);
+ } /* Auto Negotiation failed to start */
+ break;
+ }
+ break;
- case BNC:
- switch (lp->local_state) {
- case 0:
- if (lp->timeout < 0) {
- omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
- outl(omr & ~OMR_FDX, DE4X5_OMR);
- }
- irqs = 0;
- irq_mask = 0;
- sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
- if (sts < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- lp->local_state++; /* Ensure media connected */
- next_tick = dc2114x_autoconf(dev);
- }
- break;
-
- case 1:
- if (!lp->tx_enable) {
- if ((sts = ping_media(dev, 3000)) < 0) {
- next_tick = sts & ~TIMER_CB;
- } else {
- if (sts) {
- lp->local_state = 0;
- lp->tcount++;
- lp->media = INIT;
- } else {
- de4x5_init_connection(dev);
- }
- }
- } else if (!lp->linkOK && (lp->autosense == AUTO)) {
- lp->media = BNC_SUSPECT;
- next_tick = 3000;
- }
- break;
+ case AUI:
+ if (!lp->tx_enable) {
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR); /* Set up half duplex for AUI */
+ outl(omr & ~OMR_FDX, DE4X5_OMR);
+ }
+ irqs = 0;
+ irq_mask = 0;
+ sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+ lp->media = BNC;
+ next_tick = dc2114x_autoconf(dev);
+ } else {
+ lp->local_state = 1;
+ de4x5_init_connection(dev);
}
- break;
+ }
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = AUI_SUSPECT;
+ next_tick = 3000;
+ }
+ break;
- case BNC_SUSPECT:
- next_tick = de4x5_suspect_state(dev, 1000, BNC,
- ping_media, dc2114x_autoconf);
- break;
+ case AUI_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
+ break;
- case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
- if (srom_map_media(dev) < 0) {
- lp->tcount++;
- lp->media = INIT;
- return next_tick;
- }
- if (lp->media == _100Mb) {
- if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
- lp->media = SPD_DET;
- return (slnk & ~TIMER_CB);
- }
- } else {
- if (wait_for_link(dev) < 0) {
- lp->media = SPD_DET;
- return PDET_LINK_WAIT;
- }
- }
- if (((lp->media == _100Mb) && is_100_up(dev)) ||
- ((lp->media == _10Mb) && is_10_up(dev)) ||
- (lp->media == BNC) || (lp->media == AUI)) {
- next_tick = dc2114x_autoconf(dev);
+ case BNC:
+ switch (lp->local_state) {
+ case 0:
+ if (lp->timeout < 0) {
+ omr = inl(DE4X5_OMR); /* Set up half duplex for BNC */
+ outl(omr & ~OMR_FDX, DE4X5_OMR);
+ }
+ irqs = 0;
+ irq_mask = 0;
+ sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+ if (sts < 0) {
+ next_tick = sts & ~TIMER_CB;
+ } else {
+ lp->local_state++; /* Ensure media connected */
+ next_tick = dc2114x_autoconf(dev);
+ }
+ break;
+
+ case 1:
+ if (!lp->tx_enable) {
+ if ((sts = ping_media(dev, 3000)) < 0) {
+ next_tick = sts & ~TIMER_CB;
} else {
+ if (sts) {
+ lp->local_state = 0;
lp->tcount++;
lp->media = INIT;
- }
- break;
-
- case _10Mb:
- next_tick = 3000;
- if (!lp->tx_enable) {
- SET_10Mb;
+ } else {
de4x5_init_connection(dev);
- } else {
- if (!lp->linkOK && (lp->autosense == AUTO)) {
- if (!is_10_up(dev) ||
- (!lp->useSROM && is_spd_100(dev))) {
- lp->media = INIT;
- lp->tcount++;
- next_tick = DE4X5_AUTOSENSE_MS;
- }
- }
+ }
}
- break;
-
- case _100Mb:
+ } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+ lp->media = BNC_SUSPECT;
next_tick = 3000;
- if (!lp->tx_enable) {
- SET_100Mb;
- de4x5_init_connection(dev);
- } else {
- if (!lp->linkOK && (lp->autosense == AUTO)) {
- if (!is_100_up(dev) ||
- (!lp->useSROM && !is_spd_100(dev))) {
- lp->media = INIT;
- lp->tcount++;
- next_tick = DE4X5_AUTOSENSE_MS;
- }
- }
+ }
+ break;
+ }
+ break;
+
+ case BNC_SUSPECT:
+ next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
+ break;
+
+ case SPD_DET: /* Choose 10Mb/s or 100Mb/s */
+ if (srom_map_media(dev) < 0) {
+ lp->tcount++;
+ lp->media = INIT;
+ return next_tick;
+ }
+ if (lp->media == _100Mb) {
+ if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+ lp->media = SPD_DET;
+ return (slnk & ~TIMER_CB);
+ }
+ } else {
+ if (wait_for_link(dev) < 0) {
+ lp->media = SPD_DET;
+ return PDET_LINK_WAIT;
+ }
+ }
+ if (((lp->media == _100Mb) && is_100_up(dev)) ||
+ ((lp->media == _10Mb) && is_10_up(dev)) ||
+ (lp->media == BNC) || (lp->media == AUI)) {
+ next_tick = dc2114x_autoconf(dev);
+ } else {
+ lp->tcount++;
+ lp->media = INIT;
+ }
+ break;
+
+ case _10Mb:
+ next_tick = 3000;
+ if (!lp->tx_enable) {
+ SET_10Mb;
+ de4x5_init_connection(dev);
+ } else {
+ if (!lp->linkOK && (lp->autosense == AUTO)) {
+ if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+ lp->media = INIT;
+ lp->tcount++;
+ next_tick = DE4X5_AUTOSENSE_MS;
}
- break;
+ }
+ }
+ break;
- default:
- lp->tcount++;
- printk("Huh?: media:%02x\n", lp->media);
- lp->media = INIT;
- break;
+ case _100Mb:
+ next_tick = 3000;
+ if (!lp->tx_enable) {
+ SET_100Mb;
+ de4x5_init_connection(dev);
+ } else {
+ if (!lp->linkOK && (lp->autosense == AUTO)) {
+ if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+ lp->media = INIT;
+ lp->tcount++;
+ next_tick = DE4X5_AUTOSENSE_MS;
+ }
+ }
}
+ break;
+
+ default:
+ lp->tcount++;
+printk("Huh?: media:%02x\n", lp->media);
+ lp->media = INIT;
+ break;
+ }
- return next_tick;
+ return next_tick;
}
-static int srom_autoconf(struct device *dev)
+static int
+srom_autoconf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- return lp->infoleaf_fn(dev);
+ return lp->infoleaf_fn(dev);
}
/*
@@ -3074,95 +3137,91 @@ static int srom_autoconf(struct device *dev)
** While it isn't strictly necessary, it helps me for the moment...
** The early return avoids a media state / SROM media space clash.
*/
-static int srom_map_media(struct device *dev)
+static int
+srom_map_media(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
- lp->fdx = 0;
- if (lp->infoblock_media == lp->media)
- return 0;
-
- switch(lp->infoblock_media) {
- case SROM_10BASETF:
- if (!de4x5_full_duplex)
- return -1;
- lp->fdx = TRUE;
- case SROM_10BASET:
- if (de4x5_full_duplex && !lp->fdx)
- return -1;
- if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
- lp->media = _10Mb;
- } else {
- lp->media = TP;
- }
- break;
-
- case SROM_10BASE2:
- lp->media = BNC;
- break;
-
- case SROM_10BASE5:
- lp->media = AUI;
- break;
-
- case SROM_100BASETF:
- if (!de4x5_full_duplex)
- return -1;
- lp->fdx = TRUE;
- case SROM_100BASET:
- if (de4x5_full_duplex && !lp->fdx)
- return -1;
- lp->media = _100Mb;
- break;
-
- case SROM_100BASET4:
- lp->media = _100Mb;
- break;
-
- case SROM_100BASEFF:
- if (!de4x5_full_duplex)
- return -1;
- lp->fdx = TRUE;
- case SROM_100BASEF:
- if (de4x5_full_duplex && !lp->fdx)
- return -1;
- lp->media = _100Mb;
- break;
-
- case ANS:
- lp->media = ANS;
- break;
-
- default:
- printk("%s: Bad media code [%d] detected in SROM!\n", dev->name,
- lp->infoblock_media);
- return -1;
- break;
- }
-
- return 0;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+ lp->fdx = 0;
+ if (lp->infoblock_media == lp->media)
+ return 0;
+
+ switch(lp->infoblock_media) {
+ case SROM_10BASETF:
+ if (!lp->params.fdx) return -1;
+ lp->fdx = TRUE;
+ case SROM_10BASET:
+ if (lp->params.fdx && !lp->fdx) return -1;
+ if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
+ lp->media = _10Mb;
+ } else {
+ lp->media = TP;
+ }
+ break;
+
+ case SROM_10BASE2:
+ lp->media = BNC;
+ break;
+
+ case SROM_10BASE5:
+ lp->media = AUI;
+ break;
+
+ case SROM_100BASETF:
+ if (!lp->params.fdx) return -1;
+ lp->fdx = TRUE;
+ case SROM_100BASET:
+ if (lp->params.fdx && !lp->fdx) return -1;
+ lp->media = _100Mb;
+ break;
+
+ case SROM_100BASET4:
+ lp->media = _100Mb;
+ break;
+
+ case SROM_100BASEFF:
+ if (!lp->params.fdx) return -1;
+ lp->fdx = TRUE;
+ case SROM_100BASEF:
+ if (lp->params.fdx && !lp->fdx) return -1;
+ lp->media = _100Mb;
+ break;
+
+ case ANS:
+ lp->media = ANS;
+ break;
+
+ default:
+ printk("%s: Bad media code [%d] detected in SROM!\n", dev->name,
+ lp->infoblock_media);
+ return -1;
+ break;
+ }
+
+ return 0;
}
-static void de4x5_init_connection(struct device *dev)
+static void
+de4x5_init_connection(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
-
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media; /* Stop scrolling media messages */
- }
-
- cli();
- de4x5_restore_skbs(dev);
- de4x5_setup_intr(dev);
- lp->tx_enable = YES;
- dev->tbusy = 0;
- sti();
- outl(POLL_DEMAND, DE4X5_TPD);
- mark_bh(NET_BH);
-
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media; /* Stop scrolling media messages */
+ }
+
+ cli();
+ de4x5_rst_desc_ring(dev);
+ de4x5_setup_intr(dev);
+ lp->tx_enable = YES;
+ dev->tbusy = 0;
+ sti();
+ outl(POLL_DEMAND, DE4X5_TPD);
+ mark_bh(NET_BH);
+
+ return;
}
/*
@@ -3170,94 +3229,98 @@ static void de4x5_init_connection(struct device *dev)
** since their MII address pins can float at voltages that are dependent
** on the signal pin use. Do a double reset to ensure a reset.
*/
-static int de4x5_reset_phy(struct device *dev)
+static int
+de4x5_reset_phy(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
- int next_tick = 0;
-
- if ((lp->useSROM) || (lp->phy[lp->active].id)) {
- if (lp->timeout < 0) {
- if (lp->useSROM) {
- if (lp->phy[lp->active].rst) {
- srom_exec(dev, lp->phy[lp->active].rst);
- srom_exec(dev, lp->phy[lp->active].rst);
- } else if (lp->rst) { /* Type 5 infoblock reset */
- srom_exec(dev, lp->rst);
- srom_exec(dev, lp->rst);
- }
- } else {
- PHY_HARD_RESET;
- }
- if (lp->useMII) {
- mii_wr(MII_CR_RST, MII_CR,
- lp->phy[lp->active].addr, DE4X5_MII);
- }
- }
- if (lp->useMII) {
- next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
- }
- } else if (lp->chipset == DC21140) {
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int next_tick = 0;
+
+ if ((lp->useSROM) || (lp->phy[lp->active].id)) {
+ if (lp->timeout < 0) {
+ if (lp->useSROM) {
+ if (lp->phy[lp->active].rst) {
+ srom_exec(dev, lp->phy[lp->active].rst);
+ srom_exec(dev, lp->phy[lp->active].rst);
+ } else if (lp->rst) { /* Type 5 infoblock reset */
+ srom_exec(dev, lp->rst);
+ srom_exec(dev, lp->rst);
+ }
+ } else {
PHY_HARD_RESET;
+ }
+ if (lp->useMII) {
+ mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+ }
+ }
+ if (lp->useMII) {
+ next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
}
+ } else if (lp->chipset == DC21140) {
+ PHY_HARD_RESET;
+ }
- return next_tick;
+ return next_tick;
}
-static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
+static int
+test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 sts, csr12;
-
- if (lp->timeout < 0) {
- lp->timeout = msec / 100;
- if (!lp->useSROM) { /* Already done if by SROM, else dc2104[01] */
- reset_init_sia(dev, csr13, csr14, csr15);
- }
-
- /* set up the interrupt mask */
- outl(irq_mask, DE4X5_IMR);
-
- /* clear all pending interrupts */
- sts = inl(DE4X5_STS);
- outl(sts, DE4X5_STS);
-
- /* clear csr12 NRA and SRA bits */
- if ((lp->chipset == DC21041) || lp->useSROM) {
- csr12 = inl(DE4X5_SISR);
- outl(csr12, DE4X5_SISR);
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 sts, csr12;
+
+ if (lp->timeout < 0) {
+ lp->timeout = msec/100;
+ if (!lp->useSROM) { /* Already done if by SROM, else dc2104[01] */
+ reset_init_sia(dev, csr13, csr14, csr15);
}
- sts = inl(DE4X5_STS) & ~TIMER_CB;
- if (!(sts & irqs) && --lp->timeout) {
- sts = 100 | TIMER_CB;
- } else {
- lp->timeout = -1;
- }
+ /* set up the interrupt mask */
+ outl(irq_mask, DE4X5_IMR);
- return sts;
+ /* clear all pending interrupts */
+ sts = inl(DE4X5_STS);
+ outl(sts, DE4X5_STS);
+
+ /* clear csr12 NRA and SRA bits */
+ if ((lp->chipset == DC21041) || lp->useSROM) {
+ csr12 = inl(DE4X5_SISR);
+ outl(csr12, DE4X5_SISR);
+ }
+ }
+
+ sts = inl(DE4X5_STS) & ~TIMER_CB;
+
+ if (!(sts & irqs) && --lp->timeout) {
+ sts = 100 | TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
+
+ return sts;
}
-static int test_tp(struct device *dev, s32 msec)
+static int
+test_tp(struct device *dev, s32 msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int sisr;
-
- if (lp->timeout < 0) {
- lp->timeout = msec / 100;
- }
- sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
-
- if (sisr && --lp->timeout) {
- sisr = 100 | TIMER_CB;
- } else {
- lp->timeout = -1;
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int sisr;
+
+ if (lp->timeout < 0) {
+ lp->timeout = msec/100;
+ }
+
+ sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
- return sisr;
+ if (sisr && --lp->timeout) {
+ sisr = 100 | TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
+
+ return sisr;
}
/*
@@ -3267,195 +3330,204 @@ static int test_tp(struct device *dev, s32 msec)
*/
#define SAMPLE_INTERVAL 500 /* ms */
#define SAMPLE_DELAY 2000 /* ms */
-static int test_for_100Mb(struct device *dev, int msec)
+static int
+test_for_100Mb(struct device *dev, int msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
-
- if (lp->timeout < 0) {
- if ((msec/SAMPLE_INTERVAL) <= 0)
- return 0;
- if (msec > SAMPLE_DELAY) {
- lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
- gep = SAMPLE_DELAY | TIMER_CB;
- return gep;
- } else {
- lp->timeout = msec/SAMPLE_INTERVAL;
- }
- }
- if (lp->phy[lp->active].id || lp->useSROM) {
- gep = is_100_up(dev) | is_spd_100(dev);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
+
+ if (lp->timeout < 0) {
+ if ((msec/SAMPLE_INTERVAL) <= 0) return 0;
+ if (msec > SAMPLE_DELAY) {
+ lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
+ gep = SAMPLE_DELAY | TIMER_CB;
+ return gep;
} else {
- gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
+ lp->timeout = msec/SAMPLE_INTERVAL;
}
- if (!(gep & ret) && --lp->timeout) {
- gep = SAMPLE_INTERVAL | TIMER_CB;
- } else {
- lp->timeout = -1;
- }
-
- return gep;
+ }
+
+ if (lp->phy[lp->active].id || lp->useSROM) {
+ gep = is_100_up(dev) | is_spd_100(dev);
+ } else {
+ gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
+ }
+ if (!(gep & ret) && --lp->timeout) {
+ gep = SAMPLE_INTERVAL | TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
+
+ return gep;
}
-static int wait_for_link(struct device *dev)
+static int
+wait_for_link(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- if (lp->timeout < 0) {
- lp->timeout = 1;
- }
+ if (lp->timeout < 0) {
+ lp->timeout = 1;
+ }
- if (lp->timeout--) {
- return TIMER_CB;
- } else {
- lp->timeout = -1;
- }
+ if (lp->timeout--) {
+ return TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
- return 0;
+ return 0;
}
/*
**
**
*/
-static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
+static int
+test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int test;
- u_long iobase = dev->base_addr;
-
- if (lp->timeout < 0) {
- lp->timeout = msec / 100;
- }
- if (pol)
- pol = ~0;
- reg = mii_rd((u_char) reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
- test = (reg ^ pol) & mask;
-
- if (test && --lp->timeout) {
- reg = 100 | TIMER_CB;
- } else {
- lp->timeout = -1;
- }
-
- return reg;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int test;
+ u_long iobase = dev->base_addr;
+
+ if (lp->timeout < 0) {
+ lp->timeout = msec/100;
+ }
+
+ if (pol) pol = ~0;
+ reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
+ test = (reg ^ pol) & mask;
+
+ if (test && --lp->timeout) {
+ reg = 100 | TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
+
+ return reg;
}
-static int is_spd_100(struct device *dev)
+static int
+is_spd_100(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int spd;
-
- if (lp->useMII) {
- spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
- spd = ~(spd ^ lp->phy[lp->active].spd.value);
- spd &= lp->phy[lp->active].spd.mask;
- } else if (!lp->useSROM) { /* de500-xa */
- spd = ((~gep_rd(dev)) & GEP_SLNK);
- } else {
- if ((lp->ibn == 2) || !lp->asBitValid)
- return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
-
- spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
- (lp->linkOK & ~lp->asBitValid);
- }
-
- return spd;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int spd;
+
+ if (lp->useMII) {
+ spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
+ spd = ~(spd ^ lp->phy[lp->active].spd.value);
+ spd &= lp->phy[lp->active].spd.mask;
+ } else if (!lp->useSROM) { /* de500-xa */
+ spd = ((~gep_rd(dev)) & GEP_SLNK);
+ } else {
+ if ((lp->ibn == 2) || !lp->asBitValid)
+ return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+ spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
+ (lp->linkOK & ~lp->asBitValid);
+ }
+
+ return spd;
}
-static int is_100_up(struct device *dev)
+static int
+is_100_up(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- if (lp->useMII) {
- /* Double read for sticky bits & temporary drops */
- mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
- } else if (!lp->useSROM) { /* de500-xa */
- return ((~gep_rd(dev)) & GEP_SLNK);
- } else {
- if ((lp->ibn == 2) || !lp->asBitValid)
- return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
-
- return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
- (lp->linkOK & ~lp->asBitValid));
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if (lp->useMII) {
+ /* Double read for sticky bits & temporary drops */
+ mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
+ return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+ } else if (!lp->useSROM) { /* de500-xa */
+ return ((~gep_rd(dev)) & GEP_SLNK);
+ } else {
+ if ((lp->ibn == 2) || !lp->asBitValid)
+ return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+ return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+ (lp->linkOK & ~lp->asBitValid));
+ }
}
-static int is_10_up(struct device *dev)
+static int
+is_10_up(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- if (lp->useMII) {
- /* Double read for sticky bits & temporary drops */
- mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
- } else if (!lp->useSROM) { /* de500-xa */
- return ((~gep_rd(dev)) & GEP_LNP);
- } else {
- if ((lp->ibn == 2) || !lp->asBitValid)
- return (((lp->chipset & ~0x00ff) == DC2114x) ?
- (~inl(DE4X5_SISR)&SISR_LS10):
- 0);
-
- return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
- (lp->linkOK & ~lp->asBitValid));
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if (lp->useMII) {
+ /* Double read for sticky bits & temporary drops */
+ mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
+ return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+ } else if (!lp->useSROM) { /* de500-xa */
+ return ((~gep_rd(dev)) & GEP_LNP);
+ } else {
+ if ((lp->ibn == 2) || !lp->asBitValid)
+ return (((lp->chipset & ~0x00ff) == DC2114x) ?
+ (~inl(DE4X5_SISR)&SISR_LS10):
+ 0);
+
+ return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+ (lp->linkOK & ~lp->asBitValid));
+ }
}
-static int is_anc_capable(struct device *dev)
+static int
+is_anc_capable(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
- return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
- } else if ((lp->chipset & ~0x00ff) == DC2114x) {
- return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
- } else {
- return 0;
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+ return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
+ } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+ return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
+ } else {
+ return 0;
+ }
}
/*
** Send a packet onto the media and watch for send errors that indicate the
** media is bad or unconnected.
*/
-static int ping_media(struct device *dev, int msec)
+static int
+ping_media(struct device *dev, int msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int sisr;
-
- if (lp->timeout < 0) {
- lp->timeout = msec / 100;
-
- lp->tmp = lp->tx_new; /* Remember the ring position */
- load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL);
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- outl(POLL_DEMAND, DE4X5_TPD);
- }
- sisr = inl(DE4X5_SISR);
-
- if ((!(sisr & SISR_NCR)) &&
- ((s32) le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
- (--lp->timeout)) {
- sisr = 100 | TIMER_CB;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int sisr;
+
+ if (lp->timeout < 0) {
+ lp->timeout = msec/100;
+
+ lp->tmp = lp->tx_new; /* Remember the ring position */
+ load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL);
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ outl(POLL_DEMAND, DE4X5_TPD);
+ }
+
+ sisr = inl(DE4X5_SISR);
+
+ if ((!(sisr & SISR_NCR)) &&
+ ((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) &&
+ (--lp->timeout)) {
+ sisr = 100 | TIMER_CB;
+ } else {
+ if ((!(sisr & SISR_NCR)) &&
+ !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
+ lp->timeout) {
+ sisr = 0;
} else {
- if ((!(sisr & SISR_NCR)) &&
- !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
- lp->timeout) {
- sisr = 0;
- } else {
- sisr = 1;
- }
- lp->timeout = -1;
+ sisr = 1;
}
-
- return sisr;
+ lp->timeout = -1;
+ }
+
+ return sisr;
}
/*
@@ -3463,93 +3535,94 @@ static int ping_media(struct device *dev, int msec)
** replace the one about to be passed up. On Alpha's it kmallocs a buffer
** into which the packet is copied.
*/
-static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len)
+static struct sk_buff *
+de4x5_alloc_rx_buff(struct device *dev, int index, int len)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct sk_buff *p;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct sk_buff *p;
#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
- struct sk_buff *ret;
- u_long i = 0, tmp;
+ struct sk_buff *ret;
+ u_long i=0, tmp;
- p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
- if (!p)
- return NULL;
+ p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
+ if (!p) return NULL;
- p->dev = dev;
- tmp = virt_to_bus(p->data);
- i = ((tmp + ALIGN) & ~ALIGN) - tmp;
- skb_reserve(p, i);
- lp->rx_ring[index].buf = tmp + i;
+ p->dev = dev;
+ tmp = virt_to_bus(p->data);
+ i = ((tmp + ALIGN) & ~ALIGN) - tmp;
+ skb_reserve(p, i);
+ lp->rx_ring[index].buf = tmp + i;
- ret = lp->rx_skb[index];
- lp->rx_skb[index] = p;
+ ret = lp->rx_skb[index];
+ lp->rx_skb[index] = p;
- if ((u_long) ret > 1) {
- skb_put(ret, len);
- }
- return ret;
+ if ((u_long) ret > 1) {
+ skb_put(ret, len);
+ }
+
+ return ret;
#else
- if (lp->state != OPEN)
- return (struct sk_buff *) 1; /* Fake out the open */
-
- p = dev_alloc_skb(len + 2);
- if (!p)
- return NULL;
-
- p->dev = dev;
- skb_reserve(p, 2); /* Align */
- if (index < lp->rx_old) { /* Wrapped buffer */
- short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
- memcpy(skb_put(p, tlen),
- bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)), tlen);
- memcpy(skb_put(p, len - tlen),
- bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len - tlen);
- } else { /* Linear buffer */
- memcpy(skb_put(p, len),
- bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)), len);
- }
-
- return p;
+ if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
+
+ p = dev_alloc_skb(len + 2);
+ if (!p) return NULL;
+
+ p->dev = dev;
+ skb_reserve(p, 2); /* Align */
+ if (index < lp->rx_old) { /* Wrapped buffer */
+ short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
+ memcpy(skb_put(p,tlen),
+ bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen);
+ memcpy(skb_put(p,len-tlen),
+ bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen);
+ } else { /* Linear buffer */
+ memcpy(skb_put(p,len),
+ bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len);
+ }
+
+ return p;
#endif
}
-static void de4x5_free_rx_buffs(struct device *dev)
+static void
+de4x5_free_rx_buffs(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i;
- for (i = 0; i < lp->rxRingSize; i++) {
- if ((u_long) lp->rx_skb[i] > 1) {
- dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
- }
- lp->rx_ring[i].status = 0;
- lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
+ for (i=0; i<lp->rxRingSize; i++) {
+ if ((u_long) lp->rx_skb[i] > 1) {
+ dev_kfree_skb(lp->rx_skb[i]);
}
+ lp->rx_ring[i].status = 0;
+ lp->rx_skb[i] = (struct sk_buff *)1; /* Dummy entry */
+ }
- return;
+ return;
}
-static void de4x5_free_tx_buffs(struct device *dev)
+static void
+de4x5_free_tx_buffs(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i;
- for (i = 0; i < lp->txRingSize; i++) {
- if (lp->tx_skb[i]) {
- dev_kfree_skb(lp->tx_skb[i], FREE_WRITE);
- lp->tx_skb[i] = NULL;
- }
- lp->tx_ring[i].status = 0;
+ for (i=0; i<lp->txRingSize; i++) {
+ if (lp->tx_skb[i]) {
+ dev_kfree_skb(lp->tx_skb[i]);
+ lp->tx_skb[i] = NULL;
}
+ lp->tx_ring[i].status = 0;
+ }
- /* Unload the locally queued packets */
- while (lp->cache.skb) {
- dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE);
- }
+ /* Unload the locally queued packets */
+ while (lp->cache.skb) {
+ dev_kfree_skb(de4x5_get_cache(dev));
+ }
- return;
+ return;
}
/*
@@ -3559,321 +3632,339 @@ static void de4x5_free_tx_buffs(struct device *dev)
** the hardware and software and make any media probes using a loopback
** packet meaningful.
*/
-static void de4x5_save_skbs(struct device *dev)
+static void
+de4x5_save_skbs(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 omr;
-
- if (!lp->cache.save_cnt) {
- STOP_DE4X5;
- de4x5_tx(dev); /* Flush any sent skb's */
- de4x5_free_tx_buffs(dev);
- de4x5_cache_state(dev, DE4X5_SAVE_STATE);
- de4x5_sw_reset(dev);
- de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
- lp->cache.save_cnt++;
- START_DE4X5;
- }
- return;
-}
-
-static void de4x5_restore_skbs(struct device *dev)
-{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int i;
- s32 omr;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 omr;
- if (lp->cache.save_cnt) {
- STOP_DE4X5;
- outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
- outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
-
- lp->rx_new = lp->rx_old = 0;
- lp->tx_new = lp->tx_old = 0;
+ if (!lp->cache.save_cnt) {
+ STOP_DE4X5;
+ de4x5_tx(dev); /* Flush any sent skb's */
+ de4x5_free_tx_buffs(dev);
+ de4x5_cache_state(dev, DE4X5_SAVE_STATE);
+ de4x5_sw_reset(dev);
+ de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
+ lp->cache.save_cnt++;
+ START_DE4X5;
+ }
- for (i = 0; i < lp->rxRingSize; i++) {
- lp->rx_ring[i].status = cpu_to_le32(R_OWN);
- }
+ return;
+}
- for (i = 0; i < lp->txRingSize; i++) {
- lp->tx_ring[i].status = cpu_to_le32(0);
- }
+static void
+de4x5_rst_desc_ring(struct device *dev)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int i;
+ s32 omr;
- barrier();
- lp->cache.save_cnt--;
- START_DE4X5;
+ if (lp->cache.save_cnt) {
+ STOP_DE4X5;
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ lp->rx_new = lp->rx_old = 0;
+ lp->tx_new = lp->tx_old = 0;
+
+ for (i = 0; i < lp->rxRingSize; i++) {
+ lp->rx_ring[i].status = cpu_to_le32(R_OWN);
}
- return;
+
+ for (i = 0; i < lp->txRingSize; i++) {
+ lp->tx_ring[i].status = cpu_to_le32(0);
+ }
+
+ barrier();
+ lp->cache.save_cnt--;
+ START_DE4X5;
+ }
+
+ return;
}
-static void de4x5_cache_state(struct device *dev, int flag)
+static void
+de4x5_cache_state(struct device *dev, int flag)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- switch (flag) {
- case DE4X5_SAVE_STATE:
- lp->cache.csr0 = inl(DE4X5_BMR);
- lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
- lp->cache.csr7 = inl(DE4X5_IMR);
- break;
-
- case DE4X5_RESTORE_STATE:
- outl(lp->cache.csr0, DE4X5_BMR);
- outl(lp->cache.csr6, DE4X5_OMR);
- outl(lp->cache.csr7, DE4X5_IMR);
- if (lp->chipset == DC21140) {
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ switch(flag) {
+ case DE4X5_SAVE_STATE:
+ lp->cache.csr0 = inl(DE4X5_BMR);
+ lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
+ lp->cache.csr7 = inl(DE4X5_IMR);
+ break;
+
+ case DE4X5_RESTORE_STATE:
+ outl(lp->cache.csr0, DE4X5_BMR);
+ outl(lp->cache.csr6, DE4X5_OMR);
+ outl(lp->cache.csr7, DE4X5_IMR);
+ if (lp->chipset == DC21140) {
gep_wr(lp->cache.gepc, dev);
gep_wr(lp->cache.gep, dev);
- } else {
- reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
- lp->cache.csr15);
- }
- break;
+ } else {
+ reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14,
+ lp->cache.csr15);
}
+ break;
+ }
- return;
+ return;
}
-static void de4x5_put_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_put_cache(struct device *dev, struct sk_buff *skb)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct sk_buff *p;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct sk_buff *p;
- if (lp->cache.skb) {
- for (p = lp->cache.skb; p->next; p = p->next);
- p->next = skb;
- } else {
- lp->cache.skb = skb;
- }
- skb->next = NULL;
+ if (lp->cache.skb) {
+ for (p=lp->cache.skb; p->next; p=p->next);
+ p->next = skb;
+ } else {
+ lp->cache.skb = skb;
+ }
+ skb->next = NULL;
- return;
+ return;
}
-static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct sk_buff *p = lp->cache.skb;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct sk_buff *p = lp->cache.skb;
- lp->cache.skb = skb;
- skb->next = p;
+ lp->cache.skb = skb;
+ skb->next = p;
- return;
+ return;
}
-static struct sk_buff *de4x5_get_cache(struct device *dev)
+static struct sk_buff *
+de4x5_get_cache(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct sk_buff *p = lp->cache.skb;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct sk_buff *p = lp->cache.skb;
- if (p) {
- lp->cache.skb = p->next;
- p->next = NULL;
- }
- return p;
+ if (p) {
+ lp->cache.skb = p->next;
+ p->next = NULL;
+ }
+
+ return p;
}
/*
** Check the Auto Negotiation State. Return OK when a link pass interrupt
** is received and the auto-negotiation status is NWAY OK.
*/
-static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
+static int
+test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 sts, ans;
-
- if (lp->timeout < 0) {
- lp->timeout = msec / 100;
- outl(irq_mask, DE4X5_IMR);
-
- /* clear all pending interrupts */
- sts = inl(DE4X5_STS);
- outl(sts, DE4X5_STS);
- }
- ans = inl(DE4X5_SISR) & SISR_ANS;
- sts = inl(DE4X5_STS) & ~TIMER_CB;
-
- if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
- sts = 100 | TIMER_CB;
- } else {
- lp->timeout = -1;
- }
-
- return sts;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 sts, ans;
+
+ if (lp->timeout < 0) {
+ lp->timeout = msec/100;
+ outl(irq_mask, DE4X5_IMR);
+
+ /* clear all pending interrupts */
+ sts = inl(DE4X5_STS);
+ outl(sts, DE4X5_STS);
+ }
+
+ ans = inl(DE4X5_SISR) & SISR_ANS;
+ sts = inl(DE4X5_STS) & ~TIMER_CB;
+
+ if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
+ sts = 100 | TIMER_CB;
+ } else {
+ lp->timeout = -1;
+ }
+
+ return sts;
}
-static void de4x5_setup_intr(struct device *dev)
+static void
+de4x5_setup_intr(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 imr, sts;
-
- if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */
- imr = 0;
- UNMASK_IRQs;
- sts = inl(DE4X5_STS); /* Reset any pending (stale) interrupts */
- outl(sts, DE4X5_STS);
- ENABLE_IRQs;
- }
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 imr, sts;
+
+ if (inl(DE4X5_OMR) & OMR_SR) { /* Only unmask if TX/RX is enabled */
+ imr = 0;
+ UNMASK_IRQs;
+ sts = inl(DE4X5_STS); /* Reset any pending (stale) interrupts */
+ outl(sts, DE4X5_STS);
+ ENABLE_IRQs;
+ }
+
+ return;
}
/*
**
*/
-void reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15)
+static void
+reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- RESET_SIA;
- if (lp->useSROM) {
- if (lp->ibn == 3) {
- srom_exec(dev, lp->phy[lp->active].rst);
- srom_exec(dev, lp->phy[lp->active].gep);
- outl(1, DE4X5_SICR);
- return;
- } else {
- csr15 = lp->cache.csr15;
- csr14 = lp->cache.csr14;
- csr13 = lp->cache.csr13;
- outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
- outl(csr15 | lp->cache.gep, DE4X5_SIGR);
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ RESET_SIA;
+ if (lp->useSROM) {
+ if (lp->ibn == 3) {
+ srom_exec(dev, lp->phy[lp->active].rst);
+ srom_exec(dev, lp->phy[lp->active].gep);
+ outl(1, DE4X5_SICR);
+ return;
} else {
- outl(csr15, DE4X5_SIGR);
+ csr15 = lp->cache.csr15;
+ csr14 = lp->cache.csr14;
+ csr13 = lp->cache.csr13;
+ outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
+ outl(csr15 | lp->cache.gep, DE4X5_SIGR);
}
- outl(csr14, DE4X5_STRR);
- outl(csr13, DE4X5_SICR);
+ } else {
+ outl(csr15, DE4X5_SIGR);
+ }
+ outl(csr14, DE4X5_STRR);
+ outl(csr13, DE4X5_SICR);
- de4x5_ms_delay(10);
+ de4x5_ms_delay(10);
- return;
+ return;
}
/*
** Create a loopback ethernet packet
*/
-static void create_packet(struct device *dev, char *frame, int len)
+static void
+create_packet(struct device *dev, char *frame, int len)
{
- int i;
- char *buf = frame;
-
- for (i = 0; i < ETH_ALEN; i++) { /* Use this source address */
- *buf++ = dev->dev_addr[i];
- }
- for (i = 0; i < ETH_ALEN; i++) { /* Use this destination address */
- *buf++ = dev->dev_addr[i];
- }
-
- *buf++ = 0; /* Packet length (2 bytes) */
- *buf++ = 1;
-
- return;
+ int i;
+ char *buf = frame;
+
+ for (i=0; i<ETH_ALEN; i++) { /* Use this source address */
+ *buf++ = dev->dev_addr[i];
+ }
+ for (i=0; i<ETH_ALEN; i++) { /* Use this destination address */
+ *buf++ = dev->dev_addr[i];
+ }
+
+ *buf++ = 0; /* Packet length (2 bytes) */
+ *buf++ = 1;
+
+ return;
}
/*
** Known delay in microseconds
*/
-static void de4x5_us_delay(u32 usec)
+static void
+de4x5_us_delay(u32 usec)
{
- udelay(usec);
-
- return;
+ udelay(usec);
+
+ return;
}
/*
** Known delay in milliseconds, in millisecond steps.
*/
-static void de4x5_ms_delay(u32 msec)
+static void
+de4x5_ms_delay(u32 msec)
{
- u_int i;
-
- for (i = 0; i < msec; i++) {
- de4x5_us_delay(1000);
- }
-
- return;
+ u_int i;
+
+ for (i=0; i<msec; i++) {
+ de4x5_us_delay(1000);
+ }
+
+ return;
}
/*
** Look for a particular board name in the EISA configuration space
*/
-static int EISA_signature(char *name, s32 eisa_id)
+static int
+EISA_signature(char *name, s32 eisa_id)
{
- c_char *signatures[] = DE4X5_SIGNATURE;
- char ManCode[DE4X5_STRLEN];
- union {
- s32 ID;
- char Id[4];
- } Eisa;
- int i, status = 0, siglen = sizeof(signatures) / sizeof(c_char *);
-
- *name = '\0';
- Eisa.ID = inl(eisa_id);
-
- ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
- ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
- ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
- ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
- ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
- ManCode[5] = '\0';
-
- for (i = 0; i < siglen; i++) {
- if (strstr(ManCode, signatures[i]) != NULL) {
- strcpy(name, ManCode);
- status = 1;
- break;
- }
+ c_char *signatures[] = DE4X5_SIGNATURE;
+ char ManCode[DE4X5_STRLEN];
+ union {
+ s32 ID;
+ char Id[4];
+ } Eisa;
+ int i, status = 0, siglen = sizeof(signatures)/sizeof(c_char *);
+
+ *name = '\0';
+ Eisa.ID = inl(eisa_id);
+
+ ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
+ ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
+ ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
+ ManCode[3]=((Eisa.Id[2]&0x0f)+0x30);
+ ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
+ ManCode[5]='\0';
+
+ for (i=0;i<siglen;i++) {
+ if (strstr(ManCode, signatures[i]) != NULL) {
+ strcpy(name,ManCode);
+ status = 1;
+ break;
}
-
- return status; /* return the device name string */
+ }
+
+ return status; /* return the device name string */
}
/*
** Look for a particular board name in the PCI configuration space
*/
-static int PCI_signature(char *name, struct bus_type *lp)
+static int
+PCI_signature(char *name, struct bus_type *lp)
{
- c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
- int i, status = 0, siglen = sizeof(de4x5_signatures) / sizeof(c_char *);
-
- if (lp->chipset == DC21040) {
- strcpy(name, "DE434/5");
- return status;
- } else { /* Search for a DEC name in the SROM */
- int i = *((char *) &lp->srom + 19) * 3;
- strncpy(name, (char *) &lp->srom + 26 + i, 8);
- }
- name[8] = '\0';
- for (i = 0; i < siglen; i++) {
- if (strstr(name, de4x5_signatures[i]) != NULL)
- break;
- }
- if (i == siglen) {
- if (dec_only) {
- *name = '\0';
- } else { /* Use chip name to avoid confusion */
- strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
- ((lp->chipset == DC21041) ? "DC21041" :
- ((lp->chipset == DC21140) ? "DC21140" :
- ((lp->chipset == DC21142) ? "DC21142" :
- ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
- )))))));
- }
- if (lp->chipset != DC21041) {
- useSROM = TRUE; /* card is not recognisably DEC */
- }
- } else if ((lp->chipset & ~0x00ff) == DC2114x) {
- useSROM = TRUE;
- }
-
+ c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
+ int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+
+ if (lp->chipset == DC21040) {
+ strcpy(name, "DE434/5");
return status;
+ } else { /* Search for a DEC name in the SROM */
+ int i = *((char *)&lp->srom + 19) * 3;
+ strncpy(name, (char *)&lp->srom + 26 + i, 8);
+ }
+ name[8] = '\0';
+ for (i=0; i<siglen; i++) {
+ if (strstr(name,de4x5_signatures[i])!=NULL) break;
+ }
+ if (i == siglen) {
+ if (dec_only) {
+ *name = '\0';
+ } else { /* Use chip name to avoid confusion */
+ strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
+ ((lp->chipset == DC21041) ? "DC21041" :
+ ((lp->chipset == DC21140) ? "DC21140" :
+ ((lp->chipset == DC21142) ? "DC21142" :
+ ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
+ )))))));
+ }
+ if (lp->chipset != DC21041) {
+ useSROM = TRUE; /* card is not recognisably DEC */
+ }
+ } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+ useSROM = TRUE;
+ }
+
+ return status;
}
/*
@@ -3884,33 +3975,34 @@ static int PCI_signature(char *name, struct bus_type *lp)
** immediately with the prior srom contents intact (the h/w address will
** be fixed up later).
*/
-static void DevicePresent(u_long aprom_addr)
+static void
+DevicePresent(u_long aprom_addr)
{
- int i, j=0;
- struct bus_type *lp = &bus;
-
- if (lp->chipset == DC21040) {
- outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
- } else { /* Read new srom */
- u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
- for (i=0; i<(ETH_ALEN>>1); i++) {
- tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
- *p = le16_to_cpu(tmp);
- j += *p++;
- }
- if ((j == 0) || (j == 0x2fffd)) {
- return;
- }
-
- p=(short *)&lp->srom;
- for (i = 0; i < (sizeof(struct de4x5_srom) >> 1); i++) {
- tmp = srom_rd(aprom_addr, i);
- *p++ = le16_to_cpu(tmp);
- }
- de4x5_dbg_srom((struct de4x5_srom *) &lp->srom);
- }
-
- return;
+ int i, j=0;
+ struct bus_type *lp = &bus;
+
+ if (lp->chipset == DC21040) {
+ outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */
+ } else { /* Read new srom */
+ u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
+ for (i=0; i<(ETH_ALEN>>1); i++) {
+ tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
+ *p = le16_to_cpu(tmp);
+ j += *p++;
+ }
+ if ((j == 0) || (j == 0x2fffd)) {
+ return;
+ }
+
+ p=(short *)&lp->srom;
+ for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
+ tmp = srom_rd(aprom_addr, i);
+ *p++ = le16_to_cpu(tmp);
+ }
+ de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+ }
+
+ return;
}
/*
@@ -3919,302 +4011,303 @@ static void DevicePresent(u_long aprom_addr)
** as one or more of the bytes. Only the last 3 bytes should be checked
** as the first three are invariant - assigned to an organisation.
*/
-static int get_hw_addr(struct device *dev)
+static int
+get_hw_addr(struct device *dev)
{
- u_long iobase = dev->base_addr;
- int broken, i, k, tmp, status = 0;
- u_short j, chksum;
- struct bus_type *lp = &bus;
-
- broken = de4x5_bad_srom(lp);
-
- for (i = 0, k = 0, j = 0; j < 3; j++) {
- k <<= 1;
- if (k > 0xffff)
- k -= 0xffff;
-
- if (lp->bus == PCI) {
- if (lp->chipset == DC21040) {
- while ((tmp = inl(DE4X5_APROM)) < 0);
- k += (u_char) tmp;
- dev->dev_addr[i++] = (u_char) tmp;
- while ((tmp = inl(DE4X5_APROM)) < 0);
- k += (u_short) (tmp << 8);
- dev->dev_addr[i++] = (u_char) tmp;
- } else if (!broken) {
- dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i];
- i++;
- dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i];
- i++;
- } else if ((broken == SMC) || (broken == ACCTON)) {
- dev->dev_addr[i] = *((u_char *) & lp->srom + i);
- i++;
- dev->dev_addr[i] = *((u_char *) & lp->srom + i);
- i++;
- }
- } else {
- k += (u_char) (tmp = inb(EISA_APROM));
- dev->dev_addr[i++] = (u_char) tmp;
- k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
- dev->dev_addr[i++] = (u_char) tmp;
- }
+ u_long iobase = dev->base_addr;
+ int broken, i, k, tmp, status = 0;
+ u_short j,chksum;
+ struct bus_type *lp = &bus;
- if (k > 0xffff)
- k -= 0xffff;
- }
- if (k == 0xffff)
- k = 0;
+ broken = de4x5_bad_srom(lp);
+ for (i=0,k=0,j=0;j<3;j++) {
+ k <<= 1;
+ if (k > 0xffff) k-=0xffff;
+
if (lp->bus == PCI) {
- if (lp->chipset == DC21040) {
- while ((tmp = inl(DE4X5_APROM)) < 0);
- chksum = (u_char) tmp;
- while ((tmp = inl(DE4X5_APROM)) < 0);
- chksum |= (u_short) (tmp << 8);
- if ((k != chksum) && (dec_only))
- status = -1;
- }
+ if (lp->chipset == DC21040) {
+ while ((tmp = inl(DE4X5_APROM)) < 0);
+ k += (u_char) tmp;
+ dev->dev_addr[i++] = (u_char) tmp;
+ while ((tmp = inl(DE4X5_APROM)) < 0);
+ k += (u_short) (tmp << 8);
+ dev->dev_addr[i++] = (u_char) tmp;
+ } else if (!broken) {
+ dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+ dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+ } else if ((broken == SMC) || (broken == ACCTON)) {
+ dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
+ dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
+ }
} else {
- chksum = (u_char) inb(EISA_APROM);
- chksum |= (u_short) (inb(EISA_APROM) << 8);
- if ((k != chksum) && (dec_only))
- status = -1;
+ k += (u_char) (tmp = inb(EISA_APROM));
+ dev->dev_addr[i++] = (u_char) tmp;
+ k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
+ dev->dev_addr[i++] = (u_char) tmp;
+ }
+
+ if (k > 0xffff) k-=0xffff;
+ }
+ if (k == 0xffff) k=0;
+
+ if (lp->bus == PCI) {
+ if (lp->chipset == DC21040) {
+ while ((tmp = inl(DE4X5_APROM)) < 0);
+ chksum = (u_char) tmp;
+ while ((tmp = inl(DE4X5_APROM)) < 0);
+ chksum |= (u_short) (tmp << 8);
+ if ((k != chksum) && (dec_only)) status = -1;
}
+ } else {
+ chksum = (u_char) inb(EISA_APROM);
+ chksum |= (u_short) (inb(EISA_APROM) << 8);
+ if ((k != chksum) && (dec_only)) status = -1;
+ }
- /* If possible, try to fix a broken card - SMC only so far */
- srom_repair(dev, broken);
+ /* If possible, try to fix a broken card - SMC only so far */
+ srom_repair(dev, broken);
- /* Test for a bad enet address */
- status = test_bad_enet(dev, status);
+ /* Test for a bad enet address */
+ status = test_bad_enet(dev, status);
- return status;
+ return status;
}
/*
** Test for enet addresses in the first 32 bytes. The built-in strncmp
** didn't seem to work here...?
*/
-static int de4x5_bad_srom(struct bus_type *lp)
+static int
+de4x5_bad_srom(struct bus_type *lp)
{
- int i, status = 0;
-
- for (i = 0; i < sizeof(enet_det) / ETH_ALEN; i++) {
- if (!de4x5_strncmp((char *) &lp->srom, (char *) &enet_det[i], 3) &&
- !de4x5_strncmp((char *) &lp->srom + 0x10, (char *) &enet_det[i], 3)) {
- if (i == 0) {
- status = SMC;
- } else if (i == 1) {
- status = ACCTON;
- }
- break;
- }
+ int i, status = 0;
+
+ for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) {
+ if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) &&
+ !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) {
+ if (i == 0) {
+ status = SMC;
+ } else if (i == 1) {
+ status = ACCTON;
+ }
+ break;
}
+ }
- return status;
+ return status;
}
-static int de4x5_strncmp(char *a, char *b, int n)
+static int
+de4x5_strncmp(char *a, char *b, int n)
{
- int ret = 0;
+ int ret=0;
- for (; n && !ret; n--) {
- ret = *a++ - *b++;
- }
+ for (;n && !ret;n--) {
+ ret = *a++ - *b++;
+ }
- return ret;
+ return ret;
}
-static void srom_repair(struct device *dev, int card)
+static void
+srom_repair(struct device *dev, int card)
{
- struct bus_type *lp = &bus;
-
- switch (card) {
- case SMC:
- memset((char *) &bus.srom, 0, sizeof(struct de4x5_srom));
- memcpy(lp->srom.ieee_addr, (char *) dev->dev_addr, ETH_ALEN);
- memcpy(lp->srom.info, (char *) &srom_repair_info[SMC - 1], 100);
- useSROM = TRUE;
- break;
- }
-
- return;
+ struct bus_type *lp = &bus;
+
+ switch(card) {
+ case SMC:
+ memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom));
+ memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
+ memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
+ useSROM = TRUE;
+ break;
+ }
+
+ return;
}
/*
** Assume that the irq's do not follow the PCI spec - this is seems
** to be true so far (2 for 2).
*/
-static int test_bad_enet(struct device *dev, int status)
+static int
+test_bad_enet(struct device *dev, int status)
{
- struct bus_type *lp = &bus;
- int i, tmp;
-
- for (tmp = 0, i = 0; i < ETH_ALEN; i++)
- tmp += (u_char) dev->dev_addr[i];
- if ((tmp == 0) || (tmp == 0x5fa)) {
- if ((lp->chipset == last.chipset) &&
- (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
- for (i = 0; i < ETH_ALEN; i++)
- dev->dev_addr[i] = last.addr[i];
- for (i = ETH_ALEN - 1; i > 2; --i) {
- dev->dev_addr[i] += 1;
- if (dev->dev_addr[i] != 0)
- break;
- }
- for (i = 0; i < ETH_ALEN; i++)
- last.addr[i] = dev->dev_addr[i];
- dev->irq = last.irq;
-
- status = 0;
- }
- } else if (!status) {
- last.chipset = lp->chipset;
- last.bus = lp->bus_num;
- last.irq = dev->irq;
- for (i = 0; i < ETH_ALEN; i++)
- last.addr[i] = dev->dev_addr[i];
- }
- return status;
+ struct bus_type *lp = &bus;
+ int i, tmp;
+
+ for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
+ if ((tmp == 0) || (tmp == 0x5fa)) {
+ if ((lp->chipset == last.chipset) &&
+ (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
+ for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
+ for (i=ETH_ALEN-1; i>2; --i) {
+ dev->dev_addr[i] += 1;
+ if (dev->dev_addr[i] != 0) break;
+ }
+ for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+ dev->irq = last.irq;
+
+ status = 0;
+ }
+ } else if (!status) {
+ last.chipset = lp->chipset;
+ last.bus = lp->bus_num;
+ last.irq = dev->irq;
+ for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+ }
+
+ return status;
}
/*
** SROM Read
*/
-static short srom_rd(u_long addr, u_char offset)
+static short
+srom_rd(u_long addr, u_char offset)
{
- sendto_srom(SROM_RD | SROM_SR, addr);
-
- srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
- srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
- srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
-
- return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
+ sendto_srom(SROM_RD | SROM_SR, addr);
+
+ srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
+ srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
+ srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
+
+ return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
}
-static void srom_latch(u_int command, u_long addr)
+static void
+srom_latch(u_int command, u_long addr)
{
- sendto_srom(command, addr);
- sendto_srom(command | DT_CLK, addr);
- sendto_srom(command, addr);
-
- return;
+ sendto_srom(command, addr);
+ sendto_srom(command | DT_CLK, addr);
+ sendto_srom(command, addr);
+
+ return;
}
-static void srom_command(u_int command, u_long addr)
+static void
+srom_command(u_int command, u_long addr)
{
- srom_latch(command, addr);
- srom_latch(command, addr);
- srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
- return;
+ srom_latch(command, addr);
+ srom_latch(command, addr);
+ srom_latch((command & 0x0000ff00) | DT_CS, addr);
+
+ return;
}
-static void srom_address(u_int command, u_long addr, u_char offset)
+static void
+srom_address(u_int command, u_long addr, u_char offset)
{
- int i;
- char a;
-
- a = (char) (offset << 2);
- for (i = 0; i < 6; i++, a <<= 1) {
- srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
- }
- de4x5_us_delay(1);
-
- i = (getfrom_srom(addr) >> 3) & 0x01;
- return;
+ int i;
+ char a;
+
+ a = (char)(offset << 2);
+ for (i=0; i<6; i++, a <<= 1) {
+ srom_latch(command | ((a < 0) ? DT_IN : 0), addr);
+ }
+ de4x5_us_delay(1);
+
+ i = (getfrom_srom(addr) >> 3) & 0x01;
+
+ return;
}
-static short srom_data(u_int command, u_long addr)
+static short
+srom_data(u_int command, u_long addr)
{
- int i;
- short word = 0;
- s32 tmp;
-
- for (i = 0; i < 16; i++) {
- sendto_srom(command | DT_CLK, addr);
- tmp = getfrom_srom(addr);
- sendto_srom(command, addr);
-
- word = (word << 1) | ((tmp >> 3) & 0x01);
- }
-
- sendto_srom(command & 0x0000ff00, addr);
-
- return word;
+ int i;
+ short word = 0;
+ s32 tmp;
+
+ for (i=0; i<16; i++) {
+ sendto_srom(command | DT_CLK, addr);
+ tmp = getfrom_srom(addr);
+ sendto_srom(command, addr);
+
+ word = (word << 1) | ((tmp >> 3) & 0x01);
+ }
+
+ sendto_srom(command & 0x0000ff00, addr);
+
+ return word;
}
/*
- static void
- srom_busy(u_int command, u_long addr)
- {
+static void
+srom_busy(u_int command, u_long addr)
+{
sendto_srom((command & 0x0000ff00) | DT_CS, addr);
-
+
while (!((getfrom_srom(addr) >> 3) & 0x01)) {
- de4x5_ms_delay(1);
+ de4x5_ms_delay(1);
}
-
+
sendto_srom(command & 0x0000ff00, addr);
-
+
return;
- }
- */
+}
+*/
-static void sendto_srom(u_int command, u_long addr)
+static void
+sendto_srom(u_int command, u_long addr)
{
- outl(command, addr);
- udelay(1);
-
- return;
+ outl(command, addr);
+ udelay(1);
+
+ return;
}
-static int getfrom_srom(u_long addr)
+static int
+getfrom_srom(u_long addr)
{
- s32 tmp;
-
- tmp = inl(addr);
- udelay(1);
-
- return tmp;
+ s32 tmp;
+
+ tmp = inl(addr);
+ udelay(1);
+
+ return tmp;
}
-static int srom_infoleaf_info(struct device *dev)
+static int
+srom_infoleaf_info(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i, count;
- u_char *p;
-
- /* Find the infoleaf decoder function that matches this chipset */
- for (i = 0; i < INFOLEAF_SIZE; i++) {
- if (lp->chipset == infoleaf_array[i].chipset)
- break;
- }
- if (i == INFOLEAF_SIZE) {
- lp->useSROM = FALSE;
- printk("%s: Cannot find correct chipset for SROM decoding!\n",
- dev->name);
- return -ENXIO;
- }
- lp->infoleaf_fn = infoleaf_array[i].fn;
-
- /* Find the information offset that this function should use */
- count = *((u_char *) & lp->srom + 19);
- p = (u_char *) & lp->srom + 26;
-
- if (count > 1) {
- for (i = count; i; --i, p += 3) {
- if (lp->device == *p)
- break;
- }
- if (i == 0) {
- lp->useSROM = FALSE;
- printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
- dev->name, lp->device);
- return -ENXIO;
- }
- }
- lp->infoleaf_offset = TWIDDLE(p + 1);
-
- return 0;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i, count;
+ u_char *p;
+
+ /* Find the infoleaf decoder function that matches this chipset */
+ for (i=0; i<INFOLEAF_SIZE; i++) {
+ if (lp->chipset == infoleaf_array[i].chipset) break;
+ }
+ if (i == INFOLEAF_SIZE) {
+ lp->useSROM = FALSE;
+ printk("%s: Cannot find correct chipset for SROM decoding!\n",
+ dev->name);
+ return -ENXIO;
+ }
+
+ lp->infoleaf_fn = infoleaf_array[i].fn;
+
+ /* Find the information offset that this function should use */
+ count = *((u_char *)&lp->srom + 19);
+ p = (u_char *)&lp->srom + 26;
+
+ if (count > 1) {
+ for (i=count; i; --i, p+=3) {
+ if (lp->device == *p) break;
+ }
+ if (i == 0) {
+ lp->useSROM = FALSE;
+ printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
+ dev->name, lp->device);
+ return -ENXIO;
+ }
+ }
+
+ lp->infoleaf_offset = TWIDDLE(p+1);
+
+ return 0;
}
/*
@@ -4224,74 +4317,75 @@ static int srom_infoleaf_info(struct device *dev)
** The info for the MII devices will be valid since the index used
** will follow the discovery process from MII address 1-31 then 0.
*/
-static void srom_init(struct device *dev)
+static void
+srom_init(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char *p = (u_char *) & lp->srom + lp->infoleaf_offset;
- u_char count;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+ u_char count;
- p += 2;
- if (lp->chipset == DC21140) {
- lp->cache.gepc = (*p++ | GEP_CTRL);
- gep_wr(lp->cache.gepc, dev);
- }
- /* Block count */
- count = *p++;
-
- /* Jump the infoblocks to find types */
- for (; count; --count) {
- if (*p < 128) {
- p += COMPACT_LEN;
- } else if (*(p + 1) == 5) {
- type5_infoblock(dev, 1, p);
- p += ((*p & BLOCK_LEN) + 1);
- } else if (*(p+1) == 4) {
- p += ((*p & BLOCK_LEN) + 1);
- } else if (*(p + 1) == 3) {
- type3_infoblock(dev, 1, p);
- p += ((*p & BLOCK_LEN) + 1);
- } else if (*(p+1) == 2) {
- p += ((*p & BLOCK_LEN) + 1);
- } else if (*(p + 1) == 1) {
- type1_infoblock(dev, 1, p);
- p += ((*p & BLOCK_LEN) + 1);
- } else {
- p += ((*p & BLOCK_LEN) + 1);
- }
+ p+=2;
+ if (lp->chipset == DC21140) {
+ lp->cache.gepc = (*p++ | GEP_CTRL);
+ gep_wr(lp->cache.gepc, dev);
+ }
+
+ /* Block count */
+ count = *p++;
+
+ /* Jump the infoblocks to find types */
+ for (;count; --count) {
+ if (*p < 128) {
+ p += COMPACT_LEN;
+ } else if (*(p+1) == 5) {
+ type5_infoblock(dev, 1, p);
+ p += ((*p & BLOCK_LEN) + 1);
+ } else if (*(p+1) == 4) {
+ p += ((*p & BLOCK_LEN) + 1);
+ } else if (*(p+1) == 3) {
+ type3_infoblock(dev, 1, p);
+ p += ((*p & BLOCK_LEN) + 1);
+ } else if (*(p+1) == 2) {
+ p += ((*p & BLOCK_LEN) + 1);
+ } else if (*(p+1) == 1) {
+ type1_infoblock(dev, 1, p);
+ p += ((*p & BLOCK_LEN) + 1);
+ } else {
+ p += ((*p & BLOCK_LEN) + 1);
}
+ }
- return;
+ return;
}
/*
** A generic routine that writes GEP control, data and reset information
** to the GEP register (21140) or csr15 GEP portion (2114[23]).
*/
-static void srom_exec(struct device *dev, u_char * p)
+static void
+srom_exec(struct device *dev, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- u_char count = (p ? *p++ : 0);
- u_short *w = (u_short *)p;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ u_char count = (p ? *p++ : 0);
+ u_short *w = (u_short *)p;
- if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count)
- return;
+ if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
- if (lp->chipset != DC21140)
- RESET_SIA;
+ if (lp->chipset != DC21140) RESET_SIA;
- while (count--) {
- gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
- *p++ : TWIDDLE(w++)), dev);
- udelay(2000); /* 2ms per action */
- }
-
- if (lp->chipset != DC21140) {
- outl(lp->cache.csr14, DE4X5_STRR);
- outl(lp->cache.csr13, DE4X5_SICR);
- }
-
- return;
+ while (count--) {
+ gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
+ *p++ : TWIDDLE(w++)), dev);
+ udelay(2000); /* 2ms per action */
+ }
+
+ if (lp->chipset != DC21140) {
+ outl(lp->cache.csr14, DE4X5_STRR);
+ outl(lp->cache.csr13, DE4X5_SICR);
+ }
+
+ return;
}
/*
@@ -4299,944 +4393,1024 @@ static void srom_exec(struct device *dev, u_char * p)
** unless I implement the DC21041 SROM functions. There's no need
** since the existing code will be satisfactory for all boards.
*/
-static int dc21041_infoleaf(struct device *dev)
+static int
+dc21041_infoleaf(struct device *dev)
{
- return DE4X5_AUTOSENSE_MS;
+ return DE4X5_AUTOSENSE_MS;
}
-static int dc21140_infoleaf(struct device *dev)
+static int
+dc21140_infoleaf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char count = 0;
- u_char *p = (u_char *) & lp->srom + lp->infoleaf_offset;
- int next_tick = DE4X5_AUTOSENSE_MS;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char count = 0;
+ u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+ int next_tick = DE4X5_AUTOSENSE_MS;
- /* Read the connection type */
- p += 2;
+ /* Read the connection type */
+ p+=2;
- /* GEP control */
- lp->cache.gepc = (*p++ | GEP_CTRL);
+ /* GEP control */
+ lp->cache.gepc = (*p++ | GEP_CTRL);
- /* Block count */
- count = *p++;
+ /* Block count */
+ count = *p++;
- /* Recursively figure out the info blocks */
- if (*p < 128) {
- next_tick = dc_infoblock[COMPACT] (dev, count, p);
- } else {
- next_tick = dc_infoblock[*(p + 1)] (dev, count, p);
- }
+ /* Recursively figure out the info blocks */
+ if (*p < 128) {
+ next_tick = dc_infoblock[COMPACT](dev, count, p);
+ } else {
+ next_tick = dc_infoblock[*(p+1)](dev, count, p);
+ }
- if (lp->tcount == count) {
- lp->media = NC;
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
- }
- lp->media = INIT;
- lp->tcount = 0;
- lp->tx_enable = FALSE;
+ if (lp->tcount == count) {
+ lp->media = NC;
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
}
- return next_tick & ~TIMER_CB;
+ lp->media = INIT;
+ lp->tcount = 0;
+ lp->tx_enable = FALSE;
+ }
+
+ return next_tick & ~TIMER_CB;
}
-static int dc21142_infoleaf(struct device *dev)
+static int
+dc21142_infoleaf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_char count = 0;
- u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- /* Read the connection type */
- p+=2;
-
- /* Block count */
- count = *p++;
-
- /* Recursively figure out the info blocks */
- if (*p < 128) {
- next_tick = dc_infoblock[COMPACT](dev, count, p);
- } else {
- next_tick = dc_infoblock[*(p+1)](dev, count, p);
- }
-
- if (lp->tcount == count) {
- lp->media = NC;
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
- }
- lp->media = INIT;
- lp->tcount = 0;
- lp->tx_enable = FALSE;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char count = 0;
+ u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ /* Read the connection type */
+ p+=2;
+
+ /* Block count */
+ count = *p++;
+
+ /* Recursively figure out the info blocks */
+ if (*p < 128) {
+ next_tick = dc_infoblock[COMPACT](dev, count, p);
+ } else {
+ next_tick = dc_infoblock[*(p+1)](dev, count, p);
+ }
+
+ if (lp->tcount == count) {
+ lp->media = NC;
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
}
+ lp->media = INIT;
+ lp->tcount = 0;
+ lp->tx_enable = FALSE;
+ }
- return next_tick & ~TIMER_CB;
+ return next_tick & ~TIMER_CB;
}
-static int dc21143_infoleaf(struct device *dev)
+static int
+dc21143_infoleaf(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_char count = 0;
- u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
- int next_tick = DE4X5_AUTOSENSE_MS;
-
- /* Read the connection type */
- p+=2;
-
- /* Block count */
- count = *p++;
-
- /* Recursively figure out the info blocks */
- if (*p < 128) {
- next_tick = dc_infoblock[COMPACT](dev, count, p);
- } else {
- next_tick = dc_infoblock[*(p+1)](dev, count, p);
- }
- if (lp->tcount == count) {
- lp->media = NC;
- if (lp->media != lp->c_media) {
- de4x5_dbg_media(dev);
- lp->c_media = lp->media;
- }
- lp->media = INIT;
- lp->tcount = 0;
- lp->tx_enable = FALSE;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char count = 0;
+ u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+ int next_tick = DE4X5_AUTOSENSE_MS;
+
+ /* Read the connection type */
+ p+=2;
+
+ /* Block count */
+ count = *p++;
+
+ /* Recursively figure out the info blocks */
+ if (*p < 128) {
+ next_tick = dc_infoblock[COMPACT](dev, count, p);
+ } else {
+ next_tick = dc_infoblock[*(p+1)](dev, count, p);
+ }
+ if (lp->tcount == count) {
+ lp->media = NC;
+ if (lp->media != lp->c_media) {
+ de4x5_dbg_media(dev);
+ lp->c_media = lp->media;
}
+ lp->media = INIT;
+ lp->tcount = 0;
+ lp->tx_enable = FALSE;
+ }
- return next_tick & ~TIMER_CB;
+ return next_tick & ~TIMER_CB;
}
/*
** The compact infoblock is only designed for DC21140[A] chips, so
** we'll reuse the dc21140m_autoconf function. Non MII media only.
*/
-static int compact_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+compact_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char flags, csr6;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char flags, csr6;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p + COMPACT_LEN) < 128) {
- return dc_infoblock[COMPACT] (dev, count, p + COMPACT_LEN);
- } else {
- return dc_infoblock[*(p + COMPACT_LEN + 1)] (dev, count, p + COMPACT_LEN);
- }
- }
- if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = COMPACT;
- lp->active = 0;
- gep_wr(lp->cache.gepc, dev);
- lp->infoblock_media = (*p++) & COMPACT_MC;
- lp->cache.gep = *p++;
- csr6 = *p++;
- flags = *p++;
-
- lp->asBitValid = (flags & 0x80) ? 0 : -1;
- lp->defMedium = (flags & 0x40) ? -1 : 0;
- lp->asBit = 1 << ((csr6 >> 1) & 0x07);
- lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
- lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
-
- de4x5_switch_mac_port(dev);
- }
- return dc21140m_autoconf(dev);
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+COMPACT_LEN) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN);
+ } else {
+ return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN);
+ }
+ }
+
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = COMPACT;
+ lp->active = 0;
+ gep_wr(lp->cache.gepc, dev);
+ lp->infoblock_media = (*p++) & COMPACT_MC;
+ lp->cache.gep = *p++;
+ csr6 = *p++;
+ flags = *p++;
+
+ lp->asBitValid = (flags & 0x80) ? 0 : -1;
+ lp->defMedium = (flags & 0x40) ? -1 : 0;
+ lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+ lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+ lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+ lp->useMII = FALSE;
+
+ de4x5_switch_mac_port(dev);
+ }
+
+ return dc21140m_autoconf(dev);
}
/*
** This block describes non MII media for the DC21140[A] only.
*/
-static int type0_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+type0_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char flags, csr6, len = (*p & BLOCK_LEN) + 1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p + len) < 128) {
- return dc_infoblock[COMPACT] (dev, count, p + len);
- } else {
- return dc_infoblock[*(p + len + 1)] (dev, count, p + len);
- }
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
}
- if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = 0;
- lp->active = 0;
- gep_wr(lp->cache.gepc, dev);
- p += 2;
- lp->infoblock_media = (*p++) & BLOCK0_MC;
- lp->cache.gep = *p++;
- csr6 = *p++;
- flags = *p++;
-
- lp->asBitValid = (flags & 0x80) ? 0 : -1;
- lp->defMedium = (flags & 0x40) ? -1 : 0;
- lp->asBit = 1 << ((csr6 >> 1) & 0x07);
- lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
- lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
-
- de4x5_switch_mac_port(dev);
- }
- return dc21140m_autoconf(dev);
+ }
+
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 0;
+ lp->active = 0;
+ gep_wr(lp->cache.gepc, dev);
+ p+=2;
+ lp->infoblock_media = (*p++) & BLOCK0_MC;
+ lp->cache.gep = *p++;
+ csr6 = *p++;
+ flags = *p++;
+
+ lp->asBitValid = (flags & 0x80) ? 0 : -1;
+ lp->defMedium = (flags & 0x40) ? -1 : 0;
+ lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+ lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+ lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+ lp->useMII = FALSE;
+
+ de4x5_switch_mac_port(dev);
+ }
+
+ return dc21140m_autoconf(dev);
}
/* These functions are under construction! */
-static int type1_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+type1_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char len = (*p & BLOCK_LEN) + 1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char len = (*p & BLOCK_LEN)+1;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p + len) < 128) {
- return dc_infoblock[COMPACT] (dev, count, p + len);
- } else {
- return dc_infoblock[*(p + len + 1)] (dev, count, p + len);
- }
- }
- p += 2;
- if (lp->state == INITIALISED) {
- lp->active = *p++;
- lp->phy[lp->active].gep = (*p ? p : 0);
- p += (*p + 1);
- lp->phy[lp->active].rst = (*p ? p : 0);
- p += (*p + 1);
- lp->phy[lp->active].mc = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p);
- return 0;
- } else if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = 1;
- lp->active = *p;
- lp->infoblock_csr6 = OMR_MII_100;
- lp->useMII = TRUE;
- lp->infoblock_media = ANS;
- lp->media = ANS;
- de4x5_switch_mac_port(dev);
- }
- return dc21140m_autoconf(dev);
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
+ }
+ }
+
+ p += 2;
+ if (lp->state == INITIALISED) {
+ lp->active = *p++;
+ lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+ lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p);
+ return 0;
+ } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 1;
+ lp->active = *p;
+ lp->infoblock_csr6 = OMR_MII_100;
+ lp->useMII = TRUE;
+ lp->infoblock_media = ANS;
+
+ de4x5_switch_mac_port(dev);
+ }
+
+ return dc21140m_autoconf(dev);
}
-static int type2_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+type2_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_char len = (*p & BLOCK_LEN)+1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char len = (*p & BLOCK_LEN)+1;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p+len) < 128) {
- return dc_infoblock[COMPACT](dev, count, p+len);
- } else {
- return dc_infoblock[*(p+len+1)](dev, count, p+len);
- }
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
}
+ }
- if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = 2;
- lp->active = 0;
- p += 2;
- lp->infoblock_media = (*p) & MEDIA_CODE;
-
- if ((*p++) & EXT_FIELD) {
- lp->cache.csr13 = TWIDDLE(p); p += 2;
- lp->cache.csr14 = TWIDDLE(p); p += 2;
- lp->cache.csr15 = TWIDDLE(p); p += 2;
- } else {
- lp->cache.csr13 = CSR13;
- lp->cache.csr14 = CSR14;
- lp->cache.csr15 = CSR15;
- }
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16);
- lp->infoblock_csr6 = OMR_SIA;
- lp->useMII = FALSE;
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 2;
+ lp->active = 0;
+ p += 2;
+ lp->infoblock_media = (*p) & MEDIA_CODE;
- de4x5_switch_mac_port(dev);
+ if ((*p++) & EXT_FIELD) {
+ lp->cache.csr13 = TWIDDLE(p); p += 2;
+ lp->cache.csr14 = TWIDDLE(p); p += 2;
+ lp->cache.csr15 = TWIDDLE(p); p += 2;
+ } else {
+ lp->cache.csr13 = CSR13;
+ lp->cache.csr14 = CSR14;
+ lp->cache.csr15 = CSR15;
}
+ lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(TWIDDLE(p)) << 16);
+ lp->infoblock_csr6 = OMR_SIA;
+ lp->useMII = FALSE;
+
+ de4x5_switch_mac_port(dev);
+ }
- return dc2114x_autoconf(dev);
+ return dc2114x_autoconf(dev);
}
-static int type3_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+type3_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char len = (*p & BLOCK_LEN)+1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char len = (*p & BLOCK_LEN)+1;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p + len) < 128) {
- return dc_infoblock[COMPACT] (dev, count, p + len);
- } else {
- return dc_infoblock[*(p + len + 1)] (dev, count, p + len);
- }
- }
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
+ }
+ }
+
+ p += 2;
+ if (lp->state == INITIALISED) {
+ lp->active = *p++;
+ lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
+ lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
+ lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].mci = *p;
+ return 0;
+ } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 3;
+ lp->active = *p;
+ lp->infoblock_csr6 = OMR_MII_100;
+ lp->useMII = TRUE;
+ lp->infoblock_media = ANS;
- p += 2;
- if (lp->state == INITIALISED) {
- lp->active = *p++;
- lp->phy[lp->active].gep = (*p ? p : 0);
- p += (2 * (*p) + 1);
- lp->phy[lp->active].rst = (*p ? p : 0);
- p += (2 * (*p) + 1);
- lp->phy[lp->active].mc = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p);
- p += 2;
- lp->phy[lp->active].mci = *p;
- return 0;
- } else if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = 3;
- lp->active = *p;
- lp->infoblock_csr6 = OMR_MII_100;
- lp->useMII = TRUE;
- lp->infoblock_media = ANS;
-
- de4x5_switch_mac_port(dev);
- }
-
- return dc2114x_autoconf(dev);
+ de4x5_switch_mac_port(dev);
+ }
+
+ return dc2114x_autoconf(dev);
}
-static int type4_infoblock(struct device *dev, u_char count, u_char *p)
+static int
+type4_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
-
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p+len) < 128) {
- return dc_infoblock[COMPACT](dev, count, p+len);
- } else {
- return dc_infoblock[*(p+len+1)](dev, count, p+len);
- }
- }
-
- if ((lp->media == INIT) && (lp->timeout < 0)) {
- lp->ibn = 4;
- lp->active = 0;
- p += 2;
- lp->infoblock_media = (*p++) & MEDIA_CODE;
- lp->cache.csr13 = CSR13; /* Hard coded defaults */
- lp->cache.csr14 = CSR14;
- lp->cache.csr15 = CSR15;
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2;
- csr6 = *p++;
- flags = *p++;
-
- lp->asBitValid = (flags & 0x80) ? 0 : -1;
- lp->defMedium = (flags & 0x40) ? -1 : 0;
- lp->asBit = 1 << ((csr6 >> 1) & 0x07);
- lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
- lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
- de4x5_switch_mac_port(dev);
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
}
+ }
- return dc2114x_autoconf(dev);
+ if ((lp->media == INIT) && (lp->timeout < 0)) {
+ lp->ibn = 4;
+ lp->active = 0;
+ p+=2;
+ lp->infoblock_media = (*p++) & MEDIA_CODE;
+ lp->cache.csr13 = CSR13; /* Hard coded defaults */
+ lp->cache.csr14 = CSR14;
+ lp->cache.csr15 = CSR15;
+ lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2;
+ csr6 = *p++;
+ flags = *p++;
+
+ lp->asBitValid = (flags & 0x80) ? 0 : -1;
+ lp->defMedium = (flags & 0x40) ? -1 : 0;
+ lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+ lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+ lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+ lp->useMII = FALSE;
+
+ de4x5_switch_mac_port(dev);
+ }
+
+ return dc2114x_autoconf(dev);
}
/*
** This block type provides information for resetting external devices
** (chips) through the General Purpose Register.
*/
-static int type5_infoblock(struct device *dev, u_char count, u_char * p)
+static int
+type5_infoblock(struct device *dev, u_char count, u_char *p)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_char len = (*p & BLOCK_LEN)+1;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_char len = (*p & BLOCK_LEN)+1;
- /* Recursively figure out the info blocks */
- if (--count > lp->tcount) {
- if (*(p + len) < 128) {
- return dc_infoblock[COMPACT] (dev, count, p + len);
- } else {
- return dc_infoblock[*(p + len + 1)] (dev, count, p + len);
- }
- }
- /* Must be initializing to run this code */
- if ((lp->state == INITIALISED) || (lp->media == INIT)) {
- p += 2;
- lp->rst = p;
- srom_exec(dev, lp->rst);
+ /* Recursively figure out the info blocks */
+ if (--count > lp->tcount) {
+ if (*(p+len) < 128) {
+ return dc_infoblock[COMPACT](dev, count, p+len);
+ } else {
+ return dc_infoblock[*(p+len+1)](dev, count, p+len);
}
- return DE4X5_AUTOSENSE_MS;
+ }
+
+ /* Must be initializing to run this code */
+ if ((lp->state == INITIALISED) || (lp->media == INIT)) {
+ p+=2;
+ lp->rst = p;
+ srom_exec(dev, lp->rst);
+ }
+
+ return DE4X5_AUTOSENSE_MS;
}
/*
** MII Read/Write
*/
-static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
+static int
+mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
{
- mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */
- mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */
- mii_wdata(MII_STRD, 4, ioaddr); /* SFD and Read operation */
- mii_address(phyaddr, ioaddr); /* PHY address to be accessed */
- mii_address(phyreg, ioaddr); /* PHY Register to read */
- mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */
-
- return mii_rdata(ioaddr); /* Read data */
+ mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */
+ mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */
+ mii_wdata(MII_STRD, 4, ioaddr); /* SFD and Read operation */
+ mii_address(phyaddr, ioaddr); /* PHY address to be accessed */
+ mii_address(phyreg, ioaddr); /* PHY Register to read */
+ mii_ta(MII_STRD, ioaddr); /* Turn around time - 2 MDC */
+
+ return mii_rdata(ioaddr); /* Read data */
}
-static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
+static void
+mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
{
- mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */
- mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */
- mii_wdata(MII_STWR, 4, ioaddr); /* SFD and Write operation */
- mii_address(phyaddr, ioaddr); /* PHY address to be accessed */
- mii_address(phyreg, ioaddr); /* PHY Register to write */
- mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */
- data = mii_swap(data, 16); /* Swap data bit ordering */
- mii_wdata(data, 16, ioaddr); /* Write data */
-
- return;
+ mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */
+ mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */
+ mii_wdata(MII_STWR, 4, ioaddr); /* SFD and Write operation */
+ mii_address(phyaddr, ioaddr); /* PHY address to be accessed */
+ mii_address(phyreg, ioaddr); /* PHY Register to write */
+ mii_ta(MII_STWR, ioaddr); /* Turn around time - 2 MDC */
+ data = mii_swap(data, 16); /* Swap data bit ordering */
+ mii_wdata(data, 16, ioaddr); /* Write data */
+
+ return;
}
-static int mii_rdata(u_long ioaddr)
+static int
+mii_rdata(u_long ioaddr)
{
- int i;
- s32 tmp = 0;
-
- for (i = 0; i < 16; i++) {
- tmp <<= 1;
- tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
- }
-
- return tmp;
+ int i;
+ s32 tmp = 0;
+
+ for (i=0; i<16; i++) {
+ tmp <<= 1;
+ tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
+ }
+
+ return tmp;
}
-static void mii_wdata(int data, int len, u_long ioaddr)
+static void
+mii_wdata(int data, int len, u_long ioaddr)
{
- int i;
-
- for (i = 0; i < len; i++) {
- sendto_mii(MII_MWR | MII_WR, data, ioaddr);
- data >>= 1;
- }
-
- return;
+ int i;
+
+ for (i=0; i<len; i++) {
+ sendto_mii(MII_MWR | MII_WR, data, ioaddr);
+ data >>= 1;
+ }
+
+ return;
}
-static void mii_address(u_char addr, u_long ioaddr)
+static void
+mii_address(u_char addr, u_long ioaddr)
{
- int i;
-
- addr = mii_swap(addr, 5);
- for (i = 0; i < 5; i++) {
- sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
- addr >>= 1;
- }
-
- return;
+ int i;
+
+ addr = mii_swap(addr, 5);
+ for (i=0; i<5; i++) {
+ sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
+ addr >>= 1;
+ }
+
+ return;
}
-static void mii_ta(u_long rw, u_long ioaddr)
+static void
+mii_ta(u_long rw, u_long ioaddr)
{
- if (rw == MII_STWR) {
- sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
- sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
- } else {
- getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */
- }
-
- return;
+ if (rw == MII_STWR) {
+ sendto_mii(MII_MWR | MII_WR, 1, ioaddr);
+ sendto_mii(MII_MWR | MII_WR, 0, ioaddr);
+ } else {
+ getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */
+ }
+
+ return;
}
-static int mii_swap(int data, int len)
+static int
+mii_swap(int data, int len)
{
- int i, tmp = 0;
-
- for (i = 0; i < len; i++) {
- tmp <<= 1;
- tmp |= (data & 1);
- data >>= 1;
- }
-
- return tmp;
+ int i, tmp = 0;
+
+ for (i=0; i<len; i++) {
+ tmp <<= 1;
+ tmp |= (data & 1);
+ data >>= 1;
+ }
+
+ return tmp;
}
-static void sendto_mii(u32 command, int data, u_long ioaddr)
+static void
+sendto_mii(u32 command, int data, u_long ioaddr)
{
- u32 j;
-
- j = (data & 1) << 17;
- outl(command | j, ioaddr);
- udelay(1);
- outl(command | MII_MDC | j, ioaddr);
- udelay(1);
-
- return;
+ u32 j;
+
+ j = (data & 1) << 17;
+ outl(command | j, ioaddr);
+ udelay(1);
+ outl(command | MII_MDC | j, ioaddr);
+ udelay(1);
+
+ return;
}
-static int getfrom_mii(u32 command, u_long ioaddr)
+static int
+getfrom_mii(u32 command, u_long ioaddr)
{
- outl(command, ioaddr);
- udelay(1);
- outl(command | MII_MDC, ioaddr);
- udelay(1);
-
- return ((inl(ioaddr) >> 19) & 1);
+ outl(command, ioaddr);
+ udelay(1);
+ outl(command | MII_MDC, ioaddr);
+ udelay(1);
+
+ return ((inl(ioaddr) >> 19) & 1);
}
/*
** Here's 3 ways to calculate the OUI from the ID registers.
*/
-static int mii_get_oui(u_char phyaddr, u_long ioaddr)
+static int
+mii_get_oui(u_char phyaddr, u_long ioaddr)
{
/*
- union {
- u_short reg;
- u_char breg[2];
- } a;
- int i, r2, r3, ret=0; */
- int r2, r3;
-
- /* Read r2 and r3 */
- r2 = mii_rd(MII_ID0, phyaddr, ioaddr);
- r3 = mii_rd(MII_ID1, phyaddr, ioaddr);
- /* SEEQ and Cypress way * /
- / * Shuffle r2 and r3 * /
- a.reg=0;
- r3 = ((r3>>10)|(r2<<6))&0x0ff;
- r2 = ((r2>>2)&0x3fff);
-
- / * Bit reverse r3 * /
- for (i=0;i<8;i++) {
- ret<<=1;
- ret |= (r3&1);
- r3>>=1;
- }
-
- / * Bit reverse r2 * /
- for (i=0;i<16;i++) {
- a.reg<<=1;
- a.reg |= (r2&1);
- r2>>=1;
- }
-
- / * Swap r2 bytes * /
- i=a.breg[0];
- a.breg[0]=a.breg[1];
- a.breg[1]=i;
-
- return ((a.reg<<8)|ret); *//* SEEQ and Cypress way */
- /* return ((r2<<6)|(u_int)(r3>>10)); *//* NATIONAL and BROADCOM way */
- return r2; /* (I did it) My way */
+ union {
+ u_short reg;
+ u_char breg[2];
+ } a;
+ int i, r2, r3, ret=0;*/
+ int r2, r3;
+
+ /* Read r2 and r3 */
+ r2 = mii_rd(MII_ID0, phyaddr, ioaddr);
+ r3 = mii_rd(MII_ID1, phyaddr, ioaddr);
+ /* SEEQ and Cypress way * /
+ / * Shuffle r2 and r3 * /
+ a.reg=0;
+ r3 = ((r3>>10)|(r2<<6))&0x0ff;
+ r2 = ((r2>>2)&0x3fff);
+
+ / * Bit reverse r3 * /
+ for (i=0;i<8;i++) {
+ ret<<=1;
+ ret |= (r3&1);
+ r3>>=1;
+ }
+
+ / * Bit reverse r2 * /
+ for (i=0;i<16;i++) {
+ a.reg<<=1;
+ a.reg |= (r2&1);
+ r2>>=1;
+ }
+
+ / * Swap r2 bytes * /
+ i=a.breg[0];
+ a.breg[0]=a.breg[1];
+ a.breg[1]=i;
+
+ return ((a.reg<<8)|ret); */ /* SEEQ and Cypress way */
+/* return ((r2<<6)|(u_int)(r3>>10)); */ /* NATIONAL and BROADCOM way */
+ return r2; /* (I did it) My way */
}
/*
** The SROM spec forces us to search addresses [1-31 0]. Bummer.
*/
-static int mii_get_phy(struct device *dev)
+static int
+mii_get_phy(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int i, j, k, n, limit = sizeof(phy_info) / sizeof(struct phy_table);
- int id;
-
- lp->active = 0;
- lp->useMII = TRUE;
-
- /* Search the MII address space for possible PHY devices */
- for (n = 0, lp->mii_cnt = 0, i = 1; !((i == 1) && (n == 1)); i = (++i) % DE4X5_MAX_MII) {
- lp->phy[lp->active].addr = i;
- if (i == 0)
- n++; /* Count cycles */
- while (de4x5_reset_phy(dev) < 0)
- udelay(100); /* Wait for reset */
- id = mii_get_oui(i, DE4X5_MII);
- if ((id == 0) || (id == 65535))
- continue; /* Valid ID? */
- for (j = 0; j < limit; j++) { /* Search PHY table */
- if (id != phy_info[j].id)
- continue; /* ID match? */
- for (k = 0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
- if (k < DE4X5_MAX_PHY) {
- memcpy((char *) &lp->phy[k],
- (char *) &phy_info[j], sizeof(struct phy_table));
- lp->phy[k].addr = i;
- lp->mii_cnt++;
- lp->active++;
- } else {
- goto purgatory; /* Stop the search */
- }
- break;
- }
- if ((j == limit) && (i < DE4X5_MAX_MII)) {
- printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name);
- de4x5_debug |= DEBUG_MII;
- de4x5_dbg_mii(dev, i);
- printk("\n");
- }
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
+ int id;
+
+ lp->active = 0;
+ lp->useMII = TRUE;
+
+ /* Search the MII address space for possible PHY devices */
+ for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
+ lp->phy[lp->active].addr = i;
+ if (i==0) n++; /* Count cycles */
+ while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
+ id = mii_get_oui(i, DE4X5_MII);
+ if ((id == 0) || (id == 65535)) continue; /* Valid ID? */
+ for (j=0; j<limit; j++) { /* Search PHY table */
+ if (id != phy_info[j].id) continue; /* ID match? */
+ for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ if (k < DE4X5_MAX_PHY) {
+ memcpy((char *)&lp->phy[k],
+ (char *)&phy_info[j], sizeof(struct phy_table));
+ lp->phy[k].addr = i;
+ lp->mii_cnt++;
+ lp->active++;
+ } else {
+ goto purgatory; /* Stop the search */
+ }
+ break;
+ }
+ if ((j == limit) && (i < DE4X5_MAX_MII)) {
+ for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+ lp->phy[k].addr = i;
+ lp->phy[k].id = id;
+ lp->phy[k].spd.reg = GENERIC_REG; /* ANLPA register */
+ lp->phy[k].spd.mask = GENERIC_MASK; /* 100Mb/s technologies */
+ lp->phy[k].spd.value = GENERIC_VALUE; /* TX & T4, H/F Duplex */
+ lp->mii_cnt++;
+ lp->active++;
+ printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name);
+ j = de4x5_debug;
+ de4x5_debug |= DEBUG_MII;
+ de4x5_dbg_mii(dev, k);
+ de4x5_debug = j;
+ printk("\n");
+ }
+ }
purgatory:
- lp->active = 0;
- if (lp->phy[0].id) { /* Reset the PHY devices */
- for (k = 0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY */
- mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
- while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
-
- de4x5_dbg_mii(dev, k);
- }
+ lp->active = 0;
+ if (lp->phy[0].id) { /* Reset the PHY devices */
+ for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
+ mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
+ while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
+
+ de4x5_dbg_mii(dev, k);
}
- if (!lp->mii_cnt)
- lp->useMII = FALSE;
+ }
+ if (!lp->mii_cnt) lp->useMII = FALSE;
- return lp->mii_cnt;
+ return lp->mii_cnt;
}
-static char *build_setup_frame(struct device *dev, int mode)
+static char *
+build_setup_frame(struct device *dev, int mode)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i;
- char *pa = lp->setup_frame;
-
- /* Initialise the setup frame */
- if (mode == ALL) {
- memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
- }
- if (lp->setup_f == HASH_PERF) {
- for (pa = lp->setup_frame + IMPERF_PA_OFFSET, i = 0; i < ETH_ALEN; i++) {
- *(pa + i) = dev->dev_addr[i]; /* Host address */
- if (i & 0x01)
- pa += 2;
- }
- *(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
- } else {
- for (i = 0; i < ETH_ALEN; i++) { /* Host address */
- *(pa + (i & 1)) = dev->dev_addr[i];
- if (i & 0x01)
- pa += 4;
- }
- for (i = 0; i < ETH_ALEN; i++) { /* Broadcast address */
- *(pa + (i & 1)) = (char) 0xff;
- if (i & 0x01)
- pa += 4;
- }
- }
-
- return pa; /* Points to the next entry */
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i;
+ char *pa = lp->setup_frame;
+
+ /* Initialise the setup frame */
+ if (mode == ALL) {
+ memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
+ }
+
+ if (lp->setup_f == HASH_PERF) {
+ for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
+ *(pa + i) = dev->dev_addr[i]; /* Host address */
+ if (i & 0x01) pa += 2;
+ }
+ *(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
+ } else {
+ for (i=0; i<ETH_ALEN; i++) { /* Host address */
+ *(pa + (i&1)) = dev->dev_addr[i];
+ if (i & 0x01) pa += 4;
+ }
+ for (i=0; i<ETH_ALEN; i++) { /* Broadcast address */
+ *(pa + (i&1)) = (char) 0xff;
+ if (i & 0x01) pa += 4;
+ }
+ }
+
+ return pa; /* Points to the next entry */
}
-static void enable_ast(struct device *dev, u32 time_out)
+static void
+enable_ast(struct device *dev, u32 time_out)
{
- timeout(dev, (void *) &de4x5_ast, (u_long) dev, time_out);
-
- return;
+ timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
+
+ return;
}
-static void disable_ast(struct device *dev)
+static void
+disable_ast(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
-
- del_timer(&lp->timer);
-
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+ del_timer(&lp->timer);
+
+ return;
}
-static long de4x5_switch_mac_port(struct device *dev)
+static long
+de4x5_switch_mac_port(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
- s32 omr;
-
- STOP_DE4X5;
-
- /* Assert the OMR_PS bit in CSR6 */
- omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
- OMR_FDX));
- omr |= lp->infoblock_csr6;
- if (omr & OMR_PS)
- omr |= OMR_HBD;
- outl(omr, DE4X5_OMR);
-
- /* Soft Reset */
- RESET_DE4X5;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 omr;
+
+ STOP_DE4X5;
+
+ /* Assert the OMR_PS bit in CSR6 */
+ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
+ OMR_FDX));
+ omr |= lp->infoblock_csr6;
+ if (omr & OMR_PS) omr |= OMR_HBD;
+ outl(omr, DE4X5_OMR);
+
+ /* Soft Reset */
+ RESET_DE4X5;
+
+ /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
+ if (lp->chipset == DC21140) {
+ gep_wr(lp->cache.gepc, dev);
+ gep_wr(lp->cache.gep, dev);
+ } else if ((lp->chipset & ~0x0ff) == DC2114x) {
+ reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
+ }
- /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
- if (lp->chipset == DC21140) {
- gep_wr(lp->cache.gepc, dev);
- gep_wr(lp->cache.gep, dev);
- } else if ((lp->chipset & ~0x0ff) == DC2114x) {
- reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
- }
- /* Restore CSR6 */
- outl(omr, DE4X5_OMR);
+ /* Restore CSR6 */
+ outl(omr, DE4X5_OMR);
- /* Reset CSR8 */
- inl(DE4X5_MFC);
+ /* Reset CSR8 */
+ inl(DE4X5_MFC);
- return omr;
+ return omr;
}
-static void gep_wr(s32 data, struct device *dev)
+static void
+gep_wr(s32 data, struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
- if (lp->chipset == DC21140) {
- outl(data, DE4X5_GEP);
- } else if ((lp->chipset & ~0x00ff) == DC2114x) {
- outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
- }
+ if (lp->chipset == DC21140) {
+ outl(data, DE4X5_GEP);
+ } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+ outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
+ }
- return;
+ return;
}
-static int gep_rd(struct device *dev)
+static int
+gep_rd(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- u_long iobase = dev->base_addr;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
- if (lp->chipset == DC21140) {
- return inl(DE4X5_GEP);
- } else if ((lp->chipset & ~0x00ff) == DC2114x) {
- return (inl(DE4X5_SIGR) & 0x000fffff);
- }
+ if (lp->chipset == DC21140) {
+ return inl(DE4X5_GEP);
+ } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+ return (inl(DE4X5_SIGR) & 0x000fffff);
+ }
- return 0;
+ return 0;
}
-static void timeout(struct device *dev, void (*fn) (u_long data), u_long data, u_long msec)
+static void
+timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int dt;
-
- /* First, cancel any pending timer events */
- del_timer(&lp->timer);
-
- /* Convert msec to ticks */
- dt = (msec * HZ) / 1000;
- if (dt == 0)
- dt = 1;
-
- /* Set up timer */
- lp->timer.expires = jiffies + dt;
- lp->timer.function = fn;
- lp->timer.data = data;
- add_timer(&lp->timer);
-
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int dt;
+
+ /* First, cancel any pending timer events */
+ del_timer(&lp->timer);
+
+ /* Convert msec to ticks */
+ dt = (msec * HZ) / 1000;
+ if (dt==0) dt=1;
+
+ /* Set up timer */
+ lp->timer.expires = jiffies + dt;
+ lp->timer.function = fn;
+ lp->timer.data = data;
+ add_timer(&lp->timer);
+
+ return;
}
-static void yawn(struct device *dev, int state)
+static void
+yawn(struct device *dev, int state)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- if ((lp->chipset == DC21040) || (lp->chipset == DC21140))
- return;
-
- if (lp->bus == EISA) {
- switch (state) {
- case WAKEUP:
- outb(WAKEUP, PCI_CFPM);
- de4x5_ms_delay(10);
- break;
-
- case SNOOZE:
- outb(SNOOZE, PCI_CFPM);
- break;
-
- case SLEEP:
- outl(0, DE4X5_SICR);
- outb(SLEEP, PCI_CFPM);
- break;
- }
- } else {
- switch (state) {
- case WAKEUP:
- pcibios_write_config_byte(lp->bus_num, lp->device << 3,
- PCI_CFDA_PSM, WAKEUP);
- de4x5_ms_delay(10);
- break;
-
- case SNOOZE:
- pcibios_write_config_byte(lp->bus_num, lp->device << 3,
- PCI_CFDA_PSM, SNOOZE);
- break;
-
- case SLEEP:
- outl(0, DE4X5_SICR);
- pcibios_write_config_byte(lp->bus_num, lp->device << 3,
- PCI_CFDA_PSM, SLEEP);
- break;
- }
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
+
+ if(lp->bus == EISA) {
+ switch(state) {
+ case WAKEUP:
+ outb(WAKEUP, PCI_CFPM);
+ de4x5_ms_delay(10);
+ break;
+
+ case SNOOZE:
+ outb(SNOOZE, PCI_CFPM);
+ break;
+
+ case SLEEP:
+ outl(0, DE4X5_SICR);
+ outb(SLEEP, PCI_CFPM);
+ break;
+ }
+ } else {
+ switch(state) {
+ case WAKEUP:
+ pcibios_write_config_byte(lp->bus_num, lp->device << 3,
+ PCI_CFDA_PSM, WAKEUP);
+ de4x5_ms_delay(10);
+ break;
+
+ case SNOOZE:
+ pcibios_write_config_byte(lp->bus_num, lp->device << 3,
+ PCI_CFDA_PSM, SNOOZE);
+ break;
+
+ case SLEEP:
+ outl(0, DE4X5_SICR);
+ pcibios_write_config_byte(lp->bus_num, lp->device << 3,
+ PCI_CFDA_PSM, SLEEP);
+ break;
+ }
+ }
+
+ return;
+}
- return;
+static void
+de4x5_parse_params(struct device *dev)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ char *p, *q, t;
+
+ lp->params.fdx = 0;
+ lp->params.autosense = AUTO;
+
+ if (args == NULL) return;
+
+ if ((p = strstr(args, dev->name))) {
+ if (!(q = strstr(p+strlen(dev->name), "eth"))) q = p + strlen(p);
+ t = *q;
+ *q = '\0';
+
+ if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
+
+ if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
+ if (strstr(p, "TP")) {
+ lp->params.autosense = TP;
+ } else if (strstr(p, "TP_NW")) {
+ lp->params.autosense = TP_NW;
+ } else if (strstr(p, "BNC")) {
+ lp->params.autosense = BNC;
+ } else if (strstr(p, "AUI")) {
+ lp->params.autosense = AUI;
+ } else if (strstr(p, "BNC_AUI")) {
+ lp->params.autosense = BNC;
+ } else if (strstr(p, "10Mb")) {
+ lp->params.autosense = _10Mb;
+ } else if (strstr(p, "100Mb")) {
+ lp->params.autosense = _100Mb;
+ } else if (strstr(p, "AUTO")) {
+ lp->params.autosense = AUTO;
+ }
+ }
+ *q = t;
+ }
+
+ return;
}
-static void de4x5_dbg_open(struct device *dev)
+static void
+de4x5_dbg_open(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- int i;
-
- if (de4x5_debug & DEBUG_OPEN) {
- printk("%s: de4x5 opening with irq %d\n", dev->name, dev->irq);
- printk("\tphysical address: ");
- for (i = 0; i < 6; i++) {
- printk("%2.2x:", (short) dev->dev_addr[i]);
- }
- printk("\n");
- printk("Descriptor head addresses:\n");
- printk("\t0x%8.8lx 0x%8.8lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
- printk("Descriptor addresses:\nRX: ");
- for (i = 0; i < lp->rxRingSize - 1; i++) {
- if (i < 3) {
- printk("0x%8.8lx ", (u_long) & lp->rx_ring[i].status);
- }
- }
- printk("...0x%8.8lx\n", (u_long) & lp->rx_ring[i].status);
- printk("TX: ");
- for (i = 0; i < lp->txRingSize - 1; i++) {
- if (i < 3) {
- printk("0x%8.8lx ", (u_long) & lp->tx_ring[i].status);
- }
- }
- printk("...0x%8.8lx\n", (u_long) & lp->tx_ring[i].status);
- printk("Descriptor buffers:\nRX: ");
- for (i = 0; i < lp->rxRingSize - 1; i++) {
- if (i < 3) {
- printk("0x%8.8x ", le32_to_cpu(lp->rx_ring[i].buf));
- }
- }
- printk("...0x%8.8x\n", le32_to_cpu(lp->rx_ring[i].buf));
- printk("TX: ");
- for (i = 0; i < lp->txRingSize - 1; i++) {
- if (i < 3) {
- printk("0x%8.8x ", le32_to_cpu(lp->tx_ring[i].buf));
- }
- }
- printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
- printk("Ring size: \nRX: %d\nTX: %d\n",
- (short) lp->rxRingSize,
- (short) lp->txRingSize);
- }
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ int i;
+
+ if (de4x5_debug & DEBUG_OPEN) {
+ printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
+ printk("\tphysical address: ");
+ for (i=0;i<6;i++) {
+ printk("%2.2x:",(short)dev->dev_addr[i]);
+ }
+ printk("\n");
+ printk("Descriptor head addresses:\n");
+ printk("\t0x%8.8lx 0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
+ printk("Descriptor addresses:\nRX: ");
+ for (i=0;i<lp->rxRingSize-1;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ",(u_long)&lp->rx_ring[i].status);
+ }
+ }
+ printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
+ printk("TX: ");
+ for (i=0;i<lp->txRingSize-1;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ", (u_long)&lp->tx_ring[i].status);
+ }
+ }
+ printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
+ printk("Descriptor buffers:\nRX: ");
+ for (i=0;i<lp->rxRingSize-1;i++){
+ if (i < 3) {
+ printk("0x%8.8x ",le32_to_cpu(lp->rx_ring[i].buf));
+ }
+ }
+ printk("...0x%8.8x\n",le32_to_cpu(lp->rx_ring[i].buf));
+ printk("TX: ");
+ for (i=0;i<lp->txRingSize-1;i++){
+ if (i < 3) {
+ printk("0x%8.8x ", le32_to_cpu(lp->tx_ring[i].buf));
+ }
+ }
+ printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
+ printk("Ring size: \nRX: %d\nTX: %d\n",
+ (short)lp->rxRingSize,
+ (short)lp->txRingSize);
+ }
+
+ return;
}
-static void de4x5_dbg_mii(struct device *dev, int k)
+static void
+de4x5_dbg_mii(struct device *dev, int k)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- u_long iobase = dev->base_addr;
-
- if (de4x5_debug & DEBUG_MII) {
- printk("\nMII CR: %x\n", mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII));
- printk("MII SR: %x\n", mii_rd(MII_SR, lp->phy[k].addr, DE4X5_MII));
- printk("MII ID0: %x\n", mii_rd(MII_ID0, lp->phy[k].addr, DE4X5_MII));
- printk("MII ID1: %x\n", mii_rd(MII_ID1, lp->phy[k].addr, DE4X5_MII));
- if (lp->phy[k].id != BROADCOM_T4) {
- printk("MII ANA: %x\n", mii_rd(0x04, lp->phy[k].addr, DE4X5_MII));
- printk("MII ANC: %x\n", mii_rd(0x05, lp->phy[k].addr, DE4X5_MII));
- }
- printk("MII 16: %x\n", mii_rd(0x10, lp->phy[k].addr, DE4X5_MII));
- if (lp->phy[k].id != BROADCOM_T4) {
- printk("MII 17: %x\n", mii_rd(0x11, lp->phy[k].addr, DE4X5_MII));
- printk("MII 18: %x\n", mii_rd(0x12, lp->phy[k].addr, DE4X5_MII));
- } else {
- printk("MII 20: %x\n", mii_rd(0x14, lp->phy[k].addr, DE4X5_MII));
- }
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ if (de4x5_debug & DEBUG_MII) {
+ printk("\nMII device address: %d\n", lp->phy[k].addr);
+ printk("MII CR: %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
+ printk("MII SR: %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
+ printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
+ printk("MII ID1: %x\n",mii_rd(MII_ID1,lp->phy[k].addr,DE4X5_MII));
+ if (lp->phy[k].id != BROADCOM_T4) {
+ printk("MII ANA: %x\n",mii_rd(0x04,lp->phy[k].addr,DE4X5_MII));
+ printk("MII ANC: %x\n",mii_rd(0x05,lp->phy[k].addr,DE4X5_MII));
+ }
+ printk("MII 16: %x\n",mii_rd(0x10,lp->phy[k].addr,DE4X5_MII));
+ if (lp->phy[k].id != BROADCOM_T4) {
+ printk("MII 17: %x\n",mii_rd(0x11,lp->phy[k].addr,DE4X5_MII));
+ printk("MII 18: %x\n",mii_rd(0x12,lp->phy[k].addr,DE4X5_MII));
+ } else {
+ printk("MII 20: %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
}
- return;
+ }
+
+ return;
}
-static void de4x5_dbg_media(struct device *dev)
+static void
+de4x5_dbg_media(struct device *dev)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
-
- if (lp->media != lp->c_media) {
- if (de4x5_debug & DEBUG_MEDIA) {
- if (lp->chipset != DC21140) {
- printk("%s: media is %s%s\n", dev->name,
- (lp->media == NC ? "unconnected, link down or incompatible connection" :
- (lp->media == TP ? "TP" :
- (lp->media == ANS ? "TP/Nway" :
- (lp->media == BNC ? "BNC" :
- (lp->media == AUI ? "AUI" :
- (lp->media == BNC_AUI ? "BNC/AUI" :
- (lp->media == EXT_SIA ? "EXT SIA" :
- (lp->media == _100Mb ? "100Mb/s" :
- (lp->media == _10Mb ? "10Mb/s" :
- "???"
- ))))))))),
- (lp->fdx?" full duplex.":"."));
- }
- }
- lp->c_media = lp->media;
- }
- return;
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+ if (lp->media != lp->c_media) {
+ if (de4x5_debug & DEBUG_MEDIA) {
+ printk("%s: media is %s%s\n", dev->name,
+ (lp->media == NC ? "unconnected, link down or incompatible connection" :
+ (lp->media == TP ? "TP" :
+ (lp->media == ANS ? "TP/Nway" :
+ (lp->media == BNC ? "BNC" :
+ (lp->media == AUI ? "AUI" :
+ (lp->media == BNC_AUI ? "BNC/AUI" :
+ (lp->media == EXT_SIA ? "EXT SIA" :
+ (lp->media == _100Mb ? "100Mb/s" :
+ (lp->media == _10Mb ? "10Mb/s" :
+ "???"
+ ))))))))), (lp->fdx?" full duplex.":"."));
+ }
+ lp->c_media = lp->media;
+ }
+
+ return;
}
-static void de4x5_dbg_srom(struct de4x5_srom *p)
+static void
+de4x5_dbg_srom(struct de4x5_srom *p)
{
- int i;
-
- if (de4x5_debug & DEBUG_SROM) {
- printk("Sub-system Vendor ID: %04x\n", *((u_short *) p->sub_vendor_id));
- printk("Sub-system ID: %04x\n", *((u_short *) p->sub_system_id));
- printk("ID Block CRC: %02x\n", (u_char) (p->id_block_crc));
- printk("SROM version: %02x\n", (u_char) (p->version));
- printk("# controllers: %02x\n", (u_char) (p->num_controllers));
-
- printk("Hardware Address: ");
- for (i = 0; i < ETH_ALEN - 1; i++) {
- printk("%02x:", (u_char) * (p->ieee_addr + i));
- }
- printk("%02x\n", (u_char) * (p->ieee_addr + i));
- printk("CRC checksum: %04x\n", (u_short) (p->chksum));
- for (i = 0; i < 64; i++) {
- printk("%3d %04x\n", i << 1, (u_short) * ((u_short *) p + i));
- }
+ int i;
+
+ if (de4x5_debug & DEBUG_SROM) {
+ printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
+ printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id));
+ printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc));
+ printk("SROM version: %02x\n", (u_char)(p->version));
+ printk("# controllers: %02x\n", (u_char)(p->num_controllers));
+
+ printk("Hardware Address: ");
+ for (i=0;i<ETH_ALEN-1;i++) {
+ printk("%02x:", (u_char)*(p->ieee_addr+i));
}
- return;
+ printk("%02x\n", (u_char)*(p->ieee_addr+i));
+ printk("CRC checksum: %04x\n", (u_short)(p->chksum));
+ for (i=0; i<64; i++) {
+ printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
+ }
+ }
+
+ return;
}
-static void de4x5_dbg_rx(struct sk_buff *skb, int len)
+static void
+de4x5_dbg_rx(struct sk_buff *skb, int len)
{
- int i, j;
-
+ int i, j;
+
+ if (de4x5_debug & DEBUG_RX) {
+ printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+ (u_char)skb->data[0],
+ (u_char)skb->data[1],
+ (u_char)skb->data[2],
+ (u_char)skb->data[3],
+ (u_char)skb->data[4],
+ (u_char)skb->data[5],
+ (u_char)skb->data[6],
+ (u_char)skb->data[7],
+ (u_char)skb->data[8],
+ (u_char)skb->data[9],
+ (u_char)skb->data[10],
+ (u_char)skb->data[11],
+ (u_char)skb->data[12],
+ (u_char)skb->data[13],
+ len);
if (de4x5_debug & DEBUG_RX) {
- printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
- (u_char) skb->data[0],
- (u_char) skb->data[1],
- (u_char) skb->data[2],
- (u_char) skb->data[3],
- (u_char) skb->data[4],
- (u_char) skb->data[5],
- (u_char) skb->data[6],
- (u_char) skb->data[7],
- (u_char) skb->data[8],
- (u_char) skb->data[9],
- (u_char) skb->data[10],
- (u_char) skb->data[11],
- (u_char) skb->data[12],
- (u_char) skb->data[13],
- len);
- if (de4x5_debug & DEBUG_RX) {
- for (j = 0; len > 0; j += 16, len -= 16) {
- printk(" %03x: ", j);
- for (i = 0; i < 16 && i < len; i++) {
- printk("%02x ", (u_char) skb->data[i + j]);
- }
- printk("\n");
- }
+ for (j=0; len>0;j+=16, len-=16) {
+ printk(" %03x: ",j);
+ for (i=0; i<16 && i<len; i++) {
+ printk("%02x ",(u_char)skb->data[i+j]);
}
+ printk("\n");
+ }
}
- return;
+ }
+
+ return;
}
/*
@@ -5244,248 +5418,242 @@ static void de4x5_dbg_rx(struct sk_buff *skb, int len)
** effective uid is checked in those cases. In the normal course of events
** this function is only used for my testing.
*/
-static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
- struct de4x5_private *lp = (struct de4x5_private *) dev->priv;
- struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
- u_long iobase = dev->base_addr;
- int i, j, status = 0;
- s32 omr;
- union {
- u8 addr[144];
- u16 sval[72];
- u32 lval[36];
- } tmp;
-
- switch (ioc->cmd) {
- case DE4X5_GET_HWADDR: /* Get the hardware address */
- ioc->len = ETH_ALEN;
- status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len);
- if (status)
- break;
- for (i = 0; i < ETH_ALEN; i++) {
- tmp.addr[i] = dev->dev_addr[i];
- }
- copy_to_user(ioc->data, tmp.addr, ioc->len);
-
- break;
- case DE4X5_SET_HWADDR: /* Set the hardware address */
- status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN);
- if (status)
- break;
- status = -EPERM;
- if (!suser())
- break;
- status = 0;
- copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- build_setup_frame(dev, PHYS_ADDR_ONLY);
- /* Set up the descriptor and give ownership to the card */
- while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
- load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
- SETUP_FRAME_LEN, NULL);
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
- dev->tbusy = 0; /* Unlock the TX ring */
-
- break;
- case DE4X5_SET_PROM: /* Set Promiscuous Mode */
- if (suser()) {
- omr = inl(DE4X5_OMR);
- omr |= OMR_PR;
- outl(omr, DE4X5_OMR);
- dev->flags |= IFF_PROMISC;
- } else {
- status = -EPERM;
- }
-
- break;
- case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
- if (suser()) {
- omr = inl(DE4X5_OMR);
- omr &= ~OMR_PR;
- outb(omr, DE4X5_OMR);
- dev->flags &= ~IFF_PROMISC;
- } else {
- status = -EPERM;
- }
-
- break;
- case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
- printk("%s: Boo!\n", dev->name);
-
- break;
- case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
- if (suser()) {
- omr = inl(DE4X5_OMR);
- omr |= OMR_PM;
- outl(omr, DE4X5_OMR);
- } else {
- status = -EPERM;
- }
-
- break;
- case DE4X5_GET_STATS: /* Get the driver statistics */
- ioc->len = sizeof(lp->pktStats);
- status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len);
- if (status)
- break;
-
- cli();
- copy_to_user(ioc->data, &lp->pktStats, ioc->len);
- sti();
-
- break;
- case DE4X5_CLR_STATS: /* Zero out the driver statistics */
- if (suser()) {
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();
- } else {
- status = -EPERM;
- }
-
- break;
- case DE4X5_GET_OMR: /* Get the OMR Register contents */
- tmp.addr[0] = inl(DE4X5_OMR);
- if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, 1))) {
- copy_to_user(ioc->data, tmp.addr, 1);
- }
- break;
- case DE4X5_SET_OMR: /* Set the OMR Register contents */
- if (suser()) {
- if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, 1))) {
- copy_from_user(tmp.addr, ioc->data, 1);
- outl(tmp.addr[0], DE4X5_OMR);
- }
- } else {
- status = -EPERM;
- }
-
- break;
- case DE4X5_GET_REG: /* Get the DE4X5 Registers */
- j = 0;
- tmp.lval[0] = inl(DE4X5_STS);
- j += 4;
- tmp.lval[1] = inl(DE4X5_BMR);
- j += 4;
- tmp.lval[2] = inl(DE4X5_IMR);
- j += 4;
- tmp.lval[3] = inl(DE4X5_OMR);
- j += 4;
- tmp.lval[4] = inl(DE4X5_SISR);
- j += 4;
- tmp.lval[5] = inl(DE4X5_SICR);
- j += 4;
- tmp.lval[6] = inl(DE4X5_STRR);
- j += 4;
- tmp.lval[7] = inl(DE4X5_SIGR);
- j += 4;
- ioc->len = j;
- if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) {
- copy_to_user(ioc->data, tmp.addr, ioc->len);
- }
- break;
-
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
+ u_long iobase = dev->base_addr;
+ int i, j, status = 0;
+ s32 omr;
+ union {
+ u8 addr[144];
+ u16 sval[72];
+ u32 lval[36];
+ } tmp;
+
+ switch(ioc->cmd) {
+ case DE4X5_GET_HWADDR: /* Get the hardware address */
+ ioc->len = ETH_ALEN;
+ status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
+ if (status)
+ break;
+ for (i=0; i<ETH_ALEN; i++) {
+ tmp.addr[i] = dev->dev_addr[i];
+ }
+ copy_to_user(ioc->data, tmp.addr, ioc->len);
+
+ break;
+ case DE4X5_SET_HWADDR: /* Set the hardware address */
+ status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN);
+ if (status)
+ break;
+ status = -EPERM;
+ if (!suser())
+ break;
+ status = 0;
+ copy_from_user(tmp.addr, ioc->data, ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
+ }
+ build_setup_frame(dev, PHYS_ADDR_ONLY);
+ /* Set up the descriptor and give ownership to the card */
+ while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
+ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+ SETUP_FRAME_LEN, NULL);
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
+ dev->tbusy = 0; /* Unlock the TX ring */
+
+ break;
+ case DE4X5_SET_PROM: /* Set Promiscuous Mode */
+ if (suser()) {
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PR;
+ outl(omr, DE4X5_OMR);
+ dev->flags |= IFF_PROMISC;
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */
+ if (suser()) {
+ omr = inl(DE4X5_OMR);
+ omr &= ~OMR_PR;
+ outb(omr, DE4X5_OMR);
+ dev->flags &= ~IFF_PROMISC;
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ printk("%s: Boo!\n", dev->name);
+
+ break;
+ case DE4X5_MCA_EN: /* Enable pass all multicast addressing */
+ if (suser()) {
+ omr = inl(DE4X5_OMR);
+ omr |= OMR_PM;
+ outl(omr, DE4X5_OMR);
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DE4X5_GET_STATS: /* Get the driver statistics */
+ ioc->len = sizeof(lp->pktStats);
+ status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len);
+ if (status)
+ break;
+
+ cli();
+ copy_to_user(ioc->data, &lp->pktStats, ioc->len);
+ sti();
+
+ break;
+ case DE4X5_CLR_STATS: /* Zero out the driver statistics */
+ if (suser()) {
+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DE4X5_GET_OMR: /* Get the OMR Register contents */
+ tmp.addr[0] = inl(DE4X5_OMR);
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
+ copy_to_user(ioc->data, tmp.addr, 1);
+ }
+
+ break;
+ case DE4X5_SET_OMR: /* Set the OMR Register contents */
+ if (suser()) {
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
+ copy_from_user(tmp.addr, ioc->data, 1);
+ outl(tmp.addr[0], DE4X5_OMR);
+ }
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DE4X5_GET_REG: /* Get the DE4X5 Registers */
+ j = 0;
+ tmp.lval[0] = inl(DE4X5_STS); j+=4;
+ tmp.lval[1] = inl(DE4X5_BMR); j+=4;
+ tmp.lval[2] = inl(DE4X5_IMR); j+=4;
+ tmp.lval[3] = inl(DE4X5_OMR); j+=4;
+ tmp.lval[4] = inl(DE4X5_SISR); j+=4;
+ tmp.lval[5] = inl(DE4X5_SICR); j+=4;
+ tmp.lval[6] = inl(DE4X5_STRR); j+=4;
+ tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
+ ioc->len = j;
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ copy_to_user(ioc->data, tmp.addr, ioc->len);
+ }
+ break;
+
#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
/*
- case DE4X5_DUMP:
- j = 0;
- tmp.addr[j++] = dev->irq;
- for (i=0; i<ETH_ALEN; i++) {
- tmp.addr[j++] = dev->dev_addr[i];
- }
- tmp.addr[j++] = lp->rxRingSize;
- tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
- tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
-
- for (i=0;i<lp->rxRingSize-1;i++){
- if (i < 3) {
- tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
- }
- }
- tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
- for (i=0;i<lp->txRingSize-1;i++){
- if (i < 3) {
- tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
- }
- }
- tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
- for (i=0;i<lp->rxRingSize-1;i++){
- if (i < 3) {
- tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
- }
- }
- tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
- for (i=0;i<lp->txRingSize-1;i++){
- if (i < 3) {
- tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
- }
- }
- tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-
- for (i=0;i<lp->rxRingSize;i++){
- tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
- }
- for (i=0;i<lp->txRingSize;i++){
- tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
- }
-
- tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_STS); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4;
- tmp.lval[j>>2] = lp->chipset; j+=4;
- if (lp->chipset == DC21140) {
- tmp.lval[j>>2] = gep_rd(dev); j+=4;
- } else {
- tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
- tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
- }
- tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
- if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
- tmp.lval[j>>2] = lp->active; j+=4;
- tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- if (lp->phy[lp->active].id != BROADCOM_T4) {
- tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- }
- tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- if (lp->phy[lp->active].id != BROADCOM_T4) {
- tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- } else {
- tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
- }
- }
-
- tmp.addr[j++] = lp->txRingSize;
- tmp.addr[j++] = dev->tbusy;
-
- ioc->len = j;
- if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
- copy_to_user(ioc->data, tmp.addr, ioc->len);
- }
-
- break;
- */
- default:
- status = -EOPNOTSUPP;
+ case DE4X5_DUMP:
+ j = 0;
+ tmp.addr[j++] = dev->irq;
+ for (i=0; i<ETH_ALEN; i++) {
+ tmp.addr[j++] = dev->dev_addr[i];
+ }
+ tmp.addr[j++] = lp->rxRingSize;
+ tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
+ tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
+
+ for (i=0;i<lp->rxRingSize-1;i++){
+ if (i < 3) {
+ tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+ }
+ }
+ tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+ for (i=0;i<lp->txRingSize-1;i++){
+ if (i < 3) {
+ tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+ }
+ }
+ tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+
+ for (i=0;i<lp->rxRingSize-1;i++){
+ if (i < 3) {
+ tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
+ }
+ }
+ tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
+ for (i=0;i<lp->txRingSize-1;i++){
+ if (i < 3) {
+ tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
+ }
+ }
+ tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
+
+ for (i=0;i<lp->rxRingSize;i++){
+ tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
}
-
- return status;
+ for (i=0;i<lp->txRingSize;i++){
+ tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
+ }
+
+ tmp.lval[j>>2] = inl(DE4X5_BMR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_TPD); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_RPD); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_STS); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_OMR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_IMR); j+=4;
+ tmp.lval[j>>2] = lp->chipset; j+=4;
+ if (lp->chipset == DC21140) {
+ tmp.lval[j>>2] = gep_rd(dev); j+=4;
+ } else {
+ tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
+ tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
+ }
+ tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4;
+ if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+ tmp.lval[j>>2] = lp->active; j+=4;
+ tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ if (lp->phy[lp->active].id != BROADCOM_T4) {
+ tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ }
+ tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ if (lp->phy[lp->active].id != BROADCOM_T4) {
+ tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ } else {
+ tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+ }
+ }
+
+ tmp.addr[j++] = lp->txRingSize;
+ tmp.addr[j++] = dev->tbusy;
+
+ ioc->len = j;
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ copy_to_user(ioc->data, tmp.addr, ioc->len);
+ }
+
+ break;
+*/
+ default:
+ status = -EOPNOTSUPP;
+ }
+
+ return status;
}
#ifdef MODULE
@@ -5496,100 +5664,100 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
*/
#define LP(a) ((struct de4x5_private *)(a))
static struct device *mdev = NULL;
-static int io = 0x0; /* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED */
+static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED */
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
MODULE_PARM(io, "i");
#endif /* LINUX_VERSION_CODE */
-int init_module(void)
+int
+init_module(void)
{
- int i, num, status = -EIO;
- struct device *p;
+ int i, num, status = -EIO;
+ struct device *p;
- num = count_adapters();
+ num = count_adapters();
- for (i=0; i<num; i++) {
- if ((p = insert_device(NULL, io, de4x5_probe)) == NULL)
- return -ENOMEM;
+ for (i=0; i<num; i++) {
+ if ((p = insert_device(NULL, io, de4x5_probe)) == NULL)
+ return -ENOMEM;
- if (!mdev)
- mdev = p;
+ if (!mdev) mdev = p;
- if (register_netdev(p) != 0) {
- kfree(p);
- } else {
- status = 0; /* At least one adapter will work */
- lastModule = p;
- }
+ if (register_netdev(p) != 0) {
+ kfree(p);
+ } else {
+ status = 0; /* At least one adapter will work */
+ lastModule = p;
}
+ }
- return status;
+ return status;
}
-void cleanup_module(void)
+void
+cleanup_module(void)
{
- while (mdev != NULL) {
- mdev = unlink_modules(mdev);
- }
+ while (mdev != NULL) {
+ mdev = unlink_modules(mdev);
+ }
- return;
+ return;
}
-static struct device *unlink_modules(struct device *p)
+static struct device *
+unlink_modules(struct device *p)
{
- struct device *next = NULL;
-
- if (p->priv) { /* Private areas allocated? */
- struct de4x5_private *lp = (struct de4x5_private *) p->priv;
-
- next = lp->next_module;
- if (lp->cache.buf) { /* MAC buffers allocated? */
- kfree(lp->cache.buf); /* Free the MAC buffers */
- }
- kfree(lp->cache.priv); /* Free the private area */
- release_region(p->base_addr, (lp->bus == PCI ?
- DE4X5_PCI_TOTAL_SIZE :
- DE4X5_EISA_TOTAL_SIZE));
- }
- unregister_netdev(p);
- kfree(p); /* Free the device structure */
-
- return next;
+ struct device *next = NULL;
+
+ if (p->priv) { /* Private areas allocated? */
+ struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+ next = lp->next_module;
+ if (lp->cache.buf) { /* MAC buffers allocated? */
+ kfree(lp->cache.buf); /* Free the MAC buffers */
+ }
+ kfree(lp->cache.priv); /* Free the private area */
+ release_region(p->base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
+ }
+ unregister_netdev(p);
+ kfree(p); /* Free the device structure */
+
+ return next;
}
-static int count_adapters(void)
+static int
+count_adapters(void)
{
- int i, j = 0;
- char name[DE4X5_STRLEN];
- u_char pb, dev_fn, dev_num;
- u_short dev_id, vendor;
- u_int class = DE4X5_CLASS_CODE;
- u_int device;
+ int i, j;
+ char name[DE4X5_STRLEN];
+ u_char pb, dev_fn, dev_num;
+ u_short dev_id, vendor;
+ u_int class = DE4X5_CLASS_CODE;
+ u_int device;
#ifndef __sparc_v9__
- u_int iobase = 0x1000;
+ u_long iobase = 0x1000;
- for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
- if (EISA_signature(name, EISA_ID))
- j++;
- }
+ for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+ if (EISA_signature(name, EISA_ID)) j++;
+ }
#endif
- if (!pcibios_present())
- return j;
-
- for (i=0;
- (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
- i++) {
- dev_num = PCI_SLOT(dev_fn);
- device = 0;
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
- device = dev_id;
- device <<= 8;
- if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)
- j++;
- }
-
- return j;
+ if (!pcibios_present()) return j;
+
+ for (i=0;
+ (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+ i++) {
+ dev_num = PCI_SLOT(dev_fn);
+ device = 0;
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+ device = dev_id;
+ device <<= 8;
+ if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
+ }
+
+ return j;
}
/*
@@ -5599,25 +5767,25 @@ static int count_adapters(void)
__initfunc(static struct device *
insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
{
- struct device *new;
-
- new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
- if (new == NULL) {
- printk("de4x5.c: Device not initialised, insufficient memory\n");
- return NULL;
- } else {
- memset((char *)new, 0, sizeof(struct device)+8);
- new->name = (char *)(new + 1);
- new->base_addr = iobase; /* assign the io address */
- new->init = init; /* initialisation routine */
- }
-
- return new;
+ struct device *new;
+
+ new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
+ if (new == NULL) {
+ printk("de4x5.c: Device not initialised, insufficient memory\n");
+ return NULL;
+ } else {
+ memset((char *)new, 0, sizeof(struct device)+8);
+ new->name = (char *)(new + 1);
+ new->base_addr = iobase; /* assign the io address */
+ new->init = init; /* initialisation routine */
+ }
+
+ return new;
}
-#endif /* MODULE */
-
+#endif /* MODULE */
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
@@ -5625,10 +5793,3 @@ insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
* End:
*/
-
-
-
-
-
-
-
diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h
index c3a98e06a..c0c58ccf4 100644
--- a/drivers/net/de4x5.h
+++ b/drivers/net/de4x5.h
@@ -166,11 +166,7 @@
/*
** PCI Configuration Base I/O Address Register (PCI_CBIO)
*/
-#ifdef __sparc_v9__
-#define CBIO_MASK 0xffffffffffffff80 /* Base I/O Address Mask */
-#else
-#define CBIO_MASK 0xffffff80 /* Base I/O Address Mask */
-#endif
+#define CBIO_MASK -128 /* Base I/O Address Mask */
#define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */
/*
@@ -368,7 +364,7 @@
#define OMR_SIA (OMR_SDP | OMR_TTM)
#define OMR_SYM (OMR_SDP | OMR_SCR | OMR_PCS | OMR_HBD | OMR_PS)
#define OMR_MII_10 (OMR_SDP | OMR_TTM | OMR_PS)
-#define OMR_MII_100 (OMR_SDP | OMR_SCR | OMR_HBD | OMR_PS)
+#define OMR_MII_100 (OMR_SDP | OMR_HBD | OMR_PS)
/*
** DC21040 Interrupt Mask Register (DE4X5_IMR)
@@ -813,16 +809,22 @@
/*
** Media / mode state machine definitions
+** User selectable:
*/
-#define NC 0x0000 /* No Connection */
#define TP 0x0001 /* 10Base-T */
#define TP_NW 0x0002 /* 10Base-T with Nway */
#define BNC 0x0004 /* Thinwire */
#define AUI 0x0008 /* Thickwire */
#define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */
-#define ANS 0x0020 /* Intermediate AutoNegotiation State */
#define _10Mb 0x0040 /* 10Mb/s Ethernet */
#define _100Mb 0x0080 /* 100Mb/s Ethernet */
+#define AUTO 0x4000 /* Auto sense the media or speed */
+
+/*
+** Internal states
+*/
+#define NC 0x0000 /* No Connection */
+#define ANS 0x0020 /* Intermediate AutoNegotiation State */
#define SPD_DET 0x0100 /* Parallel speed detection */
#define INIT 0x0200 /* Initial state */
#define EXT_SIA 0x0400 /* External SIA for motherboard chip */
@@ -834,7 +836,6 @@
#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */
#define MII 0x1000 /* MII on the 21143 */
-#define AUTO 0x4000 /* Auto sense the media or speed */
#define TIMER_CB 0x80000000 /* Timer callback detection */
/*
@@ -907,6 +908,7 @@
#define OPEN 2 /* Running */
/*
+** Various wait times
*/
#define PDET_LINK_WAIT 1200 /* msecs to wait for link detect bits */
#define ANS_FINISH_WAIT 1000 /* msecs to wait for link detect bits */
@@ -936,12 +938,13 @@
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
- outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
+ outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
} else {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
- outl(omr | OMR_TTM, DE4X5_OMR);\
+ outl(omr | OMR_SDP | OMR_TTM, DE4X5_OMR);\
lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
+ gep_wr(lp->cache.gep, dev);\
}\
}
@@ -964,12 +967,13 @@
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
- outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
+ outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
} else {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
omr |= (lp->fdx ? OMR_FDX : 0);\
- outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+ outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
+ gep_wr(lp->cache.gep, dev);\
}\
}
@@ -981,11 +985,12 @@
outl(omr, DE4X5_OMR);\
} else if (lp->useSROM && !lp->useMII) {\
omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
- outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
+ outl(omr, DE4X5_OMR);\
} else {\
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
- outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+ outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS, DE4X5_OMR);\
lp->cache.gep = (GEP_FDXD | GEP_MODE);\
+ gep_wr(lp->cache.gep, dev);\
}\
}
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 2bdddc546..03a3205ed 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -471,7 +471,7 @@ de600_start_xmit(struct sk_buff *skb, struct device *dev)
skb->sk->prot->rspace = de600_rspace; /* Ugh! */
#endif
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index ff2251c5f..80d7a1191 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -100,7 +100,6 @@ static const char *version =
/*
* Enable debugging by "-DDE620_DEBUG=3" when compiling,
- * OR in "./CONFIG"
* OR by enabling the following #define
*
* use 0 for production, 1 for verification, >2 for debug
@@ -580,7 +579,7 @@ de620_start_xmit(struct sk_buff *skb, struct device *dev)
restore_flags(flags); /* interrupts maybe back on */
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 4ecb8a5f3..8c2cbd278 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3209,7 +3209,7 @@ int dfx_xmt_queue_pkt(
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
mark_bh(NET_BH);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return(0); /* return "success" */
}
/*
@@ -3231,7 +3231,7 @@ int dfx_xmt_queue_pkt(
else
{
bp->xmt_discards++; /* bump error counter */
- dev_kfree_skb(skb, FREE_WRITE); /* free sk_buff now */
+ dev_kfree_skb(skb); /* free sk_buff now */
return(0); /* return "success" */
}
}
@@ -3381,7 +3381,7 @@ void dfx_xmt_done(
/* Return skb to operating system */
- dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE);
+ dev_kfree_skb(p_xmt_drv_descr->p_skb);
/* Increment transmit counters */
@@ -3458,7 +3458,7 @@ void dfx_xmt_flush(
/* Return skb to operating system */
- dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE);
+ dev_kfree_skb(p_xmt_drv_descr->p_skb);
/* Increment transmit error counter */
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index fa2435219..56578f58e 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -818,7 +818,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct device *dev)
outw(INEA | TDMD, DEPCA_DATA);
dev->trans_start = jiffies;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
if (TX_BUFFS_AVAIL) {
dev->tbusy = 0;
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index 9ed7b2c8d..e562446e8 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -21,7 +21,7 @@
* When compiled as a loadable module, this driver can operate
* the board as either a 4/6 port switch with a 5th or 7th port
* that is a conventional NIC interface as far as the host is
- * concerned, OR as 4/6 independant NICs. To select multi-NIC
+ * concerned, OR as 4/6 independent NICs. To select multi-NIC
* mode, add "nicmode=1" on the insmod load line for the driver.
*
* This driver uses the "dev" common ethernet device structure
@@ -406,7 +406,7 @@ do_plx_dma(
*/
udelay(1);
- csr = (volatile) priv->vplxdma[PLX_DMA_CSR/4];
+ csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4];
if (csr & PLX_DMA_CSR_0_DONE)
break;
@@ -776,7 +776,7 @@ frame_done:
++privN->stats.tx_packets;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return (0);
no_resources:
@@ -871,7 +871,7 @@ static int dgrs_ioctl(struct device *devN, struct ifreq *ifr, int cmd)
/* Wait for old command to finish */
for (i = 0; i < 1000; ++i)
{
- if ( (volatile) privN->bcomm->bc_filter_cmd <= 0 )
+ if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )
break;
udelay(1);
}
@@ -1250,12 +1250,12 @@ dgrs_found_device(
))
{
DGRS_PRIV *priv;
- int i;
#ifdef MODULE
{
/* Allocate and fill new device structure. */
int dev_size = sizeof(struct device) + sizeof(DGRS_PRIV);
+ int i;
dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
memset(dev, 0, dev_size);
@@ -1358,6 +1358,8 @@ dgrs_found_device(
/*
* Scan for all boards
*/
+static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
+
__initfunc(static int
dgrs_scan(struct device *dev))
{
@@ -1463,8 +1465,6 @@ dgrs_scan(struct device *dev))
*/
if (EISA_bus)
{
- static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
-
for (io = 0x1000; io < 0x9000; io += 0x1000)
{
if (inb(io+ES4H_MANUFmsb) != 0x10
diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c
index c623dbd91..8ceb7a8c7 100644
--- a/drivers/net/dlci.c
+++ b/drivers/net/dlci.c
@@ -28,6 +28,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -230,7 +231,7 @@ static void dlci_receive(struct sk_buff *skb, struct device *dev)
dlp->stats.rx_packets++;
}
else
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
static int dlci_transmit(struct sk_buff *skb, struct device *dev)
@@ -275,7 +276,7 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev)
/* experience suggest a slightly more conservative approach */
if (!ret)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
dev->tbusy = 0;
}
diff --git a/drivers/net/dmascc.c b/drivers/net/dmascc.c
deleted file mode 100644
index 33b473d32..000000000
--- a/drivers/net/dmascc.c
+++ /dev/null
@@ -1,1260 +0,0 @@
-/*
- * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $
- *
- * Driver for high-speed SCC boards (those with DMA support)
- * Copyright (C) 1997 Klaus Kudielka
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include <linux/module.h>
-#include <linux/dmascc.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/netdevice.h>
-#include <linux/sockios.h>
-#include <linux/tqueue.h>
-#include <linux/version.h>
-#include <asm/atomic.h>
-#include <asm/bitops.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <net/ax25.h>
-#include <stdio.h>
-#include "z8530.h"
-
-
-/* Number of buffers per channel */
-
-#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (2 recommended) */
-#define NUM_RX_BUF 2 /* NUM_RX_BUF >= 1 (2 recommended) */
-#define BUF_SIZE 2016
-
-
-/* Cards supported */
-
-#define HW_PI { "Ottawa PI", 0x300, 0x20, 0x10, 8, \
- 0, 8, 1843200, 3686400 }
-#define HW_PI2 { "Ottawa PI2", 0x300, 0x20, 0x10, 8, \
- 0, 8, 3686400, 7372800 }
-#define HW_TWIN { "Gracilis PackeTwin", 0x200, 0x10, 0x10, 32, \
- 0, 4, 6144000, 6144000 }
-
-#define HARDWARE { HW_PI, HW_PI2, HW_TWIN }
-
-#define TYPE_PI 0
-#define TYPE_PI2 1
-#define TYPE_TWIN 2
-#define NUM_TYPES 3
-
-#define MAX_NUM_DEVS 32
-
-
-/* SCC chips supported */
-
-#define Z8530 0
-#define Z85C30 1
-#define Z85230 2
-
-#define CHIPNAMES { "Z8530", "Z85C30", "Z85230" }
-
-
-/* I/O registers */
-
-/* 8530 registers relative to card base */
-#define SCCB_CMD 0x00
-#define SCCB_DATA 0x01
-#define SCCA_CMD 0x02
-#define SCCA_DATA 0x03
-
-/* 8254 registers relative to card base */
-#define TMR_CNT0 0x00
-#define TMR_CNT1 0x01
-#define TMR_CNT2 0x02
-#define TMR_CTRL 0x03
-
-/* Additional PI/PI2 registers relative to card base */
-#define PI_DREQ_MASK 0x04
-
-/* Additional PackeTwin registers relative to card base */
-#define TWIN_INT_REG 0x08
-#define TWIN_CLR_TMR1 0x09
-#define TWIN_CLR_TMR2 0x0a
-#define TWIN_SPARE_1 0x0b
-#define TWIN_DMA_CFG 0x08
-#define TWIN_SERIAL_CFG 0x09
-#define TWIN_DMA_CLR_FF 0x0a
-#define TWIN_SPARE_2 0x0b
-
-
-/* PackeTwin I/O register values */
-
-/* INT_REG */
-#define TWIN_SCC_MSK 0x01
-#define TWIN_TMR1_MSK 0x02
-#define TWIN_TMR2_MSK 0x04
-#define TWIN_INT_MSK 0x07
-
-/* SERIAL_CFG */
-#define TWIN_DTRA_ON 0x01
-#define TWIN_DTRB_ON 0x02
-#define TWIN_EXTCLKA 0x04
-#define TWIN_EXTCLKB 0x08
-#define TWIN_LOOPA_ON 0x10
-#define TWIN_LOOPB_ON 0x20
-#define TWIN_EI 0x80
-
-/* DMA_CFG */
-#define TWIN_DMA_HDX_T1 0x08
-#define TWIN_DMA_HDX_R1 0x0a
-#define TWIN_DMA_HDX_T3 0x14
-#define TWIN_DMA_HDX_R3 0x16
-#define TWIN_DMA_FDX_T3R1 0x1b
-#define TWIN_DMA_FDX_T1R3 0x1d
-
-
-/* Status values */
-
-/* tx_state */
-#define TX_IDLE 0
-#define TX_OFF 1
-#define TX_TXDELAY 2
-#define TX_ACTIVE 3
-#define TX_SQDELAY 4
-
-
-/* Data types */
-
-struct scc_hardware {
- char *name;
- int io_region;
- int io_delta;
- int io_size;
- int num_devs;
- int scc_offset;
- int tmr_offset;
- int tmr_hz;
- int pclk_hz;
-};
-
-struct scc_priv {
- char name[10];
- struct enet_statistics stats;
- struct scc_info *info;
- int channel;
- int cmd, data, tmr;
- struct scc_param param;
- char rx_buf[NUM_RX_BUF][BUF_SIZE];
- int rx_len[NUM_RX_BUF];
- int rx_ptr;
- struct tq_struct rx_task;
- int rx_head, rx_tail, rx_count;
- int rx_over;
- char tx_buf[NUM_TX_BUF][BUF_SIZE];
- int tx_len[NUM_TX_BUF];
- int tx_ptr;
- int tx_head, tx_tail, tx_count;
- int tx_sem, tx_state;
- unsigned long tx_start;
- int status;
-};
-
-struct scc_info {
- int type;
- int chip;
- int open;
- int scc_base;
- int tmr_base;
- int twin_serial_cfg;
- struct device dev[2];
- struct scc_priv priv[2];
- struct scc_info *next;
-};
-
-
-/* Function declarations */
-
-int dmascc_init(void) __init;
-static int setup_adapter(int io, int h, int n) __init;
-
-static inline void write_scc(int ctl, int reg, int val);
-static inline int read_scc(int ctl, int reg);
-static int scc_open(struct device *dev);
-static int scc_close(struct device *dev);
-static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int scc_send_packet(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics *scc_get_stats(struct device *dev);
-static int scc_set_mac_address(struct device *dev, void *sa);
-static void scc_isr(int irq, void *dev_id, struct pt_regs * regs);
-static inline void z8530_isr(struct scc_info *info);
-static void rx_isr(struct device *dev);
-static void special_condition(struct device *dev, int rc);
-static void rx_bh(void *arg);
-static void tx_isr(struct device *dev);
-static void es_isr(struct device *dev);
-static void tm_isr(struct device *dev);
-static inline void delay(struct device *dev, int t);
-static inline unsigned char random(void);
-
-
-/* Initialization variables */
-
-static int io[MAX_NUM_DEVS] __initdata = { 0, };
-/* Beware! hw[] is also used in cleanup_module(). If __initdata also applies
- to modules, we may not declare hw[] as __initdata */
-static struct scc_hardware hw[NUM_TYPES] __initdata = HARDWARE;
-static char ax25_broadcast[7] __initdata =
- { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 };
-static char ax25_test[7] __initdata =
- { 'L'<<1, 'I'<<1, 'N'<<1, 'U'<<1, 'X'<<1, ' '<<1, '1'<<1 };
-
-
-/* Global variables */
-
-static struct scc_info *first = NULL;
-static unsigned long rand;
-
-
-
-/* Module functions */
-
-#ifdef MODULE
-
-
-MODULE_AUTHOR("Klaus Kudielka <oe1kib@oe1xtu.ampr.org>");
-MODULE_DESCRIPTION("Driver for high-speed SCC boards");
-MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
-
-
-int init_module(void)
-{
- return dmascc_init();
-}
-
-
-void cleanup_module(void)
-{
- int i;
- struct scc_info *info;
-
- while (first) {
- info = first;
-
- /* Unregister devices */
- for (i = 0; i < 2; i++) {
- if (info->dev[i].name)
- unregister_netdev(&info->dev[i]);
- }
-
- /* Reset board */
- if (info->type == TYPE_TWIN)
- outb_p(0, info->dev[0].base_addr + TWIN_SERIAL_CFG);
- write_scc(info->priv[0].cmd, R9, FHWRES);
- release_region(info->dev[0].base_addr,
- hw[info->type].io_size);
-
- /* Free memory */
- first = info->next;
- kfree_s(info, sizeof(struct scc_info));
- }
-}
-
-
-#else
-
-
-__initfunc(void dmascc_setup(char *str, int *ints))
-{
- int i;
-
- for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++)
- io[i] = ints[i+1];
-}
-
-
-#endif
-
-
-/* Initialization functions */
-
-__initfunc(int dmascc_init(void))
-{
- int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status;
- unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS];
-
- /* Initialize random number generator */
- rand = jiffies;
-
- /* Cards found = 0 */
- n = 0;
-
- /* Run autodetection for each card type */
- for (h = 0; h < NUM_TYPES; h++) {
-
- if (io[0]) {
- /* User-specified I/O address regions */
- for (i = 0; i < hw[h].num_devs; i++) base[i] = 0;
- for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) {
- j = (io[i] - hw[h].io_region) / hw[h].io_delta;
- if (j >= 0 &&
- j < hw[h].num_devs &&
- hw[h].io_region + j * hw[h].io_delta == io[i])
- base[j] = io[i];
- }
- } else {
- /* Default I/O address regions */
- for (i = 0; i < hw[h].num_devs; i++)
- base[i] = hw[h].io_region + i * hw[h].io_delta;
- }
-
- /* Check valid I/O address regions */
- for (i = 0; i < hw[h].num_devs; i++)
- if (base[i] && check_region(base[i], hw[h].io_size))
- base[i] = 0;
-
- /* Start timers */
- for (i = 0; i < hw[h].num_devs; i++)
- if (base[i]) {
- tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL;
- t0 = base[i] + hw[h].tmr_offset + TMR_CNT0;
- t1 = base[i] + hw[h].tmr_offset + TMR_CNT1;
- /* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
- outb_p(0x36, tcmd);
- outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0);
- outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0);
- /* Timer 1: LSB+MSB, Mode 0, HZ/10 */
- outb_p(0x70, tcmd);
- outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1);
- outb_p((TMR_0_HZ/HZ*10) >> 8, t1);
- /* Timer 2: LSB+MSB, Mode 0 */
- outb_p(0xb0, tcmd);
- }
-
- /* Initialize start values in case we miss the null count bit */
- time = jiffies;
- for (i = 0; i < hw[h].num_devs; i++) start[i] = time;
-
- /* Timing loop */
- while (jiffies - time < 12) {
- for (i = 0; i < hw[h].num_devs; i++)
- if (base[i]) {
- /* Read back Timer 1: Status */
- outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL);
- status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1);
- if ((status & 0x3F) != 0x30) base[i] = 0;
- if (status & 0x40) start[i] = jiffies;
- if (~status & 0x80) stop[i] = jiffies;
- }
- }
-
- /* Evaluate measurements */
- for (i = 0; i < hw[h].num_devs; i++)
- if (base[i]) {
- time = stop[i] - start[i];
- if (time < 9 || time > 11)
- /* The time expired doesn't match */
- base[i] = 0;
- else {
- /* Ok, we have found an adapter */
- if (setup_adapter(base[i], h, n) == 0)
- n++;
- }
- }
-
- } /* NUM_TYPES */
-
- /* If any adapter was successfully initialized, return ok */
- if (n) return 0;
-
- /* If no adapter found, return error */
- printk("dmascc: no adapters found\n");
- return -EIO;
-}
-
-
-__initfunc(int setup_adapter(int io, int h, int n))
-{
- int i, irq, chip;
- struct scc_info *info;
- struct device *dev;
- struct scc_priv *priv;
- unsigned long time;
- unsigned int irqs;
- int tmr = io + hw[h].tmr_offset;
- int scc = io + hw[h].scc_offset;
- int cmd = scc + SCCA_CMD;
- char *chipnames[] = CHIPNAMES;
-
- /* Reset 8530 */
- write_scc(cmd, R9, FHWRES | MIE | NV);
-
- /* Determine type of chip */
- write_scc(cmd, R15, 1);
- if (!read_scc(cmd, R15)) {
- /* WR7' not present. This is an ordinary Z8530 SCC. */
- chip = Z8530;
- } else {
- /* Put one character in TX FIFO */
- write_scc(cmd, R8, 0);
- if (read_scc(cmd, R0) & Tx_BUF_EMP) {
- /* TX FIFO not full. This is a Z85230 ESCC with a 4-byte FIFO. */
- chip = Z85230;
- } else {
- /* TX FIFO full. This is a Z85C30 SCC with a 1-byte FIFO. */
- chip = Z85C30;
- }
- }
- write_scc(cmd, R15, 0);
-
- /* Start IRQ auto-detection */
- sti();
- irqs = probe_irq_on();
-
- /* Enable interrupts */
- switch (h) {
- case TYPE_PI:
- case TYPE_PI2:
- outb_p(0, io + PI_DREQ_MASK);
- write_scc(cmd, R15, CTSIE);
- write_scc(cmd, R0, RES_EXT_INT);
- write_scc(cmd, R1, EXT_INT_ENAB);
- break;
- case TYPE_TWIN:
- outb_p(0, io + TWIN_DMA_CFG);
- inb_p(io + TWIN_CLR_TMR1);
- inb_p(io + TWIN_CLR_TMR2);
- outb_p(TWIN_EI, io + TWIN_SERIAL_CFG);
- break;
- }
-
- /* Start timer */
- outb_p(1, tmr + TMR_CNT1);
- outb_p(0, tmr + TMR_CNT1);
- /* Wait and detect IRQ */
- time = jiffies; while (jiffies - time < 2 + HZ / TMR_0_HZ);
- irq = probe_irq_off(irqs);
-
- /* Clear pending interrupt, disable interrupts */
- switch (h) {
- case TYPE_PI:
- case TYPE_PI2:
- write_scc(cmd, R1, 0);
- write_scc(cmd, R15, 0);
- write_scc(cmd, R0, RES_EXT_INT);
- break;
- case TYPE_TWIN:
- inb_p(io + TWIN_CLR_TMR1);
- outb_p(0, io + TWIN_SERIAL_CFG);
- break;
- }
-
- if (irq <= 0) {
- printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n",
- hw[h].name, io, irq);
- return -1;
- }
-
- /* Allocate memory */
- info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
- if (!info) {
- printk("dmascc: could not allocate memory for %s at %#3x\n",
- hw[h].name, io);
- return -1;
- }
-
- /* Set up data structures */
- memset(info, 0, sizeof(struct scc_info));
- info->type = h;
- info->chip = chip;
- info->scc_base = io + hw[h].scc_offset;
- info->tmr_base = io + hw[h].tmr_offset;
- info->twin_serial_cfg = 0;
- for (i = 0; i < 2; i++) {
- dev = &info->dev[i];
- priv = &info->priv[i];
- sprintf(priv->name, "dmascc%i", 2*n+i);
- priv->info = info;
- priv->channel = i;
- priv->cmd = info->scc_base + (i ? SCCB_CMD : SCCA_CMD);
- priv->data = info->scc_base + (i ? SCCB_DATA : SCCA_DATA);
- priv->tmr = info->tmr_base + (i ? TMR_CNT2 : TMR_CNT1);
- priv->param.pclk_hz = hw[h].pclk_hz;
- priv->param.brg_tc = -1;
- priv->param.clocks = TCTRxCP | RCRTxCP;
- priv->param.txdelay = TMR_0_HZ * 10 / 1000;
- priv->param.txtime = HZ * 3;
- priv->param.sqdelay = TMR_0_HZ * 1 / 1000;
- priv->param.slottime = TMR_0_HZ * 10 / 1000;
- priv->param.waittime = TMR_0_HZ * 100 / 1000;
- priv->param.persist = 32;
- priv->rx_task.routine = rx_bh;
- priv->rx_task.data = dev;
- dev->priv = priv;
- dev->name = priv->name;
- dev->base_addr = io;
- dev->irq = irq;
- dev->open = scc_open;
- dev->stop = scc_close;
- dev->do_ioctl = scc_ioctl;
- dev->hard_start_xmit = scc_send_packet;
- dev->get_stats = scc_get_stats;
- dev->hard_header = ax25_encapsulate;
- dev->rebuild_header = ax25_rebuild_header;
- dev->set_mac_address = scc_set_mac_address;
- dev->type = ARPHRD_AX25;
- dev->hard_header_len = 73;
- dev->mtu = 1500;
- dev->addr_len = 7;
- dev->tx_queue_len = 64;
- memcpy(dev->broadcast, ax25_broadcast, 7);
- memcpy(dev->dev_addr, ax25_test, 7);
- dev->flags = 0;
- dev_init_buffers(dev);
- if (register_netdev(dev)) {
- printk("dmascc: could not register %s\n", dev->name);
- dev->name = NULL;
- }
- }
-
- request_region(io, hw[h].io_size, "dmascc");
-
- info->next = first;
- first = info;
- printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[h].name,
- chipnames[chip], io, irq);
- return 0;
-}
-
-
-/* Driver functions */
-
-static inline void write_scc(int ctl, int reg, int val)
-{
- outb_p(reg, ctl);
- outb_p(val, ctl);
-}
-
-
-static inline int read_scc(int ctl, int reg)
-{
- outb_p(reg, ctl);
- return inb_p(ctl);
-}
-
-
-static int scc_open(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int io = dev->base_addr;
- int cmd = priv->cmd;
-
- /* Request IRQ if not already used by other channel */
- if (!info->open) {
- if (request_irq(dev->irq, scc_isr, SA_INTERRUPT, "dmascc", info))
- return -EAGAIN;
- }
-
- /* Request DMA if required */
- if (dev->dma && request_dma(dev->dma, "dmascc")) {
- if (!info->open) free_irq(dev->irq, info);
- return -EAGAIN;
- }
-
- /* Initialize local variables */
- dev->tbusy = 0;
- priv->rx_ptr = 0;
- priv->rx_over = 0;
- priv->rx_head = priv->rx_tail = priv->rx_count = 0;
- priv->tx_state = TX_IDLE;
- priv->tx_head = priv->tx_tail = priv->tx_count = 0;
- priv->tx_ptr = 0;
- priv->tx_sem = 0;
-
- /* Reset channel */
- write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
- /* X1 clock, SDLC mode */
- write_scc(cmd, R4, SDLC | X1CLK);
- /* DMA */
- write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
- /* 8 bit RX char, RX disable */
- write_scc(cmd, R3, Rx8);
- /* 8 bit TX char, TX disable */
- write_scc(cmd, R5, Tx8);
- /* SDLC address field */
- write_scc(cmd, R6, 0);
- /* SDLC flag */
- write_scc(cmd, R7, FLAG);
- switch (info->chip) {
- case Z85C30:
- /* Select WR7' */
- write_scc(cmd, R15, 1);
- /* Auto EOM reset */
- write_scc(cmd, R7, 0x02);
- write_scc(cmd, R15, 0);
- break;
- case Z85230:
- /* Select WR7' */
- write_scc(cmd, R15, 1);
- /* RX FIFO half full (interrupt only), Auto EOM reset,
- TX FIFO empty (DMA only) */
- write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a);
- write_scc(cmd, R15, 0);
- break;
- }
- /* Preset CRC, NRZ(I) encoding */
- write_scc(cmd, R10, CRCPS | (priv->param.nrzi ? NRZI : NRZ));
-
- /* Configure baud rate generator */
- if (priv->param.brg_tc >= 0) {
- /* Program BR generator */
- write_scc(cmd, R12, priv->param.brg_tc & 0xFF);
- write_scc(cmd, R13, (priv->param.brg_tc>>8) & 0xFF);
- /* BRG source = SYS CLK; enable BRG; DTR REQ function (required by
- PackeTwin, not connected on the PI2); set DPLL source to BRG */
- write_scc(cmd, R14, SSBR | DTRREQ | BRSRC | BRENABL);
- /* Enable DPLL */
- write_scc(cmd, R14, SEARCH | DTRREQ | BRSRC | BRENABL);
- } else {
- /* Disable BR generator */
- write_scc(cmd, R14, DTRREQ | BRSRC);
- }
-
- /* Configure clocks */
- if (info->type == TYPE_TWIN) {
- /* Disable external TX clock receiver */
- outb_p((info->twin_serial_cfg &=
- ~(priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
- io + TWIN_SERIAL_CFG);
- }
- write_scc(cmd, R11, priv->param.clocks);
- if ((info->type == TYPE_TWIN) && !(priv->param.clocks & TRxCOI)) {
- /* Enable external TX clock receiver */
- outb_p((info->twin_serial_cfg |=
- (priv->channel ? TWIN_EXTCLKB : TWIN_EXTCLKA)),
- io + TWIN_SERIAL_CFG);
- }
-
- /* Configure PackeTwin */
- if (info->type == TYPE_TWIN) {
- /* Assert DTR, enable interrupts */
- outb_p((info->twin_serial_cfg |= TWIN_EI |
- (priv->channel ? TWIN_DTRB_ON : TWIN_DTRA_ON)),
- io + TWIN_SERIAL_CFG);
- }
-
- /* Read current status */
- priv->status = read_scc(cmd, R0);
- /* Enable SYNC, DCD, and CTS interrupts */
- write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
-
- /* Configure PI2 DMA */
- if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
-
- dev->start = 1;
- info->open++;
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-
-
-static int scc_close(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int io = dev->base_addr;
- int cmd = priv->cmd;
-
- dev->start = 0;
- info->open--;
- MOD_DEC_USE_COUNT;
-
- if (info->type == TYPE_TWIN)
- /* Drop DTR */
- outb_p((info->twin_serial_cfg &=
- (priv->channel ? ~TWIN_DTRB_ON : ~TWIN_DTRA_ON)),
- io + TWIN_SERIAL_CFG);
-
- /* Reset channel, free DMA */
- write_scc(cmd, R9, (priv->channel ? CHRB : CHRA) | MIE | NV);
- if (dev->dma) {
- if (info->type == TYPE_TWIN) outb_p(0, io + TWIN_DMA_CFG);
- free_dma(dev->dma);
- }
-
- if (!info->open) {
- if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
- free_irq(dev->irq, info);
- }
- return 0;
-}
-
-
-static int scc_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
-{
- int rc;
- struct scc_priv *priv = dev->priv;
-
- switch (cmd) {
- case SIOCGSCCPARAM:
- rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
- return 0;
- case SIOCSSCCPARAM:
- if (!suser()) return -EPERM;
- rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- if (dev->start) return -EAGAIN;
- copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
- dev->dma = priv->param.dma;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int scc_send_packet(struct sk_buff *skb, struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int cmd = priv->cmd;
- unsigned long flags;
- int i;
-
- /* Block a timer-based transmit from overlapping */
- if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
- atomic_inc((void *) &priv->stats.tx_dropped);
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
-
- /* Return with an error if we cannot accept more data */
- if (dev->tbusy) {
- priv->tx_sem = 0;
- return -1;
- }
-
- /* Transfer data to DMA buffer */
- i = priv->tx_head;
- memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
- priv->tx_len[i] = skb->len-1;
-
- save_flags(flags);
- cli();
-
- /* Set the busy flag if we just filled up the last buffer */
- priv->tx_head = (i + 1) % NUM_TX_BUF;
- priv->tx_count++;
- if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
-
- /* Set new TX state */
- if (priv->tx_state == TX_IDLE) {
- /* Assert RTS, start timer */
- priv->tx_state = TX_TXDELAY;
- if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
- write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
- if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
- priv->tx_start = jiffies;
- delay(dev, priv->param.txdelay);
- }
-
- restore_flags(flags);
-
- dev_kfree_skb(skb, FREE_WRITE);
-
- priv->tx_sem = 0;
- return 0;
-}
-
-
-static struct enet_statistics *scc_get_stats(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
-
- return &priv->stats;
-}
-
-
-static int scc_set_mac_address(struct device *dev, void *sa)
-{
- memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len);
- return 0;
-}
-
-
-static void scc_isr(int irq, void *dev_id, struct pt_regs * regs)
-{
- struct scc_info *info = dev_id;
- int is, io = info->dev[0].base_addr;
-
- /* We're a fast IRQ handler and are called with interrupts disabled */
-
- /* IRQ sharing doesn't make sense due to ISA's edge-triggered
- interrupts, hence it is safe to return if we have found and
- processed a single device. */
-
- /* Interrupt processing: We loop until we know that the IRQ line is
- low. If another positive edge occurs afterwards during the ISR,
- another interrupt will be triggered by the interrupt controller
- as soon as the IRQ level is enabled again (see asm/irq.h). */
-
- switch (info->type) {
- case TYPE_PI:
- case TYPE_PI2:
- outb_p(0, io + PI_DREQ_MASK);
- z8530_isr(info);
- outb_p(1, io + PI_DREQ_MASK);
- return;
- case TYPE_TWIN:
- while ((is = ~inb_p(io + TWIN_INT_REG)) &
- TWIN_INT_MSK) {
- if (is & TWIN_SCC_MSK) {
- z8530_isr(info);
- } else if (is & TWIN_TMR1_MSK) {
- inb_p(io + TWIN_CLR_TMR1);
- tm_isr(&info->dev[0]);
- } else {
- inb_p(io + TWIN_CLR_TMR2);
- tm_isr(&info->dev[1]);
- }
- }
- /* No interrupts pending from the PackeTwin */
- return;
- }
-}
-
-
-static inline void z8530_isr(struct scc_info *info)
-{
- int is, a_cmd;
-
- a_cmd = info->scc_base + SCCA_CMD;
-
- while ((is = read_scc(a_cmd, R3))) {
- if (is & CHARxIP) {
- rx_isr(&info->dev[0]);
- } else if (is & CHATxIP) {
- tx_isr(&info->dev[0]);
- } else if (is & CHAEXT) {
- es_isr(&info->dev[0]);
- } else if (is & CHBRxIP) {
- rx_isr(&info->dev[1]);
- } else if (is & CHBTxIP) {
- tx_isr(&info->dev[1]);
- } else {
- es_isr(&info->dev[1]);
- }
- }
- /* Ok, no interrupts pending from this 8530. The INT line should
- be inactive now. */
-}
-
-
-static void rx_isr(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- int cmd = priv->cmd;
-
- if (dev->dma) {
- /* Check special condition and perform error reset. See 2.4.7.5. */
- special_condition(dev, read_scc(cmd, R1));
- write_scc(cmd, R0, ERR_RES);
- } else {
- /* Check special condition for each character. Error reset not necessary.
- Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */
- int rc;
- while (read_scc(cmd, R0) & Rx_CH_AV) {
- rc = read_scc(cmd, R1);
- if (priv->rx_ptr < BUF_SIZE)
- priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc(cmd, R8);
- else {
- priv->rx_over = 2;
- read_scc(cmd, R8);
- }
- special_condition(dev, rc);
- }
- }
-}
-
-
-static void special_condition(struct device *dev, int rc)
-{
- struct scc_priv *priv = dev->priv;
- int cb, cmd = priv->cmd;
-
- /* See Figure 2-15. Only overrun and EOF need to be checked. */
-
- if (rc & Rx_OVR) {
- /* Receiver overrun */
- priv->rx_over = 1;
- if (!dev->dma) write_scc(cmd, R0, ERR_RES);
- } else if (rc & END_FR) {
- /* End of frame. Get byte count */
- if (dev->dma) {
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- cb = BUF_SIZE - get_dma_residue(dev->dma) - 2;
- } else {
- cb = priv->rx_ptr - 2;
- }
- if (priv->rx_over) {
- /* We had an overrun */
- priv->stats.rx_errors++;
- if (priv->rx_over == 2) priv->stats.rx_length_errors++;
- else priv->stats.rx_fifo_errors++;
- priv->rx_over = 0;
- } else if (rc & CRC_ERR) {
- /* Count invalid CRC only if packet length >= minimum */
- if (cb >= 8) {
- priv->stats.rx_errors++;
- priv->stats.rx_crc_errors++;
- }
- } else {
- if (cb >= 8) {
- /* Put good frame in FIFO */
- priv->rx_len[priv->rx_head] = cb;
- priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF;
- priv->rx_count++;
- if (priv->rx_count == NUM_RX_BUF) {
- /* Disable receiver if FIFO full */
- write_scc(cmd, R3, Rx8);
- priv->stats.rx_errors++;
- priv->stats.rx_over_errors++;
- }
- /* Mark bottom half handler */
- queue_task(&priv->rx_task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
- }
- /* Get ready for new frame */
- if (dev->dma) {
- set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
- set_dma_count(dev->dma, BUF_SIZE);
- enable_dma(dev->dma);
- } else {
- priv->rx_ptr = 0;
- }
- }
-}
-
-
-static void rx_bh(void *arg)
-{
- struct device *dev = arg;
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int cmd = priv->cmd;
- int i = priv->rx_tail;
- int cb;
- unsigned long flags;
- struct sk_buff *skb;
- unsigned char *data;
-
- save_flags(flags);
- cli();
-
- while (priv->rx_count) {
- restore_flags(flags);
- cb = priv->rx_len[i];
- /* Allocate buffer */
- skb = dev_alloc_skb(cb+1);
- if (skb == NULL) {
- /* Drop packet */
- priv->stats.rx_dropped++;
- } else {
- /* Fill buffer */
- data = skb_put(skb, cb+1);
- data[0] = 0;
- memcpy(&data[1], priv->rx_buf[i], cb);
- skb->dev = dev;
- skb->protocol = ntohs(ETH_P_AX25);
- skb->mac.raw = skb->data;
- netif_rx(skb);
- priv->stats.rx_packets++;
- }
- save_flags(flags);
- cli();
- /* Enable receiver if RX buffers have been unavailable */
- if ((priv->rx_count == NUM_RX_BUF) && (priv->status & DCD)) {
- if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);
- write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
- if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);
- }
- /* Move tail */
- priv->rx_tail = i = (i + 1) % NUM_RX_BUF;
- priv->rx_count--;
- }
-
- restore_flags(flags);
-}
-
-
-static void tx_isr(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- int cmd = priv->cmd;
- int i = priv->tx_tail, p = priv->tx_ptr;
-
- /* Suspend TX interrupts if we don't want to send anything.
- See Figure 2-22. */
- if (p == priv->tx_len[i]) {
- write_scc(cmd, R0, RES_Tx_P);
- return;
- }
-
- /* Write characters */
- while ((read_scc(cmd, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {
- write_scc(cmd, R8, priv->tx_buf[i][p++]);
- }
- priv->tx_ptr = p;
-
-}
-
-
-static void es_isr(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int i, cmd = priv->cmd;
- int st, dst, res;
-
- /* Read status and reset interrupt bit */
- st = read_scc(cmd, R0);
- write_scc(cmd, R0, RES_EXT_INT);
- dst = priv->status ^ st;
- priv->status = st;
-
- /* Since the EOM latch is reset automatically, we assume that
- it has been zero if and only if we are in the TX_ACTIVE state.
- Otherwise we follow 2.4.9.6. */
-
- /* Transmit underrun */
- if ((priv->tx_state == TX_ACTIVE) && (st & TxEOM)) {
- /* Get remaining bytes */
- i = priv->tx_tail;
- if (dev->dma) {
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- res = get_dma_residue(dev->dma);
- } else {
- res = priv->tx_len[i] - priv->tx_ptr;
- if (res) write_scc(cmd, R0, RES_Tx_P);
- priv->tx_ptr = 0;
- }
- /* Remove frame from FIFO */
- priv->tx_tail = (i + 1) % NUM_TX_BUF;
- priv->tx_count--;
- dev->tbusy = 0;
- /* Check if another frame is available and we are allowed to transmit */
- if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
- if (dev->dma) {
- set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
- set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
- enable_dma(dev->dma);
- } else {
- /* If we have an ESCC, we are allowed to write data bytes
- immediately. Otherwise we have to wait for the next
- TX interrupt. See Figure 2-22. */
- if (info->chip == Z85230) {
- tx_isr(dev);
- }
- }
- } else {
- /* No frame available. Disable interrupts. */
- priv->tx_state = TX_SQDELAY;
- delay(dev, priv->param.sqdelay);
- write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);
- write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);
- }
- /* Update packet statistics */
- if (res) {
- priv->stats.tx_errors++;
- priv->stats.tx_fifo_errors++;
- } else {
- priv->stats.tx_packets++;
- }
- /* Inform upper layers */
- mark_bh(NET_BH);
- }
-
- /* DCD transition */
- if ((priv->tx_state < TX_TXDELAY) && (dst & DCD)) {
- /* Transmitter state change */
- priv->tx_state = TX_OFF;
- /* Enable or disable receiver */
- if (st & DCD) {
- if (dev->dma) {
- /* Program DMA controller */
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_READ);
- set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
- set_dma_count(dev->dma, BUF_SIZE);
- enable_dma(dev->dma);
- /* Configure PackeTwin DMA */
- if (info->type == TYPE_TWIN) {
- outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
- dev->base_addr + TWIN_DMA_CFG);
- }
- /* Sp. cond. intr. only, ext int enable */
- write_scc(cmd, R1, EXT_INT_ENAB | INT_ERR_Rx |
- WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
- } else {
- /* Intr. on all Rx characters and Sp. cond., ext int enable */
- write_scc(cmd, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
- WT_FN_RDYFN);
- }
- if (priv->rx_count < NUM_RX_BUF) {
- /* Enable receiver */
- write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);
- }
- } else {
- /* Disable DMA */
- if (dev->dma) disable_dma(dev->dma);
- /* Disable receiver */
- write_scc(cmd, R3, Rx8);
- /* DMA disable, RX int disable, Ext int enable */
- write_scc(cmd, R1, EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
- /* Transmitter state change */
- if (random() > priv->param.persist)
- delay(dev, priv->param.slottime);
- else {
- if (priv->tx_count) {
- priv->tx_state = TX_TXDELAY;
- write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
- priv->tx_start = jiffies;
- delay(dev, priv->param.txdelay);
- } else {
- priv->tx_state = TX_IDLE;
- }
- }
- }
- }
-
- /* CTS transition */
- if ((info->type <= TYPE_PI2) && (dst & CTS) && (~st & CTS)) {
- /* Timer has expired */
- tm_isr(dev);
- }
-
- /* /SYNC/HUNT transition */
- if ((dst & SYNC_HUNT) && (~st & SYNC_HUNT)) {
- /* Reset current frame and clear RX FIFO */
- while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8);
- priv->rx_over = 0;
- if (dev->dma) {
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);
- set_dma_count(dev->dma, BUF_SIZE);
- enable_dma(dev->dma);
- } else {
- priv->rx_ptr = 0;
- }
- }
-}
-
-
-static void tm_isr(struct device *dev)
-{
- struct scc_priv *priv = dev->priv;
- struct scc_info *info = priv->info;
- int cmd = priv->cmd;
-
- switch (priv->tx_state) {
- case TX_OFF:
- if (~priv->status & DCD) {
- if (random() > priv->param.persist) delay(dev, priv->param.slottime);
- else {
- if (priv->tx_count) {
- priv->tx_state = TX_TXDELAY;
- write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);
- priv->tx_start = jiffies;
- delay(dev, priv->param.txdelay);
- } else {
- priv->tx_state = TX_IDLE;
- }
- }
- }
- break;
- case TX_TXDELAY:
- priv->tx_state = TX_ACTIVE;
- if (dev->dma) {
- /* Program DMA controller */
- disable_dma(dev->dma);
- clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, DMA_MODE_WRITE);
- set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);
- set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);
- enable_dma(dev->dma);
- /* Configure PackeTwin DMA */
- if (info->type == TYPE_TWIN) {
- outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
- dev->base_addr + TWIN_DMA_CFG);
- }
- /* Enable interrupts and DMA. On the PackeTwin, the DTR//REQ pin
- is used for TX DMA requests, but we enable the WAIT/DMA request
- pin, anyway */
- write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
- write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
- } else {
- write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);
- write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
- tx_isr(dev);
- }
- if (info->chip == Z8530) write_scc(cmd, R0, RES_EOM_L);
- break;
- case TX_SQDELAY:
- /* Disable transmitter */
- write_scc(cmd, R5, TxCRC_ENAB | Tx8);
- /* Transmitter state change: Switch to TX_OFF and wait at least
- 1 slottime. */
- priv->tx_state = TX_OFF;
- if (~priv->status & DCD) delay(dev, priv->param.waittime);
- }
-}
-
-
-static inline void delay(struct device *dev, int t)
-{
- struct scc_priv *priv = dev->priv;
- int tmr = priv->tmr;
-
- outb_p(t & 0xFF, tmr);
- outb_p((t >> 8) & 0xFF, tmr);
-}
-
-
-static inline unsigned char random(void)
-{
- /* See "Numerical Recipes in C", second edition, p. 284 */
- rand = rand * 1664525L + 1013904223L;
- return (unsigned char) (rand >> 24);
-}
-
-
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index d5ba0e429..4367f476f 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -30,9 +30,9 @@
/* To have statistics (just packets sent) define this */
-#include <linux/module.h>
-
+#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
@@ -73,6 +73,13 @@ static void set_multicast_list(struct device *dev)
{
}
+#ifdef CONFIG_NET_FASTROUTE
+static int dummy_accept_fastpath(struct device *dev, struct dst_entry *dst)
+{
+ return -1;
+}
+#endif
+
__initfunc(int dummy_init(struct device *dev))
{
/* Initialize the device structure. */
@@ -92,7 +99,10 @@ __initfunc(int dummy_init(struct device *dev))
ether_setup(dev);
dev->tx_queue_len = 0;
dev->flags |= IFF_NOARP;
- dev->flags &= ~IFF_BROADCAST;
+ dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
+#ifdef CONFIG_NET_FASTROUTE
+ dev->accept_fastpath = dummy_accept_fastpath;
+#endif
return 0;
}
@@ -100,7 +110,7 @@ __initfunc(int dummy_init(struct device *dev))
static int dummy_xmit(struct sk_buff *skb, struct device *dev)
{
struct net_device_stats *stats;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
stats = (struct net_device_stats *)dev->priv;
stats->tx_packets++;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 62558807a..e4f0393d0 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -103,7 +103,7 @@ static void e21_reset_8390(struct device *dev);
static void e21_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void e21_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
@@ -441,10 +441,10 @@ cleanup_module(void)
struct device *dev = &dev_e21[this_dev];
if (dev->priv != NULL) {
/* NB: e21_close() handles free_irq */
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, E21_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 1b1ac98d2..54a7ac5ef 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -720,7 +720,7 @@ eepro_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
/* lp->stats.tx_aborted_errors++; */
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 4f1243b4e..9a33ea3a4 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -36,9 +36,8 @@ static int rxdmacount = 0;
static int rx_copybreak = 200;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 200;
-#include <linux/config.h>
#ifdef MODULE
#ifdef MODVERSIONS
#include <linux/modversions.h>
@@ -1186,7 +1185,7 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Free the original skb. */
if (sp->tx_skbuff[entry]) {
sp->stats.tx_packets++; /* Count only user packets. */
- dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE);
+ dev_kfree_skb(sp->tx_skbuff[entry]);
sp->tx_skbuff[entry] = 0;
}
dirty_tx++;
@@ -1426,7 +1425,7 @@ speedo_close(struct device *dev)
sp->rx_skbuff[i] = 0;
/* Clear the Rx descriptors. */
if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1434,7 +1433,7 @@ speedo_close(struct device *dev)
sp->tx_skbuff[i] = 0;
/* Clear the Tx descriptors. */
if (skb)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
if (sp->mc_setup_frm) {
kfree(sp->mc_setup_frm);
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index c78e798dd..d1886f7c3 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -537,7 +537,7 @@ static int eexp_xmit(struct sk_buff *buf, struct device *dev)
eexp_hw_tx_pio(dev,data,length);
}
- dev_kfree_skb(buf, FREE_WRITE);
+ dev_kfree_skb(buf);
outb(SIRQ_en|irqrmap[dev->irq],dev->base_addr+SET_IRQ);
return 0;
}
@@ -1558,10 +1558,10 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
struct device *dev = &dev_eexp[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, EEXP_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 685b1f850..f654b2cdd 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -387,7 +387,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct device *dev)
*/
eql->stats->tx_dropped++;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
return 0;
}
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index b7e0cae06..b4e3d1d79 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -71,7 +71,7 @@ static void es_reset_8390(struct device *dev);
static void es_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page);
static void es_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset);
-static void es_block_output(struct device *dev, int count, const unsigned char *buf, const start_page);
+static void es_block_output(struct device *dev, int count, const unsigned char *buf, int start_page);
#define ES_START_PG 0x00 /* First page of TX buffer */
#define ES_STOP_PG 0x40 /* Last page +1 of RX ring */
@@ -430,11 +430,11 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
struct device *dev = &dev_es3210[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(dev->base_addr, ES_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index dbf0f3beb..e68c0d64d 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -97,6 +97,7 @@ static char *version =
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
+#include <asm/delay.h>
/* Few macros */
#define BIT(a) ( (1 << (a)) )
@@ -724,7 +725,7 @@ static int eth16i_check_signature(short ioaddr)
creg[0] &= 0x0F; /* Mask collision cnr */
creg[2] &= 0x7F; /* Mask DCLEN bit */
-#ifdef 0
+#if 0
/*
This was removed because the card was sometimes left to state
from which it couldn't be find anymore. If there is need
@@ -976,7 +977,7 @@ static int eth16i_tx(struct sk_buff *skb, struct device *dev)
/* Turn TX interrupts back on */
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/ethertap.c b/drivers/net/ethertap.c
index b9bc5253a..49e84fd06 100644
--- a/drivers/net/ethertap.c
+++ b/drivers/net/ethertap.c
@@ -11,6 +11,7 @@
* even for building bridging tunnels.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -25,6 +26,7 @@
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <net/sock.h>
#include <linux/netlink.h>
/*
@@ -36,7 +38,10 @@ static int ethertap_open(struct device *dev);
static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev);
static int ethertap_close(struct device *dev);
static struct net_device_stats *ethertap_get_stats(struct device *dev);
-static int ethertap_rx(int id, struct sk_buff *skb);
+static void ethertap_rx(struct sock *sk, int len);
+#ifdef CONFIG_ETHERTAP_MC
+static void set_multicast_list(struct device *dev);
+#endif
static int ethertap_debug = 0;
@@ -48,6 +53,10 @@ static struct device *tap_map[32]; /* Returns the tap device for a given netlink
struct net_local
{
+ struct sock *nl;
+#ifdef CONFIG_ETHERTAP_MC
+ __u32 groups;
+#endif
struct net_device_stats stats;
};
@@ -58,7 +67,7 @@ struct net_local
__initfunc(int ethertap_probe(struct device *dev))
{
- memcpy(dev->dev_addr, "\xFD\xFD\x00\x00\x00\x00", 6);
+ memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6);
if (dev->mem_start & 0xf)
ethertap_debug = dev->mem_start & 0x7;
@@ -79,6 +88,9 @@ __initfunc(int ethertap_probe(struct device *dev))
dev->hard_start_xmit = ethertap_start_xmit;
dev->stop = ethertap_close;
dev->get_stats = ethertap_get_stats;
+#ifdef CONFIG_ETHERTAP_MC
+ dev->set_multicast_list = set_multicast_list;
+#endif
/*
* Setup the generic properties
@@ -86,10 +98,10 @@ __initfunc(int ethertap_probe(struct device *dev))
ether_setup(dev);
- dev->flags|=IFF_NOARP; /* Need to set ARP - looks like there is a bug
- in the 2.1.x hard header code currently */
+ dev->tx_queue_len = 0;
+ dev->flags|=IFF_NOARP;
tap_map[dev->base_addr]=dev;
-
+
return 0;
}
@@ -99,28 +111,58 @@ __initfunc(int ethertap_probe(struct device *dev))
static int ethertap_open(struct device *dev)
{
- struct in_device *in_dev;
+ struct net_local *lp = (struct net_local*)dev->priv;
+
if (ethertap_debug > 2)
printk("%s: Doing ethertap_open()...", dev->name);
- netlink_attach(dev->base_addr, ethertap_rx);
+
+ MOD_INC_USE_COUNT;
+
+ lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx);
+ if (lp->nl == NULL) {
+ MOD_DEC_USE_COUNT;
+ return -ENOBUFS;
+ }
+
dev->start = 1;
dev->tbusy = 0;
+ return 0;
+}
- /* Fill in the MAC based on the IP address. We do the same thing
- here as PLIP does */
-
- if((in_dev=dev->ip_ptr)!=NULL)
- {
- /*
- * Any address wil do - we take the first
- */
- struct in_ifaddr *ifa=in_dev->ifa_list;
- if(ifa!=NULL)
- memcpy(dev->dev_addr+2,&ifa->ifa_local,4);
+#ifdef CONFIG_ETHERTAP_MC
+static unsigned ethertap_mc_hash(__u8 *dest)
+{
+ unsigned idx = 0;
+ idx ^= dest[0];
+ idx ^= dest[1];
+ idx ^= dest[2];
+ idx ^= dest[3];
+ idx ^= dest[4];
+ idx ^= dest[5];
+ return 1U << (idx&0x1F);
+}
+
+static void set_multicast_list(struct device *dev)
+{
+ unsigned groups = ~0;
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) {
+ struct dev_mc_list *dmi;
+
+ groups = ethertap_mc_hash(dev->broadcast);
+
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+ if (dmi->dmi_addrlen != 6)
+ continue;
+ groups |= ethertap_mc_hash(dmi->dmi_addr);
+ }
}
- MOD_INC_USE_COUNT;
- return 0;
+ lp->groups = groups;
+ if (lp->nl)
+ lp->nl->protinfo.af_netlink.groups = groups;
}
+#endif
/*
* We transmit by throwing the packet at netlink. We have to clone
@@ -130,20 +172,110 @@ static int ethertap_open(struct device *dev)
static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
- struct sk_buff *tmp;
- /* copy buffer to tap */
- tmp=skb_clone(skb, GFP_ATOMIC);
- if(tmp)
- {
- if(netlink_post(dev->base_addr, tmp)<0)
- kfree_skb(tmp, FREE_WRITE);
- lp->stats.tx_bytes+=skb->len;
- lp->stats.tx_packets++;
+#ifdef CONFIG_ETHERTAP_MC
+ struct ethhdr *eth = (struct ethhdr*)skb->data;
+#endif
+
+ if (skb_headroom(skb) < 2) {
+ printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name);
+ dev_kfree_skb(skb);
+ return 0;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ skb_push(skb, 2);
+
+ /* Make the same thing, which loopback does. */
+ if (skb_shared(skb)) {
+ struct sk_buff *skb2 = skb;
+ skb = skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */
+ if (skb==NULL) {
+ dev_kfree_skb(skb2);
+ return 0;
+ }
+ dev_kfree_skb(skb2);
+ }
+ /* ... but do not orphan it here, netlink does it in any case. */
+
+ lp->stats.tx_bytes+=skb->len;
+ lp->stats.tx_packets++;
+
+#ifndef CONFIG_ETHERTAP_MC
+ netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC);
+#else
+ if (dev->flags&IFF_NOARP) {
+ netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC);
+ return 0;
+ }
+
+ if (!(eth->h_dest[0]&1)) {
+ /* Unicast packet */
+ __u32 pid;
+ memcpy(&pid, eth->h_dest+2, 4);
+ netlink_unicast(lp->nl, skb, ntohl(pid), MSG_DONTWAIT);
+ } else
+ netlink_broadcast(lp->nl, skb, 0, ethertap_mc_hash(eth->h_dest), GFP_ATOMIC);
+#endif
return 0;
}
+static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+#ifdef CONFIG_ETHERTAP_MC
+ struct ethhdr *eth = (struct ethhdr*)(skb->data + 2);
+#endif
+ int len = skb->len;
+
+ if (len < 16) {
+ printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ if (NETLINK_CREDS(skb)->uid) {
+ printk(KERN_INFO "%s : user %d\n", dev->name, NETLINK_CREDS(skb)->uid);
+ kfree_skb(skb);
+ return -EPERM;
+ }
+
+#ifdef CONFIG_ETHERTAP_MC
+ if (!(dev->flags&(IFF_NOARP|IFF_PROMISC))) {
+ int drop = 0;
+
+ if (eth->h_dest[0]&1) {
+ if (!(ethertap_mc_hash(eth->h_dest)&lp->groups))
+ drop = 1;
+ } else if (memcmp(eth->h_dest, dev->dev_addr, 6) != 0)
+ drop = 1;
+
+ if (drop) {
+ if (ethertap_debug > 3)
+ printk(KERN_DEBUG "%s : not for us\n", dev->name);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ }
+#endif
+
+ if (skb_shared(skb)) {
+ struct sk_buff *skb2 = skb;
+ skb = skb_clone(skb, GFP_KERNEL); /* Clone the buffer */
+ if (skb==NULL) {
+ kfree_skb(skb2);
+ return -ENOBUFS;
+ }
+ kfree_skb(skb2);
+ } else
+ skb_orphan(skb);
+
+ skb_pull(skb, 2);
+ skb->dev = dev;
+ skb->protocol=eth_type_trans(skb,dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes+=len;
+ netif_rx(skb);
+ return len;
+}
+
/*
* The typical workload of the driver:
* Handle the ether interface interrupts.
@@ -151,37 +283,40 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev)
* (In this case handle the packets posted from user space..)
*/
-static int ethertap_rx(int id, struct sk_buff *skb)
+static void ethertap_rx(struct sock *sk, int len)
{
- struct device *dev = (struct device *)(tap_map[id]);
- struct net_local *lp;
- int len=skb->len;
-
- if(dev==NULL)
- {
- printk("ethertap: bad unit!\n");
- kfree_skb(skb, FREE_WRITE);
- return -ENXIO;
+ struct device *dev = tap_map[sk->protocol];
+ struct sk_buff *skb;
+
+ if (dev==NULL) {
+ printk(KERN_CRIT "ethertap: bad unit!\n");
+ skb_queue_purge(&sk->receive_queue);
+ return;
}
- lp = (struct net_local *)dev->priv;
if (ethertap_debug > 3)
printk("%s: ethertap_rx()\n", dev->name);
- skb->dev = dev;
- skb->protocol=eth_type_trans(skb,dev);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=len;
- netif_rx(skb);
- return len;
+
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+ ethertap_rx_skb(skb, dev);
}
static int ethertap_close(struct device *dev)
{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ struct sock *sk = lp->nl;
+
if (ethertap_debug > 2)
- printk("%s: Shutting down tap %ld.\n", dev->name, dev->base_addr);
+ printk("%s: Shutting down.\n", dev->name);
dev->tbusy = 1;
dev->start = 0;
+
+ if (sk) {
+ lp->nl = NULL;
+ sock_release(sk->socket);
+ }
+
MOD_DEC_USE_COUNT;
return 0;
}
@@ -213,7 +348,7 @@ int init_module(void)
sprintf(devicename,"tap%d",unit);
if (dev_get(devicename))
{
- printk(KERN_INFO "ethertap: tap %d already loaded.\n", unit);
+ printk(KERN_INFO "%s already loaded.\n", devicename);
return -EBUSY;
}
if (register_netdev(&dev_ethertap) != 0)
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index ee0581e1d..f17343b40 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -847,7 +847,7 @@ static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
}
dev->trans_start = jiffies;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
} else { /* return unused page to the free memory queue */
outb(page, EWRK3_FMQ);
@@ -1904,13 +1904,13 @@ int init_module(void)
void cleanup_module(void)
{
+ unregister_netdev(&thisEthwrk);
if (thisEthwrk.priv) {
kfree(thisEthwrk.priv);
thisEthwrk.priv = NULL;
}
thisEthwrk.irq = 0;
- unregister_netdev(&thisEthwrk);
release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE);
}
#endif /* MODULE */
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 78bf20a07..3350d0d5c 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -388,7 +388,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
/* Re-enable interrupts */
outw(0x8182, ioaddr + TX_INTR);
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/hamradio/.cvsignore b/drivers/net/hamradio/.cvsignore
index 4671378ae..857dd22e9 100644
--- a/drivers/net/hamradio/.cvsignore
+++ b/drivers/net/hamradio/.cvsignore
@@ -1 +1,2 @@
.depend
+.*.flags
diff --git a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in
index 85434e502..c0719608a 100644
--- a/drivers/net/hamradio/Config.in
+++ b/drivers/net/hamradio/Config.in
@@ -1,61 +1,27 @@
-#
-# Amateur Radio protocols and AX.25 device configuration
-#
-# 19971130 Now in an own category to make correct compilation of the
-# AX.25 stuff easier...
-# Joerg Reuter DL1BKE <jreuter@poboxes.com>
+comment 'AX.25 network device drivers'
-mainmenu_option next_comment
-comment 'Amateur Radio support'
-bool 'Amateur Radio support' CONFIG_HAMRADIO
-
-if [ "$CONFIG_HAMRADIO" != "n" ] ; then
- if [ "$CONFIG_NET" != "n" ] ; then
- comment 'Packet Radio protocols'
- tristate 'Amateur Radio AX.25 Level 2 protocol' CONFIG_AX25
- if [ "$CONFIG_AX25" != "n" ]; then
- bool ' AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE
-# bool ' AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER
- dep_tristate ' Amateur Radio NET/ROM protocol' CONFIG_NETROM $CONFIG_AX25
- dep_tristate ' Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25
- fi
-
- if [ "$CONFIG_AX25" != "n" ]; then
- comment 'AX.25 network device drivers'
- tristate 'Serial port KISS driver' CONFIG_MKISS
-# tristate 'Serial port 6PACK driver' CONFIG_6PACK
- tristate 'BPQ Ethernet driver' CONFIG_BPQETHER
-
- tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
- tristate 'Z8530 SCC driver' CONFIG_SCC
- if [ "$CONFIG_SCC" != "n" ]; then
- bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY
- bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO
- fi
+dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25
+# dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25
+dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25
- tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX
- tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX
- tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR
-
- tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
- if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
- bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
- bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
- bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200
- bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7
- bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
- bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
- bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
- fi
- fi
- fi
-
- comment 'Misc. hamradio protocols'
- tristate 'Shortwave radio modem driver' CONFIG_HFMODEM
- if [ "$CONFIG_HFMODEM" != "n" ]; then
- bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC
- bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS
- fi
+dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25
+dep_tristate 'Z8530 SCC driver' CONFIG_SCC $CONFIG_AX25
+if [ "$CONFIG_SCC" != "n" ]; then
+ bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY
+ bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO
fi
+
+dep_tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX $CONFIG_AX25
+dep_tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX $CONFIG_AX25
+dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_AX25
-endmenu
+dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_AX25
+if [ "$CONFIG_SOUNDMODEM" != "n" ]; then
+ bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
+ bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
+ bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200
+ bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7
+ bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
+ bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
+ bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
+fi
diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile
index 349371dd0..c247cee79 100644
--- a/drivers/net/hamradio/Makefile
+++ b/drivers/net/hamradio/Makefile
@@ -21,6 +21,14 @@ MOD_LIST_NAME := HAM_MODULES
CONFIG_HDLCDRV_BUILTIN :=
CONFIG_HDLCDRV_MODULE :=
+ifeq ($(CONFIG_DMASCC),y)
+L_OBJS += dmascc.o
+else
+ ifeq ($(CONFIG_DMASCC),m)
+ M_OBJS += dmascc.o
+ endif
+endif
+
ifeq ($(CONFIG_SCC),y)
L_OBJS += scc.o
else
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 0b470e2f3..25fcd137e 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -392,18 +392,18 @@ static int par96_open(struct device *dev)
return -ENXIO;
}
if (pp->irq < 0) {
- printk(KERN_ERR "baycom_par: parport at 0x%x has no irq\n", pp->base);
+ printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base);
return -ENXIO;
}
memset(&bc->modem, 0, sizeof(bc->modem));
bc->hdrv.par.bitrate = 9600;
if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup,
par96_interrupt, PARPORT_DEV_LURK, dev))) {
- printk(KERN_ERR "baycom_par: cannot register parport at 0x%x\n", pp->base);
+ printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", pp->base);
return -ENXIO;
}
if (parport_claim(bc->pdev)) {
- printk(KERN_ERR "baycom_par: parport at 0x%x busy\n", pp->base);
+ printk(KERN_ERR "baycom_par: parport at 0x%lx busy\n", pp->base);
parport_unregister_device(bc->pdev);
return -EBUSY;
}
@@ -502,7 +502,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (dev->start || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 9005356d3..b70e4efde 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -587,7 +587,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (dev->start || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index e3d7ac998..f1024658d 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -626,7 +626,7 @@ static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (dev->start || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return baycom_setmode(bc, hi->data.modename);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 54d63121e..fcc9ed7cc 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -51,6 +51,7 @@
* call.
* Fixed to match Linux networking
* changes - 2.1.15.
+ * BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig.
*/
#include <linux/config.h>
@@ -78,6 +79,7 @@
#include <linux/firewall.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/rtnetlink.h>
#include <net/ip.h>
#include <net/arp.h>
@@ -186,7 +188,11 @@ static int bpq_check_devices(struct device *dev)
if (&bpq->axdev == dev)
result = 1;
- unregister_netdev(&bpq->axdev);
+ /* We should be locked, call
+ * unregister_netdevice directly
+ */
+
+ unregister_netdevice(&bpq->axdev);
kfree(bpq);
}
@@ -217,7 +223,7 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *
dev = bpq_get_ax25_dev(dev);
if (dev == NULL || dev->start == 0) {
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -230,7 +236,7 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *
if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) {
printk(KERN_DEBUG "bpqether: wrong dest %s\n", bpq_print_ethaddr(eth->h_source));
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -271,7 +277,7 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
*/
if (!dev->start) {
bpq_check_devices(dev);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return -ENODEV;
}
@@ -285,14 +291,14 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */
if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) {
printk(KERN_WARNING "bpqether: out of memory\n");
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk != NULL)
skb_set_owner_w(newskb, skb->sk);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
skb = newskb;
}
@@ -307,7 +313,7 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
if ((dev = bpq_get_ether_dev(dev)) == NULL) {
bpq->stats.tx_dropped++;
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return -ENODEV;
}
@@ -531,7 +537,9 @@ static int bpq_new_device(struct device *dev)
dev->name = buf;
dev->init = bpq_dev_init;
- if (register_netdev(dev) != 0) {
+ /* We should be locked, call register_netdevice() directly. */
+
+ if (register_netdevice(dev) != 0) {
kfree(bpq);
return -EIO;
}
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 33b473d32..c07f90249 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1,5 +1,5 @@
/*
- * $Id: dmascc.c,v 1.2 1997/12/02 16:49:49 oe1kib Exp $
+ * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $
*
* Driver for high-speed SCC boards (those with DMA support)
* Copyright (C) 1997 Klaus Kudielka
@@ -21,11 +21,11 @@
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/dmascc.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
@@ -40,12 +40,55 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/segment.h>
-#include <asm/uaccess.h>
#include <net/ax25.h>
-#include <stdio.h>
#include "z8530.h"
+/* Linux 2.0 compatibility */
+
+#if LINUX_VERSION_CODE < 0x20100
+
+
+#define __init
+#define __initdata
+#define __initfunc(x) x
+
+#define MODULE_AUTHOR(x)
+#define MODULE_DESCRIPTION(x)
+#define MODULE_PARM(x,y)
+
+#define copy_to_user(x,y,z) memcpy_tofs(x,y,z)
+#define copy_from_user(x,y,z) memcpy_fromfs(x,y,z)
+#define test_and_set_bit(x,y) set_bit(x,y)
+#define register_netdevice(x) register_netdev(x)
+#define unregister_netdevice(x) unregister_netdev(x)
+
+static int dmascc_dev_init(struct device *dev)
+{
+ return 0;
+}
+
+static void dev_init_buffers(struct device *dev)
+{
+ int i;
+
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ skb_queue_head_init(&dev->buffs[i]);
+}
+
+
+#else
+
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#define dmascc_dev_init NULL
+
+
+#endif
+
+
/* Number of buffers per channel */
#define NUM_TX_BUF 2 /* NUM_TX_BUF >= 1 (2 recommended) */
@@ -89,7 +132,7 @@
#define SCCA_CMD 0x02
#define SCCA_DATA 0x03
-/* 8254 registers relative to card base */
+/* 8253/8254 registers relative to card base */
#define TMR_CNT0 0x00
#define TMR_CNT1 0x01
#define TMR_CNT2 0x02
@@ -265,7 +308,7 @@ void cleanup_module(void)
/* Unregister devices */
for (i = 0; i < 2; i++) {
if (info->dev[i].name)
- unregister_netdev(&info->dev[i]);
+ unregister_netdevice(&info->dev[i]);
}
/* Reset board */
@@ -301,14 +344,19 @@ __initfunc(void dmascc_setup(char *str, int *ints))
__initfunc(int dmascc_init(void))
{
- int h, i, j, n, base[MAX_NUM_DEVS], tcmd, t0, t1, status;
- unsigned long time, start[MAX_NUM_DEVS], stop[MAX_NUM_DEVS];
+ int h, i, j, n;
+ int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS],
+ t1[MAX_NUM_DEVS];
+ unsigned t_val;
+ unsigned long time, start[MAX_NUM_DEVS], delay[MAX_NUM_DEVS],
+ counting[MAX_NUM_DEVS];
/* Initialize random number generator */
rand = jiffies;
-
/* Cards found = 0 */
n = 0;
+ /* Warning message */
+ if (!io[0]) printk("dmascc: autoprobing (dangerous)\n");
/* Run autodetection for each card type */
for (h = 0; h < NUM_TYPES; h++) {
@@ -320,63 +368,66 @@ __initfunc(int dmascc_init(void))
j = (io[i] - hw[h].io_region) / hw[h].io_delta;
if (j >= 0 &&
j < hw[h].num_devs &&
- hw[h].io_region + j * hw[h].io_delta == io[i])
+ hw[h].io_region + j * hw[h].io_delta == io[i]) {
base[j] = io[i];
+ }
}
} else {
/* Default I/O address regions */
- for (i = 0; i < hw[h].num_devs; i++)
+ for (i = 0; i < hw[h].num_devs; i++) {
base[i] = hw[h].io_region + i * hw[h].io_delta;
+ }
}
/* Check valid I/O address regions */
for (i = 0; i < hw[h].num_devs; i++)
- if (base[i] && check_region(base[i], hw[h].io_size))
- base[i] = 0;
+ if (base[i])
+ if (check_region(base[i], hw[h].io_size))
+ base[i] = 0;
+ else {
+ tcmd[i] = base[i] + hw[h].tmr_offset + TMR_CTRL;
+ t0[i] = base[i] + hw[h].tmr_offset + TMR_CNT0;
+ t1[i] = base[i] + hw[h].tmr_offset + TMR_CNT1;
+ }
/* Start timers */
for (i = 0; i < hw[h].num_devs; i++)
if (base[i]) {
- tcmd = base[i] + hw[h].tmr_offset + TMR_CTRL;
- t0 = base[i] + hw[h].tmr_offset + TMR_CNT0;
- t1 = base[i] + hw[h].tmr_offset + TMR_CNT1;
/* Timer 0: LSB+MSB, Mode 3, TMR_0_HZ */
- outb_p(0x36, tcmd);
- outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0);
- outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0);
+ outb_p(0x36, tcmd[i]);
+ outb_p((hw[h].tmr_hz/TMR_0_HZ) & 0xFF, t0[i]);
+ outb_p((hw[h].tmr_hz/TMR_0_HZ) >> 8, t0[i]);
/* Timer 1: LSB+MSB, Mode 0, HZ/10 */
- outb_p(0x70, tcmd);
- outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1);
- outb_p((TMR_0_HZ/HZ*10) >> 8, t1);
+ outb_p(0x70, tcmd[i]);
+ outb_p((TMR_0_HZ/HZ*10) & 0xFF, t1[i]);
+ outb_p((TMR_0_HZ/HZ*10) >> 8, t1[i]);
+ start[i] = jiffies;
+ delay[i] = 0;
+ counting[i] = 1;
/* Timer 2: LSB+MSB, Mode 0 */
- outb_p(0xb0, tcmd);
+ outb_p(0xb0, tcmd[i]);
}
-
- /* Initialize start values in case we miss the null count bit */
time = jiffies;
- for (i = 0; i < hw[h].num_devs; i++) start[i] = time;
+ /* Wait until counter registers are loaded */
+ udelay(2000000/TMR_0_HZ);
/* Timing loop */
- while (jiffies - time < 12) {
+ while (jiffies - time < 13) {
for (i = 0; i < hw[h].num_devs; i++)
- if (base[i]) {
- /* Read back Timer 1: Status */
- outb_p(0xE4, base[i] + hw[h].tmr_offset + TMR_CTRL);
- status = inb_p(base[i] + hw[h].tmr_offset + TMR_CNT1);
- if ((status & 0x3F) != 0x30) base[i] = 0;
- if (status & 0x40) start[i] = jiffies;
- if (~status & 0x80) stop[i] = jiffies;
+ if (base[i] && counting[i]) {
+ /* Read back Timer 1: latch; read LSB; read MSB */
+ outb_p(0x40, tcmd[i]);
+ t_val = inb_p(t1[i]) + (inb_p(t1[i]) << 8);
+ /* Also check whether counter did wrap */
+ if (t_val == 0 || t_val > TMR_0_HZ/HZ*10) counting[i] = 0;
+ delay[i] = jiffies - start[i];
}
}
/* Evaluate measurements */
for (i = 0; i < hw[h].num_devs; i++)
if (base[i]) {
- time = stop[i] - start[i];
- if (time < 9 || time > 11)
- /* The time expired doesn't match */
- base[i] = 0;
- else {
+ if (delay[i] >= 9 && delay[i] <= 11) {
/* Ok, we have found an adapter */
if (setup_adapter(base[i], h, n) == 0)
n++;
@@ -523,6 +574,7 @@ __initfunc(int setup_adapter(int io, int h, int n))
dev->hard_header = ax25_encapsulate;
dev->rebuild_header = ax25_rebuild_header;
dev->set_mac_address = scc_set_mac_address;
+ dev->init = dmascc_dev_init;
dev->type = ARPHRD_AX25;
dev->hard_header_len = 73;
dev->mtu = 1500;
@@ -530,9 +582,8 @@ __initfunc(int setup_adapter(int io, int h, int n))
dev->tx_queue_len = 64;
memcpy(dev->broadcast, ax25_broadcast, 7);
memcpy(dev->dev_addr, ax25_test, 7);
- dev->flags = 0;
dev_init_buffers(dev);
- if (register_netdev(dev)) {
+ if (register_netdevice(dev)) {
printk("dmascc: could not register %s\n", dev->name);
dev->name = NULL;
}
@@ -749,7 +800,7 @@ static int scc_send_packet(struct sk_buff *skb, struct device *dev)
/* Block a timer-based transmit from overlapping */
if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
atomic_inc((void *) &priv->stats.tx_dropped);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
@@ -785,7 +836,7 @@ static int scc_send_packet(struct sk_buff *skb, struct device *dev)
restore_flags(flags);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
priv->tx_sem = 0;
return 0;
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 148ed14f4..f4fb73844 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -446,18 +446,18 @@ void hdlcdrv_transmitter(struct device *dev, struct hdlcdrv_state *s)
}
if (skb->data[0] != 0) {
do_kiss_params(s, skb->data, skb->len);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
break;
}
pkt_len = skb->len-1; /* strip KISS byte */
if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) {
s->hdlctx.tx_state = 0;
s->hdlctx.numflags = 1;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
break;
}
memcpy(s->hdlctx.buffer, skb->data+1, pkt_len);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
s->hdlctx.bp = s->hdlctx.buffer;
append_crc_ccitt(s->hdlctx.buffer, pkt_len);
s->hdlctx.len = pkt_len+2; /* the appended CRC */
@@ -681,7 +681,7 @@ static int hdlcdrv_close(struct device *dev)
i = s->ops->close(dev);
/* Free any buffers left in the hardware transmit queue */
while ((skb = skb_dequeue(&s->send_queue)))
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return i;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 562a27681..21cdbf5c6 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -420,7 +420,7 @@ static int ax_xmit(struct sk_buff *skb, struct device *dev)
if (tmp_ax != NULL)
ax_lock(tmp_ax);
ax_encaps(ax, skb->data, skb->len);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
}
return 0;
diff --git a/drivers/net/hamradio/pi2.c b/drivers/net/hamradio/pi2.c
index 3eb3a9223..8de325175 100644
--- a/drivers/net/hamradio/pi2.c
+++ b/drivers/net/hamradio/pi2.c
@@ -408,7 +408,7 @@ static void a_exint(struct pi_local *lp)
}
switch (lp->tstate) {
case ACTIVE:
- kfree_skb(lp->sndbuf, FREE_WRITE);
+ kfree_skb(lp->sndbuf);
lp->sndbuf = NULL;
lp->tstate = FLAGOUT;
tdelay(lp, lp->squeldelay);
@@ -726,7 +726,7 @@ static void b_txint(struct pi_local *lp)
/* stuffing a char satisfies Interrupt condition */
} else {
/* No more to send */
- kfree_skb(lp->sndbuf, FREE_WRITE);
+ kfree_skb(lp->sndbuf);
lp->sndbuf = NULL;
if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) {
/* Did we underrun? */
@@ -778,7 +778,7 @@ static void b_exint(struct pi_local *lp)
switch (lp->tstate) {
case ACTIVE: /* Unexpected underrun */
- kfree_skb(lp->sndbuf, FREE_WRITE);
+ kfree_skb(lp->sndbuf);
lp->sndbuf = NULL;
wrtscc(lp->cardbase, cmd, R0, SEND_ABORT);
lp->tstate = FLAGOUT;
@@ -1553,7 +1553,7 @@ static int pi_close(struct device *dev)
/* Free any buffers left in the hardware transmit queue */
while ((ptr = skb_dequeue(&lp->sndq)) != NULL)
- kfree_skb(ptr, FREE_WRITE);
+ kfree_skb(ptr);
restore_flags(flags);
diff --git a/drivers/net/hamradio/pt.c b/drivers/net/hamradio/pt.c
index 11bef1d6f..86ed83d3b 100644
--- a/drivers/net/hamradio/pt.c
+++ b/drivers/net/hamradio/pt.c
@@ -967,7 +967,7 @@ static int pt_close(struct device *dev)
/* Free any buffers left in the hardware transmit queue */
while ((ptr = skb_dequeue(&lp->sndq)) != NULL)
- kfree_skb(ptr, FREE_WRITE);
+ kfree_skb(ptr);
restore_flags(flags);
@@ -1185,7 +1185,7 @@ static void pt_txisr(struct pt_local *lp)
/* stuffing a char satisfies interrupt condition */
} else {
/* No more to send */
- kfree_skb(lp->sndbuf, FREE_WRITE);
+ kfree_skb(lp->sndbuf);
lp->sndbuf = NULL;
if ((rdscc(lp->cardbase, cmd, R0) & TxEOM))
{
@@ -1540,7 +1540,7 @@ static void pt_exisr(struct pt_local *lp)
#ifdef PT_DEBUG
printk(KERN_DEBUG "PT: exisr(): unexpected underrun detected.\n");
#endif
- kfree_skb(lp->sndbuf, FREE_WRITE);
+ kfree_skb(lp->sndbuf);
lp->sndbuf = NULL;
if (!lp->dmachan)
{
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 1665d2b2b..736d6b26b 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1,4 +1,4 @@
-#define RCS_ID "$Id: scc.c,v 1.71 1997/11/29 19:59:20 jreuter Exp jreuter $"
+#define RCS_ID "$Id: scc.c,v 1.73 1998/01/29 17:38:51 jreuter Exp jreuter $"
#define VERSION "3.0"
#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
@@ -6,6 +6,9 @@
/*
* Please use z8530drv-utils-3.0 with this version.
* ------------------
+ *
+ * You can find a subset of the documentation in
+ * linux/Documentation/networking/z8530drv.txt.
*/
/*
@@ -16,7 +19,7 @@
********************************************************************
- Copyright (c) 1993, 1997 Joerg Reuter DL1BKE
+ Copyright (c) 1993, 1998 Joerg Reuter DL1BKE
portions (c) 1993 Guido ten Dolle PE1NNZ
@@ -89,7 +92,8 @@
970108 - Fixed the remaining problems.
970402 - Hopefully fixed the problems with the new *_timer()
routines, added calibration code.
- 971012 - made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
+ 971012 - Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO
+ 980129 - Small fix to avoid lock-up on initialization
Thanks to all who contributed to this driver with ideas and bug
reports!
@@ -166,10 +170,7 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <time.h>
+#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
@@ -198,7 +199,7 @@ static void scc_key_trx (struct scc_channel *scc, char tx);
static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void scc_init_timer(struct scc_channel *scc);
-static int scc_net_setup(struct scc_channel *scc, unsigned char *name);
+static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev);
static int scc_net_init(struct device *dev);
static int scc_net_open(struct device *dev);
static int scc_net_close(struct device *dev);
@@ -323,12 +324,12 @@ extern __inline__ void scc_discard_buffers(struct scc_channel *scc)
if (scc->tx_buff != NULL)
{
- dev_kfree_skb(scc->tx_buff, FREE_WRITE);
+ dev_kfree_skb(scc->tx_buff);
scc->tx_buff = NULL;
}
while (skb_queue_len(&scc->tx_queue))
- dev_kfree_skb(skb_dequeue(&scc->tx_queue), FREE_WRITE);
+ dev_kfree_skb(skb_dequeue(&scc->tx_queue));
restore_flags(flags);
}
@@ -371,7 +372,7 @@ extern __inline__ void flush_rx_FIFO(struct scc_channel *scc)
if(scc->rx_buff != NULL) /* did we receive something? */
{
scc->stat.rxerrs++; /* then count it as an error */
- kfree_skb(scc->rx_buff, FREE_READ);
+ kfree_skb(scc->rx_buff);
scc->rx_buff = NULL;
}
}
@@ -405,7 +406,7 @@ extern __inline__ void scc_txint(struct scc_channel *scc)
if (skb->len == 0) /* Paranoia... */
{
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
scc->tx_buff = NULL;
scc_tx_done(scc);
Outb(scc->ctrl, RES_Tx_P);
@@ -431,7 +432,7 @@ extern __inline__ void scc_txint(struct scc_channel *scc)
{
Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
cl(scc, R10, ABUNDER); /* send CRC */
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
scc->tx_buff = NULL;
scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
return;
@@ -512,7 +513,7 @@ extern __inline__ void scc_exint(struct scc_channel *scc)
if (scc->tx_buff != NULL)
{
- dev_kfree_skb(scc->tx_buff, FREE_WRITE);
+ dev_kfree_skb(scc->tx_buff);
scc->tx_buff = NULL;
}
@@ -562,7 +563,7 @@ extern __inline__ void scc_rxint(struct scc_channel *scc)
#ifdef notdef
printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");
#endif
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
scc->rx_buff = NULL;
Inb(scc->data);
or(scc, R3, ENT_HM);
@@ -592,7 +593,7 @@ extern __inline__ void scc_spint(struct scc_channel *scc)
or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
if (skb != NULL)
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
scc->rx_buff = NULL;
}
@@ -608,7 +609,7 @@ extern __inline__ void scc_spint(struct scc_channel *scc)
scc->rx_buff = NULL;
scc->stat.rxframes++;
} else { /* a bad frame */
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
scc->rx_buff = NULL;
scc->stat.rxerrs++;
}
@@ -1532,7 +1533,7 @@ static void z8530_init(void)
* Allocate device structure, err, instance, and register driver
*/
-static int scc_net_setup(struct scc_channel *scc, unsigned char *name)
+static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev)
{
unsigned char *buf;
struct device *dev;
@@ -1556,11 +1557,11 @@ static int scc_net_setup(struct scc_channel *scc, unsigned char *name)
dev->name = buf;
dev->init = scc_net_init;
- if (register_netdev(dev) != 0)
+ if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0)
{
kfree(dev);
- return -EIO;
- }
+ return -EIO;
+ }
return 0;
}
@@ -1670,7 +1671,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
{
if (skb->len == 0)
{
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return;
}
@@ -1694,14 +1695,14 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev)
if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)
{
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
if (skb->len > scc->stat.bufsize || skb->len < 2)
{
scc->dev_stat.tx_dropped++; /* bogus frame */
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
@@ -1714,7 +1715,7 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev)
if (kisscmd)
{
scc_set_param(scc, kisscmd, *skb->data);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
@@ -1725,7 +1726,7 @@ static int scc_net_tx(struct sk_buff *skb, struct device *dev)
{
struct sk_buff *skb_del;
skb_del = __skb_dequeue(&scc->tx_queue);
- dev_kfree_skb(skb_del, FREE_WRITE);
+ dev_kfree_skb(skb_del);
}
__skb_queue_tail(&scc->tx_queue, skb);
@@ -1871,7 +1872,7 @@ static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
if (Nchips+chan != 0)
- scc_net_setup(&SCC_Info[2*Nchips+chan], device_name);
+ scc_net_setup(&SCC_Info[2*Nchips+chan], device_name, 1);
}
}
@@ -2181,7 +2182,7 @@ __initfunc(int scc_init (void))
sprintf(devname,"%s0", SCC_DriverName);
- result = scc_net_setup(SCC_Info, devname);
+ result = scc_net_setup(SCC_Info, devname, 0);
if (result)
{
printk(KERN_ERR "z8530drv: cannot initialize module\n");
@@ -2206,7 +2207,7 @@ int init_module(void)
result = scc_init();
if (result == 0)
- printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n");
+ printk(KERN_INFO "Copyright 1993,1998 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n");
return result;
}
diff --git a/drivers/net/hamradio/soundmodem/.cvsignore b/drivers/net/hamradio/soundmodem/.cvsignore
deleted file mode 100644
index 4671378ae..000000000
--- a/drivers/net/hamradio/soundmodem/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-.depend
diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c
index d1dce6687..4750c18ee 100644
--- a/drivers/net/hamradio/soundmodem/gentbl.c
+++ b/drivers/net/hamradio/soundmodem/gentbl.c
@@ -200,7 +200,9 @@ static void gentbl_fsk9600(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
min = max = 0;
memset(c, 0, sizeof(c));
@@ -233,7 +235,9 @@ static void gentbl_fsk9600(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
}
@@ -466,7 +470,9 @@ static void gentbl_hapn4800(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
min = max = 0;
memset(c, 0, sizeof(c));
@@ -493,7 +499,9 @@ static void gentbl_hapn4800(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
/*
* secondly generate tables for the PM transmitter modulator
@@ -524,7 +532,9 @@ static void gentbl_hapn4800(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
min = max = 0;
memset(c, 0, sizeof(c));
@@ -552,7 +562,9 @@ static void gentbl_hapn4800(FILE *f)
? "\n\t" : "");
}
}
+#ifdef VERBOSE
fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max);
+#endif
fprintf(f, "\n};\n\n");
}
diff --git a/drivers/net/hamradio/soundmodem/sm.c b/drivers/net/hamradio/soundmodem/sm.c
index 171aecfc7..3423807ac 100644
--- a/drivers/net/hamradio/soundmodem/sm.c
+++ b/drivers/net/hamradio/soundmodem/sm.c
@@ -592,7 +592,7 @@ static int sm_ioctl(struct device *dev, struct ifreq *ifr,
return 0;
case HDLCDRVCTL_SETMODE:
- if (!suser() || dev->start)
+ if (dev->start || !suser())
return -EACCES;
hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
return sethw(dev, sm, hi->data.modename);
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 0952b8ae0..84289fcba 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -103,13 +103,13 @@ static int hpp_close(struct device *dev);
static void hpp_mem_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void hpp_mem_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void hpp_mem_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void hpp_io_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void hpp_io_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void hpp_io_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
@@ -385,7 +385,7 @@ hpp_mem_block_input(struct device *dev, int count, struct sk_buff *skb, int ring
It's always safe to round up, so we do. */
static void
hpp_io_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page)
+ const unsigned char *buf, int start_page)
{
int ioaddr = dev->base_addr - NIC_OFFSET;
outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
@@ -395,7 +395,7 @@ hpp_io_block_output(struct device *dev, int count,
static void
hpp_mem_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page)
+ const unsigned char *buf, int start_page)
{
int ioaddr = dev->base_addr - NIC_OFFSET;
int option_reg = inw(ioaddr + HPP_OPTION);
@@ -466,10 +466,10 @@ cleanup_module(void)
if (dev->priv != NULL) {
/* NB: hpp_close() handles free_irq */
int ioaddr = dev->base_addr - NIC_OFFSET;
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(ioaddr, HP_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 156ed5f14..55ac7de0f 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -31,6 +31,7 @@ static const char *version =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -66,7 +67,7 @@ static void hp_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
static void hp_block_input(struct device *dev, int count,
struct sk_buff *skb , int ring_offset);
static void hp_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void hp_init_card(struct device *dev);
@@ -309,7 +310,7 @@ hp_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offs
static void
hp_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page)
+ const unsigned char *buf, int start_page)
{
int nic_base = dev->base_addr;
int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
@@ -432,11 +433,11 @@ cleanup_module(void)
struct device *dev = &dev_hp[this_dev];
if (dev->priv != NULL) {
int ioaddr = dev->base_addr - NIC_OFFSET;
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(ioaddr, HP_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index b5eaec24f..cb6b1bb69 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1474,7 +1474,7 @@ static void hp100_clean_txring(struct device *dev)
hp100_inb(TX_PDL),
donecount);
#endif
- dev_kfree_skb(lp->txrhead->skb, FREE_WRITE);
+ dev_kfree_skb(lp->txrhead->skb);
lp->txrhead->skb = (void *) NULL;
lp->txrhead = lp->txrhead->next;
lp->txrcommit--;
@@ -1599,7 +1599,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
hp100_ints_on();
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
#ifdef HP100_DEBUG_TX
printk("hp100_start_xmit: end\n");
@@ -1815,7 +1815,7 @@ static void hp100_rx_bm(struct device *dev)
printk("hp100: rx_bm: Received bad packet (length=%d)\n", pkt_len);
#endif
if (ptr->skb != NULL)
- dev_kfree_skb(ptr->skb, FREE_READ);
+ dev_kfree_skb(ptr->skb);
lp->stats.rx_errors++;
}
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index b7dbeb815..00549b6b9 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -500,7 +500,7 @@ static int hydra_start_xmit(struct sk_buff *skb, struct device *dev)
/* clear the unused space */
for(; len1<len; len1++)
(u16)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
priv->stats.tx_packets++;
diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
index 4fe7aefcd..dad41c2dd 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/ibmtr.c
@@ -790,7 +790,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
DPRINTK("error on xmit_dir_frame request: %02X\n",
xmit_ret_code);
if (ti->current_skb) {
- dev_kfree_skb(ti->current_skb, FREE_WRITE);
+ dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
}
dev->tbusy=0;
@@ -807,7 +807,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
DPRINTK("error on xmit_ui_frame request: %02X\n",
xmit_ret_code);
if (ti->current_skb) {
- dev_kfree_skb(ti->current_skb, FREE_WRITE);
+ dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
}
dev->tbusy=0;
@@ -1305,7 +1305,7 @@ static void tr_tx(struct device *dev)
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
dev->tbusy=0;
- dev_kfree_skb(ti->current_skb,FREE_WRITE);
+ dev_kfree_skb(ti->current_skb);
ti->current_skb=NULL;
mark_bh(NET_BH);
if (ti->readlog_pending) ibmtr_readlog(dev);
diff --git a/drivers/net/ipddp.c b/drivers/net/ipddp.c
index fa3072a6c..141349576 100644
--- a/drivers/net/ipddp.c
+++ b/drivers/net/ipddp.c
@@ -1,9 +1,10 @@
/*
- * ipddp.c: IP-over-DDP driver for Linux
+ * ipddp.c: IP to Appletalk-IP Encapsulation driver for Linux
+ * Appletalk-IP to IP Decapsulation driver for Linux
*
* Authors:
- * - Original code by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
- * - Moved to driver by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+ * - DDP-IP Encap by: Bradford W. Johnson <johns393@maroon.tc.umn.edu>
+ * - DDP-IP Decap by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
*
* Derived from:
* - Almost all code already existed in net/appletalk/ddp.c I just
@@ -12,6 +13,8 @@
* - skeleton.c: A network driver outline for linux.
* Written 1993-94 by Donald Becker.
* - dummy.c: A dummy net driver. By Nick Holloway.
+ * - MacGate: A user space Daemon for Appletalk-IP Decap for
+ * Linux by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
*
* Copyright 1993 United States Government as represented by the
* Director, National Security Agency.
@@ -21,7 +24,7 @@
*/
static const char *version =
-"ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+ "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
#include <linux/config.h>
#ifdef MODULE
@@ -53,16 +56,24 @@ static const char *version =
#include <linux/atalk.h>
#include <linux/ip.h>
#include <net/route.h>
+#include <linux/inet.h>
#include "ipddp.h" /* Our stuff */
+static struct ipddp_route *ipddp_route_list = NULL;
+
/*
* The name of the card. Is used for messages and in the requests for
* io regions, irqs and dma channels
*/
-
static const char *cardname = "ipddp";
+#ifdef CONFIG_IPDDP_ENCAP
+static int ipddp_mode = IPDDP_ENCAP;
+#else
+static int ipddp_mode = IPDDP_DECAP;
+#endif
+
/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
#ifndef IPDDP_DEBUG
#define IPDDP_DEBUG 1
@@ -73,8 +84,11 @@ static unsigned int ipddp_debug = IPDDP_DEBUG;
static int ipddp_xmit(struct sk_buff *skb, struct device *dev);
static struct net_device_stats *ipddp_get_stats(struct device *dev);
static int ipddp_rebuild_header(struct sk_buff *skb);
-static int ipddp_header(struct sk_buff *skb, struct device *dev,
+static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len);
+static int ipddp_create(struct ipddp_route *new_rt);
+static int ipddp_delete(struct ipddp_route *rt);
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
@@ -103,6 +117,17 @@ int ipddp_init(struct device *dev)
if (ipddp_debug && version_printed++ == 0)
printk("%s", version);
+ /* Let the user now what mode we are in */
+ if(ipddp_mode == IPDDP_ENCAP)
+ printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n",
+ dev->name);
+ if(ipddp_mode == IPDDP_DECAP)
+ printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist <Jay.Schulist@spacs.k12.wi.us>\n",
+ dev->name);
+
+ /* Fill in the device structure with ethernet-generic values. */
+ ether_setup(dev);
+
/* Initalize the device structure. */
dev->hard_start_xmit = ipddp_xmit;
@@ -115,7 +140,7 @@ int ipddp_init(struct device *dev)
dev->stop = ipddp_close;
dev->get_stats = ipddp_get_stats;
dev->do_ioctl = ipddp_ioctl;
- dev->hard_header = ipddp_header; /* see ip_output.c */
+ dev->hard_header = ipddp_hard_header; /* see ip_output.c */
dev->rebuild_header = ipddp_rebuild_header;
dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
@@ -129,9 +154,6 @@ int ipddp_init(struct device *dev)
*/
dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
- /* Fill in the device structure with ethernet-generic values. */
- ether_setup(dev);
-
return 0;
}
@@ -141,17 +163,14 @@ int ipddp_init(struct device *dev)
static int ipddp_xmit(struct sk_buff *skb, struct device *dev)
{
/* Retrieve the saved address hint */
- struct at_addr *a=(struct at_addr *)skb->data;
+ struct at_addr *at = (struct at_addr *)skb->data;
skb_pull(skb,4);
((struct net_device_stats *) dev->priv)->tx_packets++;
((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
- if(ipddp_debug>1)
- printk("ipddp_xmit: Headroom %d\n",skb_headroom(skb));
-
- if(aarp_send_ddp(skb->dev,skb,a,NULL) < 0)
- dev_kfree_skb(skb,FREE_WRITE);
+ if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0)
+ dev_kfree_skb(skb);
return 0;
}
@@ -165,7 +184,8 @@ static struct net_device_stats *ipddp_get_stats(struct device *dev)
}
/*
- * Now the packet really wants to go out.
+ * Now the packet really wants to go out. On entry skb->data points to the
+ * ddpehdr we reserved earlier. skb->h.raw will be the higher level header.
*/
static int ipddp_rebuild_header(struct sk_buff *skb)
{
@@ -175,106 +195,172 @@ static int ipddp_rebuild_header(struct sk_buff *skb)
struct ipddp_route *rt;
struct at_addr *our_addr;
- /*
- * On entry skb->data points to the ddpehdr we reserved earlier.
- * skb->h.raw will be the higher level header.
- */
+ /* Wow! I'll eat my hat if this routine is really called. --ANK */
- /*
- * We created this earlier.
+ /*
+ * Find appropriate route to use, based only on IP number.
*/
-
- ddp = (struct ddpehdr *) (skb->data+4);
-
- /* find appropriate route */
-
- for(rt=ipddp_route_head;rt;rt=rt->next)
+ for(rt = ipddp_route_list; rt != NULL; rt = rt->next)
{
if(rt->ip == paddr)
break;
}
- if(!rt) {
- printk("ipddp unreachable dst %08lx\n",ntohl(paddr));
+ if(rt == NULL)
+ {
+ printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr));
return -ENETUNREACH;
}
our_addr = atalk_find_dev_addr(rt->dev);
- /* fill in ddpehdr */
+ if(ipddp_mode == IPDDP_DECAP)
+ /*
+ * Pull off the excess room that should not be there.
+ * This is the case for Localtalk, this may not hold
+ * true for Ethertalk, etc.
+ */
+ skb_pull(skb, 31-(sizeof(struct ddpehdr)+1));
+
+ /* Create the Extended DDP header */
+ ddp = (struct ddpehdr *) (skb->data+4);
ddp->deh_len = skb->len;
ddp->deh_hops = 1;
ddp->deh_pad = 0;
ddp->deh_sum = 0;
- ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */
- ddp->deh_snet = our_addr->s_net;
+
+ /*
+ * For Localtalk we need aarp_send_ddp to strip the
+ * Ext DDP header and place a Shrt DDP header on it.
+ */
+ if(rt->dev->type == ARPHRD_LOCALTLK)
+ {
+ ddp->deh_dnet = 0; /* FIXME more hops?? */
+ ddp->deh_snet = 0;
+ }
+ else
+ {
+ ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */
+ ddp->deh_snet = our_addr->s_net;
+ }
ddp->deh_dnode = rt->at.s_node;
ddp->deh_snode = our_addr->s_node;
ddp->deh_dport = 72;
ddp->deh_sport = 72;
- *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
-
- /* fix up length field */
- *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));
+ *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
+ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
- /* set skb->dev to appropriate device */
- skb->dev = rt->dev;
-
- /* skb->raddr = (unsigned long) at */
+ /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */
at = rt->at;
- /* Hide it at the start of the buffer */
memcpy(skb->data,(void *)&at,sizeof(at));
- skb->arp = 1; /* so the actual device doesn't try to arp it... */
+
+ skb->dev = rt->dev; /* set skb->dev to appropriate device */
skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
return 0;
}
-static int ipddp_header(struct sk_buff *skb, struct device *dev,
+static int ipddp_hard_header(struct sk_buff *skb, struct device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
- if(ipddp_debug>=2)
- printk("%s: ipddp_header\n", cardname);
-
/* Push down the header space and the type byte */
skb_push(skb, sizeof(struct ddpehdr)+1+4);
return 0;
}
+/*
+ * Create a routing entry. We first verify that the
+ * record does not already exist. If it does we return -EEXIST
+ */
+static int ipddp_create(struct ipddp_route *new_rt)
+{
+ struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
+ struct ipddp_route *test;
+
+ if(rt == NULL)
+ return -ENOMEM;
+
+ rt->ip = new_rt->ip;
+ rt->at = new_rt->at;
+ rt->next = NULL;
+ rt->dev = atrtr_get_dev(&rt->at);
+ if(rt->dev == NULL)
+ return (-ENETUNREACH);
+
+ test = ipddp_find_route(rt);
+ if(test != NULL)
+ return (-EEXIST);
+
+ rt->next = ipddp_route_list;
+ ipddp_route_list = rt;
+
+ return 0;
+}
+
+/*
+ * Delete a route, we only delete a FULL match.
+ * If route does not exist we return -ENOENT.
+ */
+static int ipddp_delete(struct ipddp_route *rt)
+{
+ struct ipddp_route **r = &ipddp_route_list;
+ struct ipddp_route *tmp;
+
+ while((tmp = *r) != NULL)
+ {
+ if(tmp->ip == rt->ip
+ && tmp->at.s_net == rt->at.s_net
+ && tmp->at.s_node == rt->at.s_node)
+ {
+ *r = tmp->next;
+ kfree_s(tmp, sizeof(struct ipddp_route));
+ return 0;
+ }
+ r = &tmp->next;
+ }
+
+ return (-ENOENT);
+}
+
+/*
+ * Find a routing entry, we only return a FULL match
+ */
+static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+{
+ struct ipddp_route *f;
+
+ for(f = ipddp_route_list; f != NULL; f = f->next)
+ {
+ if(f->ip == rt->ip
+ && f->at.s_net == rt->at.s_net
+ && f->at.s_node == rt->at.s_node)
+ return (f);
+ }
+
+ return (NULL);
+}
+
static int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
{
- struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data;
+ struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
if(!suser())
return -EPERM;
- /* for now we only have one route at a time */
-
switch(cmd)
{
- case SIOCADDIPDDPRT:
- if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route)))
- return -EFAULT;
- ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at);
- if (dev==NULL)
- return -ENETUNREACH;
- ipddp_route_test.next = NULL;
- printk("%s: Added route through %s\n",
- ipddp_route_test.dev->name, cardname);
- ipddp_route_head = &ipddp_route_test;
- return 0;
+ case SIOCADDIPDDPRT:
+ return (ipddp_create(rt));
case SIOCFINDIPDDPRT:
- if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route)))
+ if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
return -EFAULT;
return 0;
case SIOCDELIPDDPRT:
- ipddp_route_test.dev = NULL;
- ipddp_route_head = NULL;
- return 0;
+ return (ipddp_delete(rt));
default:
return -EINVAL;
@@ -291,9 +377,17 @@ static struct device dev_ipddp=
0, 0, 0, NULL, ipddp_init
};
+MODULE_PARM(ipddp_mode, "i");
+
int init_module(void)
{
- if (register_netdev(&dev_ipddp) != 0)
+ int err;
+
+ err=dev_alloc_name(&dev_ipddp, "ipddp%d");
+ if(err < 0)
+ return err;
+
+ if(register_netdev(&dev_ipddp) != 0)
return -EIO;
return 0;
diff --git a/drivers/net/ipddp.h b/drivers/net/ipddp.h
index 6093adfec..31178934b 100644
--- a/drivers/net/ipddp.h
+++ b/drivers/net/ipddp.h
@@ -7,9 +7,10 @@
#ifdef __KERNEL__
-#define SIOCADDIPDDPRT SIOCDEVPRIVATE
-#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
-#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
+#define SIOCADDIPDDPRT (SIOCDEVPRIVATE)
+#define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1)
+#define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2)
+#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3)
struct ipddp_route
{
@@ -20,8 +21,8 @@ struct ipddp_route
struct ipddp_route *next;
};
-static struct ipddp_route *ipddp_route_head;
-static struct ipddp_route ipddp_route_test;
+#define IPDDP_ENCAP 1
+#define IPDDP_DECAP 2
#endif /* __KERNEL__ */
#endif /* __LINUX_IPDDP_H */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 97d0f27d6..423b4a7ac 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -611,7 +611,7 @@ __initfunc(void lance_probe1(int ioaddr))
can watch the LEDs even if the board isn't opened. */
outw(0x0002, ioaddr+LANCE_ADDR);
/* set autoselect and clean xmausel */
- outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF);
+ outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
}
if (lance_debug > 0 && did_version++ == 0)
@@ -667,7 +667,7 @@ lance_open(struct device *dev)
/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
outw(0x0002, ioaddr+LANCE_ADDR);
/* set autoselect and clean xmausel */
- outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF);
+ outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF);
}
if (lance_debug > 1)
@@ -730,7 +730,7 @@ lance_purge_tx_ring(struct device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
if (lp->tx_skbuff[i]) {
- dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
+ dev_kfree_skb(lp->tx_skbuff[i]);
lp->tx_skbuff[i] = NULL;
}
}
@@ -870,7 +870,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
lp->tx_ring[entry].base =
((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
} else {
lp->tx_skbuff[entry] = skb;
lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
@@ -969,7 +969,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb if it's not a data-only copy
in the bounce buffer. */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
+ dev_kfree_skb(lp->tx_skbuff[entry]);
lp->tx_skbuff[entry] = 0;
}
dirty_tx++;
diff --git a/drivers/net/lapbether.c b/drivers/net/lapbether.c
index bee5d50bf..40fce3adc 100644
--- a/drivers/net/lapbether.c
+++ b/drivers/net/lapbether.c
@@ -18,7 +18,6 @@
* LAPBETH 001 Jonathan Naylor Cloned from bpqether.c
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -165,7 +164,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct device *dev, struct packet_ty
dev = lapbeth_get_x25_dev(dev);
if (dev == NULL || dev->start == 0) {
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -179,7 +178,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct device *dev, struct packet_ty
skb_trim(skb, len); /* Set the length of the data */
if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
}
@@ -218,7 +217,7 @@ static int lapbeth_xmit(struct sk_buff *skb, struct device *dev)
*/
if (!dev->start) {
lapbeth_check_devices(dev);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return -ENODEV;
}
@@ -228,15 +227,15 @@ static int lapbeth_xmit(struct sk_buff *skb, struct device *dev)
case 0x01:
if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
case 0x02:
if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
default:
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
}
@@ -244,7 +243,7 @@ static int lapbeth_xmit(struct sk_buff *skb, struct device *dev)
if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return -ENOMEM;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 075304def..63723afb5 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -79,10 +79,10 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
struct sk_buff *skb2=skb;
skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */
if(skb==NULL) {
- kfree_skb(skb2, FREE_WRITE);
+ kfree_skb(skb2);
return 0;
}
- kfree_skb(skb2, FREE_WRITE);
+ kfree_skb(skb2);
}
else
skb_orphan(skb);
diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c
index 8626b8406..205ec6ac2 100644
--- a/drivers/net/ltpc.c
+++ b/drivers/net/ltpc.c
@@ -180,7 +180,6 @@ static int debug=0;
#define DEBUG_UPPER 2
#define DEBUG_LOWER 4
-#include <linux/config.h> /* for CONFIG_MAX_16M */
#ifdef MODULE
#include <linux/module.h>
@@ -951,7 +950,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct device *dev)
stats->tx_packets++;
stats->tx_bytes+=skb->len;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 74bc0a5e4..cf1e9e903 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -333,12 +333,12 @@ static int mace_close(struct device *dev)
/* free some skb's */
for (i = 0; i < N_RX_RING; ++i) {
if (mp->rx_bufs[i] != 0) {
- dev_kfree_skb(mp->rx_bufs[i], FREE_READ);
+ dev_kfree_skb(mp->rx_bufs[i]);
mp->rx_bufs[i] = 0;
}
}
for (i = mp->tx_empty; i != mp->tx_fill; ) {
- dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ dev_kfree_skb(mp->tx_bufs[i]);
if (++i >= N_TX_RING)
i = 0;
}
@@ -601,7 +601,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++mp->stats.tx_aborted_errors;
} else
++mp->stats.tx_packets;
- dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ dev_kfree_skb(mp->tx_bufs[i]);
--mp->tx_active;
if (++i >= N_TX_RING)
i = 0;
@@ -680,7 +680,7 @@ static void mace_tx_timeout(unsigned long data)
if (mp->tx_bad_runt) {
mp->tx_bad_runt = 0;
} else if (i != mp->tx_fill) {
- dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+ dev_kfree_skb(mp->tx_bufs[i]);
if (++i >= N_TX_RING)
i = 0;
mp->tx_empty = i;
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 73ea41f26..52d3a5089 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -244,7 +244,7 @@ static void myri_clean_rings(struct myri_eth *mp)
rq->tail = rq->head = 0;
for(i = 0; i < (RX_RING_SIZE+1); i++) {
if(mp->rx_skbs[i] != NULL) {
- dev_kfree_skb(mp->rx_skbs[i], FREE_READ);
+ dev_kfree_skb(mp->rx_skbs[i]);
mp->rx_skbs[i] = NULL;
}
}
@@ -252,7 +252,7 @@ static void myri_clean_rings(struct myri_eth *mp)
mp->tx_old = sq->tail = sq->head = 0;
for(i = 0; i < TX_RING_SIZE; i++) {
if(mp->tx_skbs[i] != NULL) {
- dev_kfree_skb(mp->tx_skbs[i], FREE_WRITE);
+ dev_kfree_skb(mp->tx_skbs[i]);
mp->tx_skbs[i] = NULL;
}
}
@@ -337,7 +337,7 @@ static inline void myri_tx(struct myri_eth *mp, struct device *dev)
struct sk_buff *skb = mp->tx_skbs[entry];
DTX(("SKB[%d] ", entry));
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
mp->enet_stats.tx_packets++;
@@ -714,7 +714,6 @@ static int myri_rebuild_header(struct sk_buff *skb)
unsigned char *pad = (unsigned char *)skb->data;
struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN);
struct device *dev = skb->dev;
- struct neighbour *neigh = NULL;
#ifdef DEBUG_HEADER
DHDR(("myri_rebuild_header: pad[%02x,%02x] ", pad[0], pad[1]));
@@ -725,16 +724,6 @@ static int myri_rebuild_header(struct sk_buff *skb)
pad[0] = MYRI_PAD_LEN;
pad[1] = 0xab;
- /*
- * Only ARP/IP and NDISC/IPv6 are currently supported
- */
-
- if (skb->dst)
- neigh = skb->dst->neighbour;
-
- if (neigh)
- return neigh->ops->resolve(eth->h_dest, skb);
-
switch (eth->h_proto)
{
#ifdef CONFIG_INET
@@ -755,59 +744,31 @@ static int myri_rebuild_header(struct sk_buff *skb)
return 0;
}
-int myri_header_cache(struct dst_entry *dst, struct neighbour *neigh,
- struct hh_cache *hh)
+int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
unsigned char *pad = (unsigned char *)hh->hh_data;
struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN);
- struct device *dev = dst->dev;
+ struct device *dev = neigh->dev;
- if (type == ETH_P_802_3)
+ if (type == __constant_htons(ETH_P_802_3))
return -1;
/* Refill MyriNet padding identifiers, this is just being anal. */
pad[0] = MYRI_PAD_LEN;
pad[1] = 0xab;
- eth->h_proto = htons(type);
-
+ eth->h_proto = type;
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
- if (dev->flags & IFF_LOOPBACK) {
- memset(eth->h_dest, 0, dev->addr_len);
- hh->hh_uptodate = 1;
- return 0;
- }
-
- if (type != ETH_P_IP) {
- printk(KERN_DEBUG "%s: unable to resolve type %X addresses.\n",
- dev->name, (int)eth->h_proto);
- hh->hh_uptodate = 0;
- return 0;
- }
-
-#ifdef CONFIG_INET
- hh->hh_uptodate = arp_find_1(eth->h_dest, dst, neigh);
-#else
- hh->hh_uptodate = 0;
-#endif
+ memcpy(eth->h_dest, neigh->ha, dev->addr_len);
return 0;
}
+
/* Called by Address Resolution module to notify changes in address. */
-void myri_header_cache_update(struct hh_cache *hh, struct device *dev,
- unsigned char * haddr)
+void myri_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
{
- if (hh->hh_type != ETH_P_IP) {
- printk(KERN_DEBUG "eth_header_cache_update: %04x cache is not "
- "implemented\n", hh->hh_type);
- return;
- }
- hh->hh_data[0] = MYRI_PAD_LEN;
- hh->hh_data[1] = 0xab;
- memcpy(hh->hh_data+2, haddr, ETH_ALEN);
- hh->hh_uptodate = 1;
+ memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
}
static int myri_change_mtu(struct device *dev, int new_mtu)
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index efbfc54e4..87b808754 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -72,14 +72,14 @@ static unsigned int netcard_portlist[] __initdata =
#ifdef CONFIG_PCI
/* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */
-static struct { unsigned short vendor, dev_id;}
+static struct { unsigned short vendor, dev_id; char *name; }
pci_clone_list[] __initdata = {
- {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029},
- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940},
- {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000},
- {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2},
- {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC},
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926},
+ {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, "Realtek 8029" },
+ {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, "Winbond 89C940" },
+ {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, "Compex ReadyLink 2000" },
+ {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, "KTI ET32P2" },
+ {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, "NetVin NV5000" },
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926, "VIA 82C926 Amazon" },
{0,}
};
#endif
@@ -228,9 +228,8 @@ __initfunc(static int ne_probe_pci(struct device *dev))
break; /* Beauty -- got a valid card. */
}
if (pci_irq_line == 0) continue; /* Try next PCI ID */
- printk("ne.c: PCI BIOS reports %s %s at i/o %#x, irq %d.\n",
- pci_strvendor(pci_clone_list[i].vendor),
- pci_strdev(pci_clone_list[i].vendor, pci_clone_list[i].dev_id),
+ printk("ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n",
+ pci_clone_list[i].name,
pci_ioaddr, pci_irq_line);
if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */
printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
@@ -783,11 +782,11 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
struct device *dev = &dev_ne[this_dev];
if (dev->priv != NULL) {
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(dev->base_addr, NE_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 9a853e9c9..9eea1b7ac 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -460,7 +460,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct device *dev)
hardware_send_packet(dev, (unsigned char *)skb->data, length);
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 332addbe3..1f2330133 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -989,7 +989,7 @@ static void ni52_rcv_int(struct device *dev)
}
#endif
-#ifdef 0
+#if 0
if(!at_least_one)
{
int i;
@@ -1203,7 +1203,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
ni_attn586();
dev->trans_start = jiffies;
if(!i)
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
WAIT_4_SCB_CMD();
if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
break;
@@ -1223,7 +1223,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
dev->trans_start = jiffies;
p->nop_point = next_nop;
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
# endif
#else
p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
@@ -1248,7 +1248,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
p->lock = 0;
restore_flags(flags);
}
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
#endif
}
return 0;
@@ -1338,9 +1338,9 @@ int init_module(void)
void cleanup_module(void)
{
release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE);
+ unregister_netdev(&dev_ni52);
kfree(dev_ni52.priv);
dev_ni52.priv = NULL;
- unregister_netdev(&dev_ni52);
}
#endif /* MODULE */
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index e0812c6d6..63d862a45 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -306,7 +306,7 @@ static int ni65_close(struct device *dev)
for(i=0;i<TMDNUM;i++)
{
if(p->tmd_skb[i]) {
- dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+ dev_kfree_skb(p->tmd_skb[i]);
p->tmd_skb[i] = NULL;
}
}
@@ -548,7 +548,7 @@ static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type)
if( (u32) virt_to_bus(ptr+size) > 0x1000000) {
printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
if(type)
- kfree_skb(skb,FREE_WRITE);
+ kfree_skb(skb);
else
kfree(ptr);
return NULL;
@@ -623,7 +623,7 @@ static void ni65_free_buffer(struct priv *p)
kfree(p->tmdbounce[i]);
#ifdef XMT_VIA_SKB
if(p->tmd_skb[i])
- dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+ dev_kfree_skb(p->tmd_skb[i]);
#endif
}
@@ -631,7 +631,7 @@ static void ni65_free_buffer(struct priv *p)
{
#ifdef RCV_VIA_SKB
if(p->recv_skb[i])
- dev_kfree_skb(p->recv_skb[i],FREE_WRITE);
+ dev_kfree_skb(p->recv_skb[i]);
#else
if(p->recvbounce[i])
kfree(p->recvbounce[i]);
@@ -741,7 +741,7 @@ static int ni65_lance_reinit(struct device *dev)
struct tmd *tmdp = p->tmdhead + i;
#ifdef XMT_VIA_SKB
if(p->tmd_skb[i]) {
- dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);
+ dev_kfree_skb(p->tmd_skb[i]);
p->tmd_skb[i] = NULL;
}
#endif
@@ -955,7 +955,7 @@ static void ni65_xmit_intr(struct device *dev,int csr0)
#ifdef XMT_VIA_SKB
if(p->tmd_skb[p->tmdlast]) {
- dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE);
+ dev_kfree_skb(p->tmd_skb[p->tmdlast]);
p->tmd_skb[p->tmdlast] = NULL;
}
#endif
@@ -1104,7 +1104,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
(skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
save_flags(flags);
cli();
@@ -1202,10 +1202,10 @@ void cleanup_module(void)
}
disable_dma(dev_ni65.dma);
free_dma(dev_ni65.dma);
+ unregister_netdev(&dev_ni65);
release_region(dev_ni65.base_addr,cards[p->cardno].total_size);
ni65_free_buffer(p);
dev_ni65.priv = NULL;
- unregister_netdev(&dev_ni65);
}
#endif /* MODULE */
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 629ace381..391714567 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -497,7 +497,7 @@ pcnet32_purge_tx_ring(struct device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
if (lp->tx_skbuff[i]) {
- dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
+ dev_kfree_skb(lp->tx_skbuff[i]);
lp->tx_skbuff[i] = NULL;
}
}
@@ -730,7 +730,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb */
if (lp->tx_skbuff[entry]) {
- dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
+ dev_kfree_skb(lp->tx_skbuff[entry]);
lp->tx_skbuff[entry] = 0;
}
dirty_tx++;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 1774de0bb..4341a3449 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -12,11 +12,11 @@
* Modularization and ifreq/ifmap support by Alan Cox.
* Rewritten by Niibe Yutaka.
* parport-sharing awareness code by Philip Blundell.
+ * SMP locking by Niibe Yutaka.
*
* Fixes:
* Niibe Yutaka
- * - Module initialization. You can specify I/O addr and IRQ:
- * # insmod plip.o io=0x3bc irq=7
+ * - Module initialization.
* - MTU fix.
* - Make sure other end is OK, before sending a packet.
* - Fix immediate timer problem.
@@ -45,7 +45,7 @@
* To use with DOS box, please do (Turn on ARP switch):
* # ifconfig plip[0-2] arp
*/
-static const char *version = "NET3 PLIP version 2.2-parport gniibe@mri.co.jp\n";
+static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";
/*
Sources:
@@ -80,7 +80,6 @@ static const char *version = "NET3 PLIP version 2.2-parport gniibe@mri.co.jp\n";
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -108,6 +107,7 @@ static const char *version = "NET3 PLIP version 2.2-parport gniibe@mri.co.jp\n";
#include <asm/bitops.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <asm/spinlock.h>
#include <linux/parport.h>
@@ -214,6 +214,7 @@ struct net_local {
int port_owner;
int should_relinquish;
int (*orig_rebuild_header)(struct sk_buff *skb);
+ spinlock_t lock;
};
/* Entry point of PLIP driver.
@@ -238,7 +239,7 @@ plip_init_dev(struct device *dev, struct parport *pb))
printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name);
return -ENODEV;
}
-
+
pardev = parport_register_device(pb, dev->name, plip_preempt,
plip_wakeup, plip_interrupt,
PARPORT_DEV_LURK, dev);
@@ -291,6 +292,7 @@ plip_init_dev(struct device *dev, struct parport *pb))
nl->deferred.sync = 0;
nl->deferred.routine = (void *)(void *)plip_kick_bh;
nl->deferred.data = dev;
+ spin_lock_init(&nl->lock);
return 0;
}
@@ -367,7 +369,7 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
{
unsigned char c0;
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_SEND) {
if (error != ERROR) { /* Timeout */
@@ -375,7 +377,7 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
if ((snd->state == PLIP_PK_TRIGGER
&& nl->timeout_count <= 10)
|| nl->timeout_count <= 3) {
- sti();
+ spin_unlock_irq(&nl->lock);
/* Try again later */
return TIMEOUT;
}
@@ -388,12 +390,12 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
} else if (nl->connection == PLIP_CN_RECEIVE) {
if (rcv->state == PLIP_PK_TRIGGER) {
/* Transmission was interrupted. */
- sti();
+ spin_unlock_irq(&nl->lock);
return OK;
}
if (error != ERROR) { /* Timeout */
if (++nl->timeout_count <= 3) {
- sti();
+ spin_unlock_irq(&nl->lock);
/* Try again later */
return TIMEOUT;
}
@@ -405,20 +407,21 @@ plip_bh_timeout_error(struct device *dev, struct net_local *nl,
}
rcv->state = PLIP_PK_DONE;
if (rcv->skb) {
- kfree_skb(rcv->skb, FREE_READ);
+ kfree_skb(rcv->skb);
rcv->skb = NULL;
}
snd->state = PLIP_PK_DONE;
if (snd->skb) {
- dev_kfree_skb(snd->skb, FREE_WRITE);
+ dev_kfree_skb(snd->skb);
snd->skb = NULL;
}
+ spin_unlock_irq(&nl->lock);
disable_irq(dev->irq);
+ synchronize_irq();
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->tbusy = 1;
nl->connection = PLIP_CN_ERROR;
outb(0x00, PAR_DATA(dev));
- sti();
return TIMEOUT;
}
@@ -493,6 +496,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
switch (rcv->state) {
case PLIP_PK_TRIGGER:
disable_irq(dev->irq);
+ /* Don't need to synchronize irq, as we can safely ignore it */
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->interrupt = 0;
outb(0x01, PAR_DATA(dev)); /* send ACK */
@@ -577,10 +581,10 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
/* Close the connection. */
outb (0x00, PAR_DATA(dev));
- cli();
+ spin_lock_irq(&nl->lock);
if (snd->state != PLIP_PK_DONE) {
nl->connection = PLIP_CN_SEND;
- sti();
+ spin_unlock_irq(&nl->lock);
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
@@ -588,7 +592,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
return OK;
} else {
nl->connection = PLIP_CN_NONE;
- sti();
+ spin_unlock_irq(&nl->lock);
outb(PAR_INTR_ON, PAR_CONTROL(dev));
enable_irq(dev->irq);
return OK;
@@ -673,28 +677,34 @@ plip_send_packet(struct device *dev, struct net_local *nl,
cx = nl->trigger;
while (1) {
udelay(PLIP_DELAY_UNIT);
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_RECEIVE) {
- sti();
- /* interrupted */
+ spin_unlock_irq(&nl->lock);
+ /* Interrupted. */
nl->enet_stats.collisions++;
- if (net_debug > 1)
- printk("%s: collision.\n", dev->name);
return OK;
}
c0 = inb(PAR_STATUS(dev));
if (c0 & 0x08) {
+ spin_unlock_irq(&nl->lock);
disable_irq(dev->irq);
+ synchronize_irq();
+ if (nl->connection == PLIP_CN_RECEIVE) {
+ /* Interrupted.
+ We don't need to enable irq,
+ as it is soon disabled. */
+ nl->enet_stats.collisions++;
+ return OK;
+ }
outb(PAR_INTR_OFF, PAR_CONTROL(dev));
if (net_debug > 2)
printk("%s: send start\n", dev->name);
snd->state = PLIP_PK_LENGTH_LSB;
snd->nibble = PLIP_NB_BEGIN;
nl->timeout_count = 0;
- sti();
break;
}
- sti();
+ spin_unlock_irq(&nl->lock);
if (--cx == 0) {
outb(0x00, data_addr);
return TIMEOUT;
@@ -731,7 +741,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
&snd->nibble, snd->checksum))
return TIMEOUT;
- dev_kfree_skb(snd->skb, FREE_WRITE);
+ dev_kfree_skb(snd->skb);
nl->enet_stats.tx_packets++;
snd->state = PLIP_PK_DONE;
@@ -755,13 +765,13 @@ static int
plip_connection_close(struct device *dev, struct net_local *nl,
struct plip_local *snd, struct plip_local *rcv)
{
- cli();
+ spin_lock_irq(&nl->lock);
if (nl->connection == PLIP_CN_CLOSING) {
nl->connection = PLIP_CN_NONE;
dev->tbusy = 0;
mark_bh(NET_BH);
}
- sti();
+ spin_unlock_irq(&nl->lock);
if (nl->should_relinquish) {
nl->should_relinquish = nl->port_owner = 0;
parport_release(nl->pardev);
@@ -805,7 +815,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
unsigned char c0;
if (dev == NULL) {
- printk ("plip_interrupt: irq %d for unknown device.\n", irq);
+ printk("plip_interrupt: irq %d for unknown device.\n", irq);
return;
}
@@ -825,7 +835,7 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if (net_debug > 3)
printk("%s: interrupt.\n", dev->name);
- cli();
+ spin_lock_irq(&nl->lock);
switch (nl->connection) {
case PLIP_CN_CLOSING:
dev->tbusy = 0;
@@ -837,16 +847,18 @@ plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
nl->timeout_count = 0;
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- sti();
+ spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_RECEIVE:
- sti();
- printk("%s: receive interrupt when receiving packet\n", dev->name);
+ /* May occur because there is race condition
+ around test and set of dev->interrupt.
+ Ignore this interrupt. */
+ spin_unlock_irq(&nl->lock);
break;
case PLIP_CN_ERROR:
- sti();
+ spin_unlock_irq(&nl->lock);
printk("%s: receive interrupt in error state\n", dev->name);
break;
}
@@ -898,7 +910,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
if (net_debug > 2)
printk("%s: send request\n", dev->name);
- cli();
+ spin_lock_irq(&nl->lock);
dev->trans_start = jiffies;
snd->skb = skb;
snd->length.h = skb->len;
@@ -909,7 +921,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
}
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- sti();
+ spin_unlock_irq(&nl->lock);
return 0;
}
@@ -946,24 +958,25 @@ plip_open(struct device *dev)
nl->connection = PLIP_CN_NONE;
nl->is_deferred = 0;
- /* Fill in the MAC-level header. */
+ /* Fill in the MAC-level header.
+ (ab)Use "dev->broadcast" to store point-to-point MAC address.
+ PLIP doesn't have a real mac address, but we need to create one
+ to be DOS compatible. */
memset(dev->dev_addr, 0xfc, ETH_ALEN);
+ memset(dev->broadcast, 0xfc, ETH_ALEN);
- /* Now PLIP doesnt have a real mac addr which is a pain..
- we need to create one, and to be DOS compatible its a good
- idea to use the same rules. Layering purists please look away */
-
- if((in_dev=dev->ip_ptr)!=NULL)
- {
+ if ((in_dev=dev->ip_ptr) != NULL) {
/*
- * Any address wil do - we take the first
+ * Any address will do - we take the first
*/
struct in_ifaddr *ifa=in_dev->ifa_list;
- if(ifa!=NULL)
- memcpy(dev->dev_addr+2,&ifa->ifa_local,4);
+ if (ifa != NULL) {
+ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+ memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
+ }
}
-
+
dev->interrupt = 0;
dev->start = 1;
dev->tbusy = 0;
@@ -982,8 +995,9 @@ plip_close(struct device *dev)
dev->tbusy = 1;
dev->start = 0;
- cli();
- sti();
+ disable_irq(dev->irq);
+ synchronize_irq();
+
#ifdef NOTDEF
outb(0x00, PAR_DATA(dev));
#endif
@@ -996,12 +1010,12 @@ plip_close(struct device *dev)
snd->state = PLIP_PK_DONE;
if (snd->skb) {
- dev_kfree_skb(snd->skb, FREE_WRITE);
+ dev_kfree_skb(snd->skb);
snd->skb = NULL;
}
rcv->state = PLIP_PK_DONE;
if (rcv->skb) {
- kfree_skb(rcv->skb, FREE_READ);
+ kfree_skb(rcv->skb);
rcv->skb = NULL;
}
@@ -1070,15 +1084,21 @@ plip_get_stats(struct device *dev)
static int
plip_config(struct device *dev, struct ifmap *map)
{
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct pardevice *pardev = nl->pardev;
+
if (dev->flags & IFF_UP)
return -EBUSY;
- if (map->base_addr != (unsigned long)-1
- && map->base_addr != dev->base_addr)
- printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+ printk(KERN_WARNING "plip: Warning, changing irq with ifconfig will be obsoleted.\n");
+ printk("plip: Next time, please set with /proc/parport/*/irq instead.\n");
- if (map->irq != (unsigned char)-1)
- dev->irq = map->irq;
+ if (map->irq != (unsigned char)-1) {
+ pardev->port->irq = dev->irq = map->irq;
+ /* Dummy request */
+ request_irq(dev->irq, plip_interrupt, SA_INTERRUPT,
+ pardev->name, NULL);
+ }
return 0;
}
@@ -1233,6 +1253,6 @@ plip_init(void))
/*
* Local variables:
- * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
+ * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c"
* End:
*/
diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c
index cb977abde..9380f32f8 100644
--- a/drivers/net/ppp.c
+++ b/drivers/net/ppp.c
@@ -2,11 +2,12 @@
*
* Michael Callahan <callahan@maths.ox.ac.uk>
* Al Longyear <longyear@netcom.com>
+ * Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
* ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
*
- * ==FILEVERSION 970126==
+ * ==FILEVERSION 980123==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
@@ -47,19 +48,9 @@
#define CHECK_CHARACTERS 1
#define PPP_COMPRESS 1
-#ifndef PPP_MAX_DEV
-#define PPP_MAX_DEV 256
-#endif
-
-/* $Id: ppp.c,v 1.27 1997/01/26 07:13:29 davem Exp $
- * Added dynamic allocation of channels to eliminate
- * compiled-in limits on the number of channels.
- *
- * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
- * released under the GNU General Public License Version 2.
- */
+/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
-#include <linux/config.h>
+#include <linux/config.h> /* for CONFIG_KERNELD */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -68,7 +59,6 @@
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
-#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/tty.h>
@@ -102,14 +92,11 @@ typedef struct sk_buff sk_buff;
#include <linux/socket.h>
#include <linux/if_ppp.h>
#include <linux/if_pppvar.h>
-
-#undef PACKETPTR
-#define PACKETPTR 1
#include <linux/ppp-comp.h>
-#undef PACKETPTR
-#define bsd_decompress (*ppp->sc_rcomp->decompress)
-#define bsd_compress (*ppp->sc_xcomp->compress)
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
#ifndef PPP_IPX
#define PPP_IPX 0x2b /* IPX protocol over PPP */
@@ -129,7 +116,6 @@ static void ppp_unregister_compressor (struct compressor *cp);
static struct compressor *find_compressor (int type);
static void ppp_init_ctrl_blk (register struct ppp *);
static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
-static int ppp_doframe (struct ppp *);
static struct ppp *ppp_alloc (void);
static struct ppp *ppp_find (int pid_value);
static void ppp_print_buffer (const __u8 *, const __u8 *, int);
@@ -137,6 +123,8 @@ extern inline void ppp_stuff_char (struct ppp *ppp,
register struct ppp_buffer *buf,
register __u8 chr);
extern inline int lock_buffer (register struct ppp_buffer *buf);
+static int ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf,
+ __u8 *data, int len, enum NPmode npmode);
static int rcv_proto_ip (struct ppp *, __u16, __u8 *, int);
static int rcv_proto_ipx (struct ppp *, __u16, __u8 *, int);
@@ -147,7 +135,6 @@ static int rcv_proto_lqr (struct ppp *, __u16, __u8 *, int);
static void ppp_doframe_lower (struct ppp *, __u8 *, int);
static int ppp_doframe (struct ppp *);
-extern int ppp_bsd_compressor_init(void);
static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd);
static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
@@ -157,19 +144,12 @@ static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
#define OPTIMIZE_FLAG_TIME 0
#endif
-#ifndef PPP_MAX_DEV
-#define PPP_MAX_DEV 256
-#endif
-
/*
* Parameters which may be changed via insmod.
*/
static int flag_time = OPTIMIZE_FLAG_TIME;
-static int max_dev = PPP_MAX_DEV;
-
MODULE_PARM(flag_time, "i");
-MODULE_PARM(max_dev, "i");
/*
* The "main" procedure to the ppp device
@@ -196,8 +176,9 @@ static ssize_t ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
static ssize_t ppp_tty_write (struct tty_struct *, struct file *,
const __u8 *, size_t);
static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
- unsigned long);
-static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait);
+ unsigned long);
+static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp,
+ poll_table * wait);
static int ppp_tty_open (struct tty_struct *);
static void ppp_tty_close (struct tty_struct *);
static int ppp_tty_room (struct tty_struct *tty);
@@ -205,8 +186,25 @@ static void ppp_tty_receive (struct tty_struct *tty, const __u8 * cp,
char *fp, int count);
static void ppp_tty_wakeup (struct tty_struct *tty);
-#define CHECK_PPP(a) if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
-#define CHECK_PPP_VOID() if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
+#define CHECK_PPP_MAGIC(ppp) do { \
+ if (ppp->magic != PPP_MAGIC) { \
+ printk(KERN_WARNING "bad magic for ppp %p at %s:%d\n", \
+ ppp, __FILE__, __LINE__); \
+ } \
+} while (0)
+#define CHECK_PPP(a) do { \
+ CHECK_PPP_MAGIC(ppp); \
+ if (!ppp->inuse) { \
+ printk (ppp_warning, __LINE__); \
+ return a; \
+ } \
+} while (0)
+#define CHECK_PPP_VOID() do { \
+ CHECK_PPP_MAGIC(ppp); \
+ if (!ppp->inuse) { \
+ printk (ppp_warning, __LINE__); \
+ } \
+} while (0)
#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
#define in_rmap(ppp,c) ((((unsigned int) (__u8) (c)) < 0x20) && \
@@ -214,31 +212,13 @@ static void ppp_tty_wakeup (struct tty_struct *tty);
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-#define tty2ppp(tty) ((struct ppp *) (tty->disc_data))
-#define dev2ppp(dev) ((struct ppp *) (dev->priv))
-#define ppp2tty(ppp) ((struct tty_struct *) ppp->tty)
-#define ppp2dev(ppp) ((struct device *) ppp->dev)
-
-struct ppp_hdr {
- __u8 address;
- __u8 control;
- __u8 protocol[2];
-};
-
-#define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr))
-
-typedef struct ppp_ctrl {
- struct ppp_ctrl *next; /* Next structure in the list */
- char name [8]; /* Name of the device */
- struct ppp ppp; /* PPP control table */
- struct device dev; /* Device information table */
-} ppp_ctrl_t;
+#define tty2ppp(tty) ((struct ppp *) ((tty)->disc_data))
+#define dev2ppp(dev) ((struct ppp *) ((dev)->priv))
+#define ppp2tty(ppp) ((ppp)->tty)
+#define ppp2dev(ppp) (&(ppp)->dev)
-static ppp_ctrl_t *ppp_list = NULL;
-
-#define ctl2ppp(ctl) (struct ppp *) &ctl->ppp
-#define ctl2dev(ctl) (struct device *) &ctl->dev
-#undef PPP_NRUNIT
+static struct ppp *ppp_list = NULL;
+static struct ppp *ppp_last = NULL;
/* Buffer types */
#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */
@@ -343,7 +323,7 @@ ppp_first_time (void))
int status;
printk (KERN_INFO
- "PPP: version %s (dynamic channel allocation)"
+ "PPP: version %s (demand dialling)"
"\n", szVersion);
#ifndef MODULE /* slhc module logic has its own copyright announcement */
@@ -352,9 +332,6 @@ ppp_first_time (void))
"University of California\n");
#endif
- printk (KERN_INFO
- "PPP Dynamic channel allocation code copyright 1995 "
- "Caldera, Inc.\n");
/*
* Register the tty discipline
*/
@@ -389,7 +366,7 @@ ppp_first_time (void))
static int
ppp_init_dev (struct device *dev)
{
- dev->hard_header_len = PPP_HARD_HDR_LEN;
+ dev->hard_header_len = PPP_HDRLEN;
/* device INFO */
dev->mtu = PPP_MTU;
@@ -403,9 +380,9 @@ ppp_init_dev (struct device *dev)
dev->type = ARPHRD_PPP;
dev_init_buffers(dev);
-
+
/* New-style flags */
- dev->flags = IFF_POINTOPOINT;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
return 0;
}
@@ -438,13 +415,11 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
ppp->read_wait = NULL;
ppp->write_wait = NULL;
ppp->last_xmit = jiffies - flag_time;
+ ppp->last_recv = jiffies;
/* clear statistics */
- memset (&ppp->stats, '\0', sizeof (struct pppstat));
-
- /* Reset the demand dial information */
- ppp->ddinfo.xmit_idle= /* time since last NP packet sent */
- ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
+ memset(&ppp->stats, 0, sizeof (struct pppstat));
+ memset(&ppp->estats, 0, sizeof(ppp->estats));
/* PPP compression data */
ppp->sc_xc_state =
@@ -474,6 +449,14 @@ ppp_init (struct device *dev)
}
#endif
+#define BUFFER_MAGIC 0x1d10
+#define CHECK_BUF_MAGIC(buf) do { \
+ if (buf->magic != BUFFER_MAGIC) { \
+ printk(KERN_WARNING "bad magic for ppp buffer %p at %s:%d\n", \
+ buf, __FILE__, __LINE__); \
+ } \
+} while (0)
+
/*
* Routine to allocate a buffer for later use by the driver.
*/
@@ -494,7 +477,7 @@ ppp_alloc_buf (int size, int type)
buf->head = 0;
buf->tail = 0;
buf->fcs = PPP_INITFCS;
-
+ buf->magic = BUFFER_MAGIC;
}
return (buf);
}
@@ -506,8 +489,10 @@ ppp_alloc_buf (int size, int type)
static void
ppp_free_buf (struct ppp_buffer *ptr)
{
- if (ptr != NULL)
+ if (ptr != NULL) {
+ CHECK_BUF_MAGIC(ptr);
kfree (ptr);
+ }
}
/*
@@ -517,11 +502,12 @@ ppp_free_buf (struct ppp_buffer *ptr)
extern inline int
lock_buffer (register struct ppp_buffer *buf)
{
- register long state;
- int flags;
+ unsigned long state;
+ unsigned long flags;
/*
* Save the current state and if free then set it to the "busy" state
*/
+ CHECK_BUF_MAGIC(buf);
save_flags (flags);
cli ();
state = buf->locked;
@@ -542,6 +528,7 @@ static int
ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
{
struct device *dev;
+ unsigned long flags;
struct ppp_buffer *new_rbuf;
struct ppp_buffer *new_wbuf;
@@ -557,7 +544,11 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
/*
* Allocate the buffer from the kernel for the data
*/
+ CHECK_PPP(0);
dev = ppp2dev (ppp);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: changedmtu %d %d\n", ppp->name,
+ new_mtu, new_mru);
mru = new_mru;
/* allow for possible escaping of every character */
mtu = (new_mtu * 2) + 20;
@@ -568,23 +559,17 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
mru += 10;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
- dev->name, new_mtu, new_mru);
-
- new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
+ new_wbuf = ppp_alloc_buf (mtu+PPP_HDRLEN, BUFFER_TYPE_DEV_WR);
new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
- new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ);
+ new_cbuf = ppp_alloc_buf (mru+PPP_HDRLEN, BUFFER_TYPE_VJ);
/*
* If the buffers failed to allocate then complain and release the partial
* allocations.
*/
if (new_wbuf == NULL || new_tbuf == NULL ||
new_rbuf == NULL || new_cbuf == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp: failed to allocate new buffers\n");
+ printk (KERN_ERR "ppp: failed to allocate new buffers\n");
ppp_free_buf (new_wbuf);
ppp_free_buf (new_tbuf);
@@ -595,6 +580,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
/*
* Update the pointers to the new buffer structures.
*/
+ save_flags(flags);
cli ();
old_wbuf = ppp->wbuf;
old_rbuf = ppp->rbuf;
@@ -606,6 +592,9 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
ppp->cbuf = new_cbuf;
ppp->tbuf = new_tbuf;
+ if (old_wbuf)
+ new_wbuf->locked = old_wbuf->locked;
+
ppp->rbuf->size -= 80; /* reserve space for vj header expansion */
dev->mem_start = (unsigned long) buf_base (new_wbuf);
@@ -629,7 +618,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
ppp->flags &= ~SC_XMIT_BUSY;
- sti ();
+ restore_flags(flags);
/*
* Release old buffer pointers
*/
@@ -647,6 +636,14 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
static void
ppp_ccp_closed (struct ppp *ppp)
{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
+ restore_flags(flags);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: ccp closed\n", ppp->name);
if (ppp->sc_xc_state) {
(*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
ppp->sc_xc_state = NULL;
@@ -671,25 +668,22 @@ ppp_release (struct ppp *ppp)
struct tty_struct *tty;
struct device *dev;
+ CHECK_PPP_MAGIC(ppp);
tty = ppp2tty (ppp);
dev = ppp2dev (ppp);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s released\n", ppp->name);
+
ppp_ccp_closed (ppp);
- /* Ensure that the pppd process is not hanging on poll() */
- wake_up_interruptible (&ppp->read_wait);
- wake_up_interruptible (&ppp->write_wait);
+ /* Ensure that the pppd process is not hanging on poll() */
+ wake_up_interruptible (&ppp->read_wait);
+ wake_up_interruptible (&ppp->write_wait);
if (tty != NULL && tty->disc_data == ppp)
tty->disc_data = NULL; /* Break the tty->ppp link */
- rtnl_lock();
- /* Strong layering violation. */
- if (dev && dev->flags & IFF_UP) {
- dev_close (dev); /* close the device properly */
- }
- rtnl_unlock();
-
ppp_free_buf (ppp->rbuf);
ppp_free_buf (ppp->wbuf);
ppp_free_buf (ppp->cbuf);
@@ -712,16 +706,18 @@ ppp_release (struct ppp *ppp)
ppp->inuse = 0;
ppp->tty = NULL;
+ ppp->backup_tty = NULL;
}
/*
- * Device callback.
+ * TTY callback.
*
- * Called when the PPP device goes down in response to an ifconfig request.
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
*/
static void
-ppp_tty_close_local (struct tty_struct *tty, int sc_xfer)
+ppp_tty_close (struct tty_struct *tty)
{
struct ppp *ppp = tty2ppp (tty);
@@ -730,24 +726,27 @@ ppp_tty_close_local (struct tty_struct *tty, int sc_xfer)
if (ppp->flags & SC_DEBUG)
printk (KERN_WARNING
"ppp: trying to close unopened tty!\n");
+ return;
+ }
+ CHECK_PPP_VOID();
+ tty->disc_data = NULL;
+ if (tty == ppp->backup_tty)
+ ppp->backup_tty = 0;
+ if (tty != ppp->tty)
+ return;
+ if (ppp->backup_tty) {
+ ppp->tty = ppp->backup_tty;
} else {
- CHECK_PPP_VOID();
- ppp->sc_xfer = sc_xfer;
+ ppp->sc_xfer = 0;
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO "ppp: channel %s closing.\n",
- ppp2dev(ppp) -> name);
+ ppp2dev(ppp)->name);
ppp_release (ppp);
MOD_DEC_USE_COUNT;
}
}
}
-static void
-ppp_tty_close (struct tty_struct *tty)
-{
- ppp_tty_close_local (tty, 0);
-}
-
/*
* TTY callback.
*
@@ -763,8 +762,7 @@ ppp_tty_open (struct tty_struct *tty)
* There should not be an existing table for this slot.
*/
if (ppp) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
+ printk (KERN_ERR
"ppp_tty_open: gack! tty already associated to %s!\n",
ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
: "unknown");
@@ -774,70 +772,72 @@ ppp_tty_open (struct tty_struct *tty)
* Allocate the structure from the system
*/
ppp = ppp_find(current->pid);
- if (ppp == NULL) {
- ppp = ppp_find(0);
- if (ppp == NULL)
- ppp = ppp_alloc();
- }
+ if (ppp != NULL) {
+ /*
+ * If we are taking over a ppp unit which is currently
+ * connected to a loopback pty, there's not much to do.
+ */
+ CHECK_PPP(-EINVAL);
+ tty->disc_data = ppp;
+ ppp->tty = tty;
- if (ppp == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: couldn't allocate ppp channel\n");
- return -ENFILE;
- }
+ } else {
+ ppp = ppp_alloc();
+ if (ppp == NULL) {
+ printk (KERN_ERR "ppp_alloc failed\n");
+ return -ENFILE;
+ }
/*
* Initialize the control block
*/
- ppp_init_ctrl_blk (ppp);
- ppp->tty = tty;
- tty->disc_data = ppp;
-/*
- * Flush any pending characters in the driver and discipline.
- */
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
-
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer (tty);
+ ppp_init_ctrl_blk (ppp);
+ tty->disc_data = ppp;
+ ppp->tty = tty;
/*
* Allocate space for the default VJ header compression slots
*/
- ppp->slcomp = slhc_init (16, 16);
- if (ppp->slcomp == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: no space for compression buffers!\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
+ ppp->slcomp = slhc_init (16, 16);
+ if (ppp->slcomp == NULL) {
+ printk (KERN_ERR "ppp_tty_open: "
+ "no space for compression buffers!\n");
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
/*
* Allocate space for the MTU and MRU buffers
*/
- if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
- ppp_release (ppp);
- return -ENOMEM;
- }
+ if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
/*
* Allocate space for a user level buffer
*/
- ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
- if (ppp->ubuf == NULL) {
+ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
+ if (ppp->ubuf == NULL) {
+ printk (KERN_ERR "ppp_tty_open: "
+ "no space for user receive buffer\n");
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
+
if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: no space for user receive buffer\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
+ printk (KERN_INFO "ppp: channel %s open\n",
+ ppp2dev(ppp)->name);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp: channel %s open\n",
- ppp2dev(ppp)->name);
+ for (indx = 0; indx < NUM_NP; ++indx)
+ ppp->sc_npmode[indx] = NPMODE_PASS;
- for (indx = 0; indx < NUM_NP; ++indx)
- ppp->sc_npmode[indx] = NPMODE_PASS;
+ MOD_INC_USE_COUNT;
+ }
+/*
+ * Flush any pending characters in the driver and discipline.
+ */
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer (tty);
- MOD_INC_USE_COUNT;
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
return (ppp->line);
}
@@ -857,16 +857,21 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
struct ppp_buffer *xbuf)
{
register int count, actual;
+ unsigned long flags;
+
+ CHECK_PPP_VOID();
+ CHECK_BUF_MAGIC(xbuf);
/*
* Prevent re-entrancy by ensuring that this routine is called only once.
*/
+ save_flags(flags);
cli ();
if (ppp->flags & SC_XMIT_BUSY) {
- sti ();
+ restore_flags(flags);
return;
}
ppp->flags |= SC_XMIT_BUSY;
- sti ();
+ restore_flags(flags);
/*
* Send the next block of data to the modem
*/
@@ -901,11 +906,8 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
* If the completed buffer came from the device write, then complete the
* transmission block.
*/
- if (ppp2dev (ppp) -> flags & IFF_UP) {
- if (xbuf->type == BUFFER_TYPE_DEV_WR)
- ppp2dev (ppp)->tbusy = 0;
- mark_bh (NET_BH);
- }
+ ppp2dev (ppp)->tbusy = 0;
+ mark_bh (NET_BH);
/*
* Wake up the transmission queue for all completion events.
*/
@@ -913,6 +915,7 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
/*
* Look at the priorities. Choose a daemon write over the device driver.
*/
+ save_flags(flags);
cli();
xbuf = ppp->s1buf;
ppp->s1buf = NULL;
@@ -920,21 +923,25 @@ ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
xbuf = ppp->s2buf;
ppp->s2buf = NULL;
}
- sti();
/*
* If there is a pending buffer then transmit it now.
*/
if (xbuf != NULL) {
ppp->flags &= ~SC_XMIT_BUSY;
ppp_kick_tty (ppp, xbuf);
+ restore_flags(flags);
return;
}
+ restore_flags(flags);
}
}
/*
* Clear the re-entry flag
*/
+ save_flags(flags); /* &=~ may not be atomic */
+ cli ();
ppp->flags &= ~SC_XMIT_BUSY;
+ restore_flags(flags);
}
/*
@@ -954,9 +961,12 @@ ppp_tty_wakeup (struct tty_struct *tty)
if (!ppp)
return;
+ CHECK_PPP_VOID();
- if (ppp->magic != PPP_MAGIC)
+ if (tty != ppp->tty) {
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
return;
+ }
/*
* Ensure that there is a transmission pending. Clear the re-entry flag if
* there is no pending buffer. Otherwise, send the buffer.
@@ -977,7 +987,10 @@ ppp_tty_wakeup (struct tty_struct *tty)
static void
ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
{
- register int flags;
+ unsigned long flags;
+
+ CHECK_PPP_VOID();
+ CHECK_BUF_MAGIC(xbuf);
/*
* Hold interrupts.
*/
@@ -1036,7 +1049,6 @@ ppp_tty_room (struct tty_struct *tty)
/*
* Callback function when data is available at the tty driver.
*/
-
static void
ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
char *flags, int count)
@@ -1044,12 +1056,18 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
register struct ppp *ppp = tty2ppp (tty);
register struct ppp_buffer *buf = NULL;
__u8 chr;
+
+ if (ppp != 0)
+ CHECK_PPP_VOID();
+ /*
+ * This can happen if stuff comes in on the backup tty.
+ */
+ if (ppp == 0 || tty != ppp->tty)
+ return;
/*
* Fetch the pointer to the buffer. Be careful about race conditions.
*/
- if (ppp != NULL)
- buf = ppp->rbuf;
-
+ buf = ppp->rbuf;
if (buf == NULL)
return;
/*
@@ -1059,7 +1077,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
if (ppp->magic != PPP_MAGIC) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
- "PPP: handler called but couldn't find "
+ "PPP: tty_receive called but couldn't find "
"PPP struct.\n");
return;
}
@@ -1078,17 +1096,25 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
ppp->bytes_rcvd++;
chr = *data++;
if (flags) {
- if (*flags && ppp->toss == 0)
+ if (*flags && ppp->toss == 0) {
ppp->toss = *flags;
+ switch (ppp->toss) {
+ case TTY_OVERRUN:
+ ++ppp->estats.rx_fifo_errors;
+ break;
+ case TTY_FRAME:
+ case TTY_BREAK:
+ ++ppp->estats.rx_frame_errors;
+ break;
+ }
+ }
++flags;
}
/*
- * Set the flags for 8 data bits and no parity.
- *
- * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
- * so that the normal processing would have all flags set at the end of the
- * session. A missing flag bit would denote an error condition.
+ * Set the flags for d7 being 0/1 and parity being even/odd so that
+ * the normal processing would have all flags set at the end of the
+ * session. A missing flag bit indicates an error condition.
*/
#ifdef CHECK_CHARACTERS
@@ -1103,13 +1129,9 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
ppp->flags |= SC_RCV_EVNP;
#endif
/*
- * Branch on the character. Process the escape character. The sequence ESC ESC
- * is defined to be ESC.
+ * Branch on the character.
*/
switch (chr) {
- case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
- ppp->escape = PPP_TRANS;
- break;
/*
* FLAG. This is the end of the block. If the block terminated by ESC FLAG,
* then the block is to be ignored. In addition, characters before the very
@@ -1123,8 +1145,8 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
* Process frames which are not to be ignored. If the processing failed,
* then clean up the VJ tables.
*/
- if ((ppp->toss & 0x80) != 0 ||
- ppp_doframe (ppp) == 0) {
+ if (ppp_doframe (ppp) == 0) {
+ ++ppp->stats.ppp_ierrors;
slhc_toss (ppp->slcomp);
}
/*
@@ -1140,17 +1162,39 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
* receive mask then ignore the character.
*/
default:
+ /* If we're tossing, look no further. */
+ if (ppp->toss != 0)
+ break;
+
+ /* If this is a control char to be ignored, do so */
if (in_rmap (ppp, chr))
break;
-/*
- * Adjust the character and if the frame is to be discarded then simply
- * ignore the character until the ending FLAG is received.
- */
- chr ^= ppp->escape;
- ppp->escape = 0;
- if (ppp->toss != 0)
+ /*
+ * Modify the next character if preceded by escape.
+ * The escape character (0x7d) could be an escaped
+ * 0x5d, if it follows an escape :-)
+ */
+ if (ppp->escape) {
+ chr ^= PPP_TRANS;
+ ppp->escape = 0;
+ } else if (chr == PPP_ESCAPE) {
+ ppp->escape = PPP_TRANS;
break;
+ }
+
+ /*
+ * Decompress A/C and protocol compression here.
+ */
+ if (buf->count == 0 && chr != PPP_ALLSTATIONS) {
+ buf_base(buf)[0] = PPP_ALLSTATIONS;
+ buf_base(buf)[1] = PPP_UI;
+ buf->count = 2;
+ }
+ if (buf->count == 2 && (chr & 1) != 0) {
+ buf_base(buf)[2] = 0;
+ buf->count = 3;
+ }
/*
* If the count sent is within reason then store the character, bump the
* count, and update the FCS for the character.
@@ -1164,13 +1208,166 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
* The peer sent too much data. Set the flags to discard the current frame
* and wait for the re-synchronization FLAG to be sent.
*/
- ppp->stats.ppp_ierrors++;
+ ++ppp->estats.rx_length_errors;
ppp->toss |= 0xC0;
break;
}
}
}
+/* on entry, a received frame is in ppp->rbuf.bufr
+ check it and dispose as appropriate */
+
+static int
+ppp_doframe (struct ppp *ppp)
+{
+ __u8 *data = buf_base (ppp->rbuf);
+ int count = ppp->rbuf->count;
+ int proto;
+ int new_count;
+ __u8 *new_data;
+
+ CHECK_PPP(0);
+ CHECK_BUF_MAGIC(ppp->rbuf);
+
+/*
+ * If there is a pending error from the receiver then log it and discard
+ * the damaged frame.
+ */
+ if (ppp->toss) {
+ if ((ppp->flags & SC_DEBUG) && count > 0)
+ printk (KERN_DEBUG
+ "ppp_toss: tossing frame, reason = %x\n",
+ ppp->toss);
+ return 0;
+ }
+/*
+ * An empty frame is ignored. This occurs if the FLAG sequence precedes and
+ * follows each frame.
+ */
+ if (count == 0)
+ return 1;
+/*
+ * Generate an error if the frame is too small.
+ */
+ if (count < PPP_HDRLEN + 2) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp: got runt ppp frame, %d chars\n", count);
+ ++ppp->estats.rx_length_errors;
+ return 0;
+ }
+/*
+ * Verify the CRC of the frame and discard the CRC characters from the
+ * end of the buffer.
+ */
+ if (ppp->rbuf->fcs != PPP_GOODFCS) {
+ if (ppp->flags & SC_DEBUG) {
+ printk (KERN_DEBUG
+ "ppp: frame with bad fcs, length = %d\n",
+ count);
+ ppp_print_buffer("bad frame", data, count);
+ }
+ ++ppp->estats.rx_crc_errors;
+ return 0;
+ }
+ count -= 2; /* ignore the fcs characters */
+/*
+ * Obtain the protocol from the frame
+ */
+ proto = PPP_PROTOCOL(data);
+/*
+ * Process the active decompressor.
+ */
+ if ((ppp->sc_rc_state != (void *) 0) &&
+ (ppp->flags & SC_DECOMP_RUN) &&
+ ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+ if (proto == PPP_COMP) {
+/*
+ * If the frame is compressed then decompress it.
+ */
+ new_data = kmalloc (ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+ if (new_data == NULL) {
+ printk (KERN_ERR "ppp_doframe: no memory\n");
+ new_count = DECOMP_ERROR;
+ } else {
+ new_count = (*ppp->sc_rcomp->decompress)
+ (ppp->sc_rc_state, data, count,
+ new_data, ppp->mru + PPP_HDRLEN);
+ }
+ switch (new_count) {
+ default:
+ ppp_doframe_lower (ppp, new_data, new_count);
+ kfree (new_data);
+ return 1;
+
+ case DECOMP_ERROR:
+ ppp->flags |= SC_DC_ERROR;
+ break;
+
+ case DECOMP_FATALERROR:
+ ppp->flags |= SC_DC_FERROR;
+ printk(KERN_ERR "ppp: fatal decomp error\n");
+ break;
+ }
+/*
+ * Log the error condition and discard the frame.
+ */
+ if (new_data != 0)
+ kfree (new_data);
+ slhc_toss (ppp->slcomp);
+ ++ppp->stats.ppp_ierrors;
+ } else {
+/*
+ * The frame is not special. Pass it through the compressor without
+ * actually compressing the data
+ */
+ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+ data, count);
+ }
+ }
+/*
+ * Process the uncompressed frame.
+ */
+ ppp_doframe_lower (ppp, data, count);
+ return 1;
+}
+
+static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
+{
+ __u16 proto = PPP_PROTOCOL (data);
+ ppp_proto_type *proto_ptr;
+
+ CHECK_PPP_VOID();
+/*
+ * Ignore empty frames
+ */
+ if (count <= PPP_HDRLEN)
+ return;
+/*
+ * Count the frame and print it
+ */
+ ++ppp->stats.ppp_ipackets;
+ if (ppp->flags & SC_LOG_INPKT)
+ ppp_print_buffer ("receive frame", data, count);
+/*
+ * Find the procedure to handle this protocol. The last one is marked
+ * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
+ */
+ proto_ptr = proto_list;
+ while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+ ++proto_ptr;
+/*
+ * Update the appropriate statistic counter.
+ */
+ if ((*proto_ptr->func) (ppp, proto,
+ &data[PPP_HDRLEN],
+ count - PPP_HDRLEN))
+ ppp->stats.ppp_ioctects += count;
+ else
+ ++ppp->stats.ppp_discards;
+}
+
/*
* Put the input frame into the networking system for the indicated protocol
*/
@@ -1199,7 +1396,7 @@ ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
/*
* Tag the frame and kick it to the proper receive routine
*/
- ppp->ddinfo.recv_idle = jiffies;
+ ppp->last_recv = jiffies;
netif_rx (skb);
return 1;
}
@@ -1211,6 +1408,7 @@ ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
static int
rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count)
{
+ CHECK_PPP(0);
if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
if (ppp->sc_npmode[NP_IP] == NPMODE_PASS)
return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
@@ -1224,6 +1422,7 @@ rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count)
static int
rcv_proto_ipx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
{
+ CHECK_PPP(0);
if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
return 0;
@@ -1237,6 +1436,7 @@ static int
rcv_proto_vjc_comp (struct ppp *ppp, __u16 proto,
__u8 *data, int count)
{
+ CHECK_PPP(0);
if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
int new_count = slhc_uncompress (ppp->slcomp, data, count);
if (new_count >= 0) {
@@ -1257,6 +1457,7 @@ static int
rcv_proto_vjc_uncomp (struct ppp *ppp, __u16 proto,
__u8 *data, int count)
{
+ CHECK_PPP(0);
if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
if (slhc_remember (ppp->slcomp, data, count) > 0) {
return rcv_proto_ip (ppp, PPP_IP, data, count);
@@ -1287,6 +1488,7 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
goto failure; \
}
+ CHECK_PPP(0);
/*
* The total length includes the protocol data.
* Lock the user information buffer.
@@ -1294,8 +1496,9 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
if (test_and_set_bit (0, &ppp->ubuf->locked)) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
- "ppp_us_queue: can't get lock\n");
+ "ppp: rcv_proto_unknown: can't get lock\n");
} else {
+ CHECK_BUF_MAGIC(ppp->ubuf);
current_idx = ppp->ubuf->head;
/*
* Insert the buffer length (not counted), the protocol, and the data
@@ -1323,11 +1526,6 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
if (ppp->tty->fasync != NULL)
kill_fasync (ppp->tty->fasync, SIGIO);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp: successfully queued %d bytes, flags = %x\n",
- len + 2, ppp->flags);
-
return 1;
/*
* The buffer is full. Unlock the header
@@ -1335,16 +1533,15 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
failure:
clear_bit (0, &ppp->ubuf->locked);
if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_us_queue: ran out of buffer space.\n");
+ printk (KERN_DEBUG
+ "ppp: rcv_proto_unknown: buffer overflow\n");
}
/*
* Discard the frame. There are no takers for this protocol.
*/
if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp: dropping packet on the floor.\n");
- slhc_toss (ppp->slcomp);
+ printk (KERN_DEBUG
+ "ppp: rcv_proto_unknown: dropping packet\n");
return 0;
}
@@ -1361,10 +1558,12 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
int slen = CCP_LENGTH(dp);
__u8 *opt = dp + CCP_HDRLEN;
int opt_len = slen - CCP_HDRLEN;
+ unsigned long flags;
if (slen > len)
return;
+ save_flags(flags);
switch (CCP_CODE(dp)) {
case CCP_CONFREQ:
case CCP_TERMREQ:
@@ -1373,6 +1572,7 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
* CCP must be going down - disable compression
*/
if (ppp->flags & SC_CCP_UP) {
+ cli();
ppp->flags &= ~(SC_CCP_UP |
SC_COMP_RUN |
SC_DECOMP_RUN);
@@ -1401,8 +1601,13 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
opt_len,
ppp2dev (ppp)->base_addr,
0,
- ppp->flags))
+ ppp->flags & SC_DEBUG)) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp running\n",
+ ppp->name);
+ cli();
ppp->flags |= SC_COMP_RUN;
+ }
break;
}
/*
@@ -1418,34 +1623,48 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
ppp2dev (ppp)->base_addr,
0,
ppp->mru,
- ppp->flags)) {
+ ppp->flags & SC_DEBUG)) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp running\n",
+ ppp->name);
+ cli();
ppp->flags |= SC_DECOMP_RUN;
ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
}
break;
/*
- * The protocol sequence is complete at this end
+ * CCP Reset-ack resets compressors and decompressors as it passes through.
*/
case CCP_RESETACK:
if ((ppp->flags & SC_CCP_UP) == 0)
break;
if (!rcvd) {
- if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
+ if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) {
(*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp reset\n",
+ ppp->name);
+ }
} else {
if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
(*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
- ppp->flags &= ~SC_DC_ERROR;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp reset\n",
+ ppp->name);
+ cli();
+ ppp->flags &= ~SC_DC_ERROR;
}
}
break;
}
+ restore_flags(flags);
}
static int
rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len)
{
+ CHECK_PPP(0);
ppp_proto_ccp (ppp, dp, len, 1);
return rcv_proto_unknown (ppp, proto, dp, len);
}
@@ -1460,197 +1679,6 @@ rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
return rcv_proto_unknown (ppp, proto, data, len);
}
-/* on entry, a received frame is in ppp->rbuf.bufr
- check it and dispose as appropriate */
-
-static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
-{
- __u16 proto = PPP_PROTOCOL (data);
- ppp_proto_type *proto_ptr;
-
-/*
- * Ignore empty frames
- */
- if (count <= 4)
- return;
-/*
- * Count the frame and print it
- */
- ++ppp->stats.ppp_ipackets;
- if (ppp->flags & SC_LOG_INPKT)
- ppp_print_buffer ("receive frame", data, count);
-/*
- * Find the procedure to handle this protocol. The last one is marked
- * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
- */
- proto_ptr = proto_list;
- while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
- ++proto_ptr;
-/*
- * Update the appropriate statistic counter.
- */
- if ((*proto_ptr->func) (ppp, proto,
- &data[PPP_HARD_HDR_LEN],
- count - PPP_HARD_HDR_LEN))
- ppp->stats.ppp_ioctects += count;
- else
- ++ppp->stats.ppp_discards;
-}
-
-/* on entry, a received frame is in ppp->rbuf.bufr
- check it and dispose as appropriate */
-
-static int
-ppp_doframe (struct ppp *ppp)
-{
- __u8 *data = buf_base (ppp->rbuf);
- int count = ppp->rbuf->count;
- int addr, ctrl, proto;
- int new_count;
- __u8 *new_data;
-
-/*
- * If there is a pending error from the receiver then log it and discard
- * the damaged frame.
- */
- if (ppp->toss) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_toss: tossing frame, reason = %d\n",
- ppp->toss);
- ppp->stats.ppp_ierrors++;
- return 0;
- }
-/*
- * An empty frame is ignored. This occurs if the FLAG sequence precedes and
- * follows each frame.
- */
- if (count == 0)
- return 1;
-/*
- * Generate an error if the frame is too small.
- */
- if (count < PPP_HARD_HDR_LEN) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp: got runt ppp frame, %d chars\n", count);
- slhc_toss (ppp->slcomp);
- ppp->stats.ppp_ierrors++;
- return 1;
- }
-/*
- * Verify the CRC of the frame and discard the CRC characters from the
- * end of the buffer.
- */
- if (ppp->rbuf->fcs != PPP_GOODFCS) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp: frame with bad fcs, excess = %x\n",
- ppp->rbuf->fcs ^ PPP_GOODFCS);
- ppp->stats.ppp_ierrors++;
- return 0;
- }
- count -= 2; /* ignore the fcs characters */
-/*
- * Ignore the leading ADDRESS and CONTROL fields in the frame.
- */
- addr = PPP_ALLSTATIONS;
- ctrl = PPP_UI;
-
- if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
- data += 2;
- count -= 2;
- }
-/*
- * Obtain the protocol from the frame
- */
- proto = (__u16) *data++;
- if ((proto & 1) == 0) {
- proto = (proto << 8) | (__u16) *data++;
- --count;
- }
-/*
- * Rewrite the header with the full information. This may encroach upon
- * the 'filler' area in the buffer header. This is the purpose for the
- * filler.
- */
- *(--data) = proto;
- *(--data) = proto >> 8;
- *(--data) = ctrl;
- *(--data) = addr;
- count += 3;
-/*
- * Process the active decompressor.
- */
- if ((ppp->sc_rc_state != (void *) 0) &&
- (ppp->flags & SC_DECOMP_RUN) &&
- ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
- if (proto == PPP_COMP) {
-/*
- * If the frame is compressed then decompress it.
- */
- new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
- if (new_data == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_doframe: no memory\n");
- slhc_toss (ppp->slcomp);
- (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
- data,
- count);
- return 1;
- }
-/*
- * Decompress the frame
- */
- new_count = bsd_decompress (ppp->sc_rc_state,
- data,
- count,
- new_data,
- ppp->mru + 4);
- switch (new_count) {
- default:
- ppp_doframe_lower (ppp, new_data, new_count);
- kfree (new_data);
- return 1;
-
- case DECOMP_OK:
- break;
-
- case DECOMP_ERROR:
- ppp->flags |= SC_DC_ERROR;
- break;
-
- case DECOMP_FATALERROR:
- ppp->flags |= SC_DC_FERROR;
- break;
- }
-/*
- * Log the error condition and discard the frame.
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_proto_comp: "
- "decompress err %d\n", new_count);
- kfree (new_data);
- slhc_toss (ppp->slcomp);
- return 1;
- }
-/*
- * The frame is not special. Pass it through the compressor without
- * actually compressing the data
- */
- (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
- data,
- count);
- }
-/*
- * Process the uncompressed frame.
- */
- ppp_doframe_lower (ppp, data, count);
- return 1;
-}
-
/*************************************************************
* LINE DISCIPLINE SUPPORT
* The following functions form support user programs
@@ -1668,7 +1696,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
{
struct ppp *ppp = tty2ppp (tty);
__u8 c;
- ssize_t len, indx;
+ int error;
+ ssize_t len, ret;
#define GETC(c) \
{ \
@@ -1682,28 +1711,34 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
if (!ppp)
return -EIO;
- if (ppp->magic != PPP_MAGIC)
- return -EIO;
+ /* if (ppp->magic != PPP_MAGIC)
+ return -EIO; */
CHECK_PPP (-ENXIO);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: called buf=%p nr=%lu\n",
- buf, (unsigned long)nr);
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * user has access to the pages for the total buffer length.
+ */
+ error = verify_area (VERIFY_WRITE, buf, nr);
+ if (error != 0)
+ return (error);
+
/*
* Acquire the read lock.
*/
for (;;) {
ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+ || tty != ppp->tty)
return 0;
if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
+#if 0
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"ppp_tty_read: sleeping(ubuf)\n");
-
+#endif
current->timeout = 0;
current->state = TASK_INTERRUPTIBLE;
schedule ();
@@ -1712,13 +1747,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
return -EINTR;
continue;
}
-/*
- * Before we attempt to write the frame to the user, ensure that the
- * user has access to the pages for the total buffer length.
- */
- indx = verify_area (VERIFY_WRITE, buf, nr);
- if (indx != 0)
- return (indx);
+
/*
* Fetch the length of the buffer from the first two bytes.
*/
@@ -1729,90 +1758,77 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, size_t nr)
len = c << 8;
GETC (c);
len += c;
+ if (len)
+ break;
}
-/*
- * If there is no length then wait for the data to arrive.
- */
- if (len == 0) {
- /* no data */
- clear_bit (0, &ppp->ubuf->locked);
- if (file->f_flags & O_NONBLOCK) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: no data "
- "(EAGAIN)\n");
- return -EAGAIN;
- }
- current->timeout = 0;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(read_wait)\n");
-
- interruptible_sleep_on (&ppp->read_wait);
- if (signal_pending(current))
- return -EINTR;
- continue;
- }
/*
- * Reset the time of the last read operation.
+ * If there is no length then wait for the data to arrive.
*/
+ /* no data */
+ clear_bit (0, &ppp->ubuf->locked);
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ current->timeout = 0;
+#if 0
if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_tty_read: len = %ld\n",
- (long)len);
+ printk (KERN_DEBUG
+ "ppp_tty_read: sleeping(read_wait)\n");
+#endif
+ interruptible_sleep_on (&ppp->read_wait);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+
/*
* Ensure that the frame will fit within the caller's buffer. If not, then
* discard the frame from the input buffer.
*/
- if (len + 2 > nr) {
- /* Can't copy it, update us_rbuff_head */
+ if (len + 2 > nr) {
+ /* Can't copy it, update us_rbuff_head */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
"ppp: read of %lu bytes too small for %ld "
- "frame\n", (unsigned long)nr, (long)len + 2);
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- ppp->stats.ppp_ierrors++;
- return -EOVERFLOW;
- }
-/*
- * Before we attempt to write the frame to the user, ensure that the
- * page tables are proper.
- */
- indx = verify_area (VERIFY_WRITE, buf, len + 2);
- if (indx != 0) {
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- return (indx);
- }
+ "frame\n", (unsigned long) nr, (long) len + 2);
+ ppp->stats.ppp_ierrors++;
+ error = -EOVERFLOW;
+ goto out;
+ }
+
/*
* Fake the insertion of the ADDRESS and CONTROL information because these
* were not saved in the buffer.
*/
- put_user (PPP_ALLSTATIONS, buf++);
- put_user (PPP_UI, buf++);
+ error = put_user((u_char) PPP_ALLSTATIONS, buf);
+ if (error)
+ goto out;
+ ++buf;
+ error = put_user((u_char) PPP_UI, buf);
+ if (error)
+ goto out;
+ ++buf;
- indx = len;
/*
* Copy the received data from the buffer to the caller's area.
*/
- while (indx-- > 0) {
- GETC (c);
- put_user (c, buf);
- ++buf;
- }
-
- clear_bit (0, &ppp->ubuf->locked);
- len += 2; /* Account for ADDRESS and CONTROL bytes */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: passing %ld bytes up\n",
- (long) len);
- return len;
+ ret = len + 2; /* Account for ADDRESS and CONTROL bytes */
+ while (len-- > 0) {
+ GETC (c);
+ error = put_user(c, buf);
+ if (error)
+ goto out;
+ ++buf;
}
+
+ clear_bit (0, &ppp->ubuf->locked);
+ return ret;
+
+out:
+ ppp->ubuf->tail += len;
+ ppp->ubuf->tail &= ppp->ubuf->size;
+ clear_bit (0, &ppp->ubuf->locked);
+ return error;
#undef GETC
}
@@ -1829,7 +1845,7 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
*/
if (ppp->flags & SC_DEBUG) {
if ((buf->count < 0) || (buf->count > 3000))
- printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+ printk (KERN_DEBUG "ppp_stuff_char: %d %x\n",
(unsigned int) buf->count,
(unsigned int) chr);
}
@@ -1859,6 +1875,12 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
__u16 write_fcs;
int address, control;
int proto;
+
+ CHECK_PPP_VOID();
+ CHECK_BUF_MAGIC(buf);
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+
/*
* Insert the leading FLAG character
*/
@@ -1867,7 +1889,7 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
if (non_ip || flag_time == 0)
ins_char (buf, PPP_FLAG);
else {
- if (jiffies - ppp->last_xmit > flag_time)
+ if (jiffies - ppp->last_xmit >= flag_time)
ins_char (buf, PPP_FLAG);
}
ppp->last_xmit = jiffies;
@@ -1906,27 +1928,11 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
write_fcs = buf->fcs ^ 0xFFFF;
ppp_stuff_char (ppp, buf, write_fcs);
ppp_stuff_char (ppp, buf, write_fcs >> 8);
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
- write_fcs);
/*
* Add the trailing flag character
*/
ins_char (buf, PPP_FLAG);
/*
- * Print the buffer
- */
- if (ppp->flags & SC_LOG_FLUSH)
- ppp_print_buffer ("ppp flush", buf_base (buf),
- buf->count);
- else {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_dev_xmit: writing %d chars\n",
- buf->count);
- }
-/*
* Send the block to the tty driver.
*/
ppp->stats.ppp_obytes += buf->count;
@@ -1934,7 +1940,7 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
}
/*
- * Send an frame to the remote with the proper bsd compression.
+ * Compress and send an frame to the peer.
*
* Return 0 if frame was queued for transmission.
* 1 if frame must be re-queued for later driver support.
@@ -1948,6 +1954,9 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
int address, control;
__u8 *new_data;
int new_count;
+
+ CHECK_PPP(0);
+ CHECK_BUF_MAGIC(buf);
/*
* Print the buffer
*/
@@ -1967,7 +1976,7 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
(control == PPP_UI) &&
(proto != PPP_LCP) &&
(proto != PPP_CCP)) {
- new_data = kmalloc (count, GFP_ATOMIC);
+ new_data = kmalloc (ppp->mtu, GFP_ATOMIC);
if (new_data == NULL) {
if (ppp->flags & SC_DEBUG)
printk (KERN_ERR
@@ -1975,33 +1984,21 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
return 1;
}
- new_count = bsd_compress (ppp->sc_xc_state,
- data,
- new_data,
- count,
- count);
-
- if (new_count > 0) {
- ++ppp->stats.ppp_opackets;
- ppp->stats.ppp_ooctects += new_count;
+ new_count = (*ppp->sc_xcomp->compress)
+ (ppp->sc_xc_state, data, new_data, count, ppp->mtu);
- ppp_dev_xmit_lower (ppp, buf, new_data,
- new_count, 0);
+ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
+ ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
kfree (new_data);
return 0;
}
/*
- * The frame could not be compressed.
+ * The frame could not be compressed, or it could not be sent in
+ * compressed form because CCP is not yet up.
*/
kfree (new_data);
}
/*
- * The frame may not be compressed. Update the statistics before the
- * count field is destroyed. The frame will be transmitted.
- */
- ++ppp->stats.ppp_opackets;
- ppp->stats.ppp_ooctects += count;
-/*
* Go to the escape encoding
*/
ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
@@ -2033,8 +2030,8 @@ send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
*/
case PPP_CCP:
ppp_proto_ccp (ppp,
- data + PPP_HARD_HDR_LEN,
- len - PPP_HARD_HDR_LEN,
+ data + PPP_HDRLEN,
+ len - PPP_HDRLEN,
0);
break;
@@ -2056,70 +2053,77 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
{
struct ppp *ppp = tty2ppp (tty);
__u8 *new_data;
- ssize_t status;
+ int error;
+ struct wait_queue wait = {current, NULL};
+
/*
* Verify the pointers.
*/
+ error = -EIO;
if (!ppp)
- return -EIO;
-
+ goto out;
if (ppp->magic != PPP_MAGIC)
- return -EIO;
+ goto out;
CHECK_PPP (-ENXIO);
/*
* Ensure that the caller does not wish to send too much.
*/
- if (count > PPP_MTU) {
+ if (count > PPP_MTU + PPP_HDRLEN) {
if (ppp->flags & SC_DEBUG)
printk (KERN_WARNING
"ppp_tty_write: truncating user packet "
- "from %lu to mtu %d\n",
- (unsigned long) count, PPP_MTU);
- count = PPP_MTU;
+ "from %lu to mtu %d\n", (unsigned long) count,
+ PPP_MTU + PPP_HDRLEN);
+ count = PPP_MTU + PPP_HDRLEN;
}
/*
* Allocate a buffer for the data and fetch it from the user space.
*/
new_data = kmalloc (count, GFP_KERNEL);
if (new_data == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_write: no memory\n");
+ printk (KERN_ERR "ppp_tty_write: no memory\n");
return 0;
}
/*
- * lock this PPP unit so we will be the only writer;
- * sleep if necessary
+ * Retrieve the user's buffer
+ */
+ error = -EFAULT;
+ if (copy_from_user(new_data, data, count))
+ goto out_free;
+/*
+ * Lock this PPP unit so we will be the only writer,
+ * sleeping if necessary.
+ *
+ * Note that we add our task to the wait queue before
+ * attempting to lock, as the lock flag may be cleared
+ * from an interrupt.
*/
- while (lock_buffer (ppp->tbuf) != 0) {
+ add_wait_queue(&ppp->write_wait, &wait);
+ while (1) {
+ error = 0;
current->timeout = 0;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
- interruptible_sleep_on (&ppp->write_wait);
+ current->state = TASK_INTERRUPTIBLE;
+ if (lock_buffer(ppp->tbuf) == 0)
+ break;
+ schedule();
+ error = -EINVAL;
ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
- kfree (new_data);
- return 0;
- }
-
- if (signal_pending(current)) {
- kfree (new_data);
- return -EINTR;
+ if (!ppp || ppp->magic != PPP_MAGIC ||
+ !ppp->inuse || tty != ppp->tty) {
+ printk("ppp_tty_write: %p invalid after wait!\n", ppp);
+ break;
}
+ error = -EINTR;
+ if (signal_pending(current))
+ break;
}
-/*
- * Ensure that the caller's buffer is valid.
- */
- status = verify_area (VERIFY_READ, data, count);
- if (status != 0) {
- kfree (new_data);
- ppp->tbuf->locked = 0;
- return status;
- }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&ppp->write_wait, &wait);
+ if (error)
+ goto out_free;
- copy_from_user (new_data, data, count);
/*
* Change the LQR frame
*/
@@ -2127,9 +2131,24 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
/*
* Send the data
*/
- ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+ if (PPP_PROTOCOL(new_data) == PPP_IP) {
+ /*
+ * IP frames can be sent by pppd when we're doing
+ * demand-dialling. We send them via ppp_dev_xmit_ip
+ * to make sure that VJ compression happens properly.
+ */
+ ppp_dev_xmit_ip(ppp, ppp->tbuf, new_data + PPP_HDRLEN,
+ count - PPP_HDRLEN, NPMODE_PASS);
+
+ } else {
+ ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+ }
+ error = count;
+
+out_free:
kfree (new_data);
- return count;
+out:
+ return error;
}
/*
@@ -2140,74 +2159,92 @@ static int
ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
{
struct compressor *cp;
- struct ppp_option_data data;
- int error;
- int nb;
+ int error, nb;
+ unsigned long flags;
__u8 *ptr;
__u8 ccp_option[CCP_MAX_OPTION_LENGTH];
+ struct ppp_option_data data;
+
/*
* Fetch the compression parameters
*/
- error = verify_area (VERIFY_READ, odp, sizeof (data));
- if (error == 0) {
- copy_from_user (&data, odp, sizeof (data));
- nb = data.length;
- ptr = data.ptr;
- if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
- nb = CCP_MAX_OPTION_LENGTH;
+ error = -EFAULT;
+ if (copy_from_user(&data, odp, sizeof (data)))
+ goto out;
- error = verify_area (VERIFY_READ, ptr, nb);
- if(!error)
- copy_from_user (ccp_option, ptr, nb);
- }
- if (error != 0)
- return error;
+ nb = data.length;
+ ptr = data.ptr;
+ if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
+ nb = CCP_MAX_OPTION_LENGTH;
+
+ if (copy_from_user(ccp_option, ptr, nb))
+ goto out;
+ error = -EINVAL;
if (ccp_option[1] < 2) /* preliminary check on the length byte */
- return (-EINVAL);
+ goto out;
- cp = find_compressor ((int) (unsigned int) (__u8) ccp_option[0]);
- if (cp != (struct compressor *) 0) {
- /*
- * Found a handler for the protocol - try to allocate
- * a compressor or decompressor.
- */
- error = 0;
- if (data.transmit) {
- if (ppp->sc_xc_state != NULL)
- (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+ save_flags(flags);
+ cli();
+ ppp->flags &= ~(SC_COMP_RUN | SC_DECOMP_RUN);
+ restore_flags(flags);
- ppp->sc_xcomp = cp;
- ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+ cp = find_compressor (ccp_option[0]);
+#ifdef CONFIG_KERNELD
+ if (cp == NULL) {
+ char modname[32];
+ sprintf(modname, "ppp-compress-%d", ccp_option[0]);
+ request_module(modname);
+ cp = find_compressor(ccp_option[0]);
+ }
+#endif /* CONFIG_KERNELD */
+
+ if (cp == NULL)
+ goto out_no_comp;
+ /*
+ * Found a handler for the protocol - try to allocate
+ * a compressor or decompressor.
+ */
+ error = 0;
+ if (data.transmit) {
+ if (ppp->sc_xc_state != NULL)
+ (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+ ppp->sc_xc_state = NULL;
- if (ppp->sc_xc_state == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk("ppp%ld: comp_alloc failed\n",
- ppp2dev (ppp)->base_addr);
- error = -ENOBUFS;
- }
- ppp->flags &= ~SC_COMP_RUN;
- } else {
- if (ppp->sc_rc_state != NULL)
- (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
- ppp->sc_rcomp = cp;
- ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
- if (ppp->sc_rc_state == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk("ppp%ld: decomp_alloc failed\n",
- ppp2dev (ppp)->base_addr);
- error = ENOBUFS;
- }
- ppp->flags &= ~SC_DECOMP_RUN;
- }
- return (error);
- }
+ ppp->sc_xcomp = cp;
+ ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+ if (ppp->sc_xc_state == NULL) {
+ printk(KERN_WARNING "%s: comp_alloc failed\n",
+ ppp->name);
+ error = -ENOBUFS;
+ } else if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp_alloc -> %p\n",
+ ppp->name, ppp->sc_xc_state);
+ } else {
+ if (ppp->sc_rc_state != NULL)
+ (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+ ppp->sc_rcomp = cp;
+ ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+ if (ppp->sc_rc_state == NULL) {
+ printk(KERN_WARNING "%s: decomp_alloc failed\n",
+ ppp->name);
+ error = -ENOBUFS;
+ } else if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp_alloc -> %p\n",
+ ppp->name, ppp->sc_rc_state);
+ }
+out:
+ return error;
+
+out_no_comp:
+ error = -EINVAL; /* no handler found */
if (ppp->flags & SC_DEBUG)
- printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
- ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
- ccp_option[2], nb);
- return (-EINVAL); /* no handler found */
+ printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n",
+ ppp->name, ccp_option[0], ccp_option[1],
+ ccp_option[2], nb);
+ goto out;
}
/*
@@ -2241,57 +2278,45 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
*/
switch (param2) {
case PPPIOCSMRU:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (temp_i, (int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set mru to %x\n", temp_i);
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set mru to %x\n", temp_i);
- if (ppp->mru != temp_i)
- ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
- }
+ if (ppp->mru != temp_i)
+ ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
break;
/*
* Fetch the flags
*/
case PPPIOCGFLAGS:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- temp_i = (ppp->flags & SC_MASK);
+ temp_i = (ppp->flags & SC_MASK);
#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
- temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
- SC_RCV_ODDP | SC_RCV_EVNP;
+ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+ SC_RCV_ODDP | SC_RCV_EVNP;
#endif
- put_user (temp_i, (int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_ioctl: get flags: addr %lx flags "
- "%x\n", param3, temp_i);
- }
+ error = put_user(temp_i, (int *) param3);
break;
/*
* Set the flags for the various options
*/
case PPPIOCSFLAGS:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (temp_i, (int *) param3);
- temp_i &= SC_MASK;
- temp_i |= (ppp->flags & ~SC_MASK);
-
- if ((ppp->flags & SC_CCP_OPEN) &&
- (temp_i & SC_CCP_OPEN) == 0)
- ppp_ccp_closed (ppp);
-
- if ((ppp->flags | temp_i) & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set flags to %x\n", temp_i);
- ppp->flags = temp_i;
- }
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ temp_i &= SC_MASK;
+ temp_i |= (ppp->flags & ~SC_MASK);
+
+ if ((ppp->flags & SC_CCP_OPEN) &&
+ (temp_i & SC_CCP_OPEN) == 0)
+ ppp_ccp_closed (ppp);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
break;
/*
* Set the compression mode
@@ -2304,157 +2329,122 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
* Retrieve the transmit async map
*/
case PPPIOCGASYNCMAP:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- put_user (ppp->xmit_async_map[0], (int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get asyncmap: addr "
- "%lx asyncmap %x\n",
- param3,
- ppp->xmit_async_map[0]);
- }
+ error = put_user(ppp->xmit_async_map[0], (int *) param3);
break;
/*
* Set the transmit async map
*/
case PPPIOCSASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (ppp->xmit_async_map[0],(int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set xmit asyncmap %x\n",
- ppp->xmit_async_map[0]);
- }
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ ppp->xmit_async_map[0] = temp_i;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set xmit asyncmap %x\n",
+ ppp->xmit_async_map[0]);
break;
/*
* Set the receive async map
*/
case PPPIOCSRASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (ppp->recv_async_map,(int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set rcv asyncmap %x\n",
- ppp->recv_async_map);
- }
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ ppp->recv_async_map = temp_i;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set rcv asyncmap %x\n",
+ ppp->recv_async_map);
break;
/*
* Obtain the unit number for this device.
*/
case PPPIOCGUNIT:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- put_user (ppp2dev (ppp)->base_addr, (int *) param3);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get unit: %ld",
- ppp2dev (ppp)->base_addr);
- }
+ error = put_user(ppp2dev (ppp)->base_addr, (int *) param3);
+ if (error != 0)
+ break;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get unit: %ld\n",
+ ppp2dev (ppp)->base_addr);
break;
/*
* Set the debug level
*/
case PPPIOCSDEBUG:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (temp_i, (int *) param3);
- temp_i = (temp_i & 0x1F) << 16;
- temp_i |= (ppp->flags & ~0x1F0000);
-
- if ((ppp->flags | temp_i) & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set flags to %x\n", temp_i);
- ppp->flags = temp_i;
- }
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ temp_i = (temp_i & 0x1F) << 16;
+ temp_i |= (ppp->flags & ~0x1F0000);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
break;
/*
* Get the debug level
*/
case PPPIOCGDEBUG:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- temp_i = (ppp->flags >> 16) & 0x1F;
- put_user (temp_i, (int *) param3);
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get debug level %d\n",
- temp_i);
- }
+ temp_i = (ppp->flags >> 16) & 0x1F;
+ error = put_user(temp_i, (int *) param3);
break;
/*
* Get the times since the last send/receive frame operation
*/
case PPPIOCGIDLE:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (struct ppp_idle));
- if (error == 0) {
+ {
struct ppp_idle cur_ddinfo;
- unsigned long cur_jiffies = jiffies;
/* change absolute times to relative times. */
- cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
- cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
- copy_to_user ((void *) param3, &cur_ddinfo,
- sizeof (cur_ddinfo));
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: read demand dial info\n");
+ cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ error = -EFAULT;
+ if (!copy_to_user((void *) param3, &cur_ddinfo,
+ sizeof (cur_ddinfo)))
+ error = 0;
}
break;
/*
* Retrieve the extended async map
*/
case PPPIOCGXASYNCMAP:
- error = verify_area (VERIFY_WRITE,
- (void *) param3,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
- copy_to_user ((void *) param3,
- ppp->xmit_async_map,
- sizeof (ppp->xmit_async_map));
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
- param3);
- }
+ error = -EFAULT;
+ if (!copy_to_user((void *) param3, ppp->xmit_async_map,
+ sizeof (ppp->xmit_async_map)))
+ error = 0;
break;
/*
* Set the async extended map
*/
case PPPIOCSXASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
+ {
__u32 temp_tbl[8];
- copy_from_user (temp_tbl, (void *) param3,
- sizeof (ppp->xmit_async_map));
+ error = -EFAULT;
+ if (copy_from_user(temp_tbl, (void *) param3,
+ sizeof (temp_tbl)))
+ break;
+
temp_tbl[1] = 0x00000000;
temp_tbl[2] &= ~0x40000000;
temp_tbl[3] |= 0x60000000;
+ error = 0;
if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
(temp_tbl[4] & temp_tbl[5]) != 0 ||
(temp_tbl[6] & temp_tbl[7]) != 0)
error = -EINVAL;
else {
- memcpy (ppp->xmit_async_map, temp_tbl,
+ memcpy (ppp->xmit_async_map,
+ temp_tbl,
sizeof (ppp->xmit_async_map));
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
- "ppp_tty_ioctl: set xasyncmap\n");
+ "ppp_tty_ioctl: set xasyncmap\n");
}
}
break;
@@ -2462,75 +2452,65 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
* Set the maximum VJ header compression slot number.
*/
case PPPIOCSMAXCID:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- get_user (temp_i, (int *) param3);
- ++temp_i;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set maxcid to %d\n",
- temp_i);
- if (ppp->slcomp != NULL)
- slhc_free (ppp->slcomp);
- ppp->slcomp = slhc_init (16, temp_i);
-
- if (ppp->slcomp == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp: no space for compression buffers!\n");
- ppp_release (ppp);
- error = -ENOMEM;
- }
+ error = get_user(temp_i, (int *) param3);
+ if (error != 0)
+ break;
+ temp_i = (temp_i & 255) + 1;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set maxcid to %d\n", temp_i);
+ if (ppp->slcomp != NULL)
+ slhc_free (ppp->slcomp);
+ ppp->slcomp = NULL;
+
+ ppp->slcomp = slhc_init (16, temp_i);
+ if (ppp->slcomp == NULL) {
+ printk (KERN_ERR "ppp_tty_ioctl: "
+ "no space for compression buffers!\n");
+ ppp_release (ppp);
+ error = -ENOMEM;
}
break;
case PPPIOCXFERUNIT:
- ppp_tty_close_local (tty, current->pid);
+ ppp->backup_tty = tty;
+ ppp->sc_xfer = current->pid;
break;
case PPPIOCGNPMODE:
case PPPIOCSNPMODE:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (struct npioctl));
- if (error == 0) {
+ {
struct npioctl npi;
- copy_from_user (&npi,
- (void *) param3,
- sizeof (npi));
- switch (npi.protocol) {
- case PPP_IP:
- npi.protocol = NP_IP;
+ error = -EFAULT;
+ if (copy_from_user(&npi, (void *) param3, sizeof(npi)))
break;
- default:
- error = -EINVAL;
- }
- if (error != 0)
+ if (npi.protocol != PPP_IP) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "pppioc[gs]npmode: "
+ "invalid protocol %d\n",
+ npi.protocol);
+ error = -EINVAL;
break;
+ }
+ npi.protocol = NP_IP;
if (param2 == PPPIOCGNPMODE) {
npi.mode = ppp->sc_npmode[npi.protocol];
- error = verify_area (VERIFY_WRITE,
- (void *) param3,
- sizeof (npi));
- if (error != 0)
+ if (copy_to_user((void *) param3, &npi,
+ sizeof (npi)))
break;
-
- copy_to_user ((void *) param3,
- &npi,
- sizeof (npi));
- break;
}
- if (npi.mode != ppp->sc_npmode[npi.protocol]) {
- ppp->sc_npmode[npi.protocol] = npi.mode;
- if (npi.mode != NPMODE_QUEUE) {
- /* ppp_requeue(ppp); maybe needed */
- ppp_tty_wakeup (ppp2tty(ppp));
- }
- }
+ ppp->sc_npmode[npi.protocol] = npi.mode;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "ppp: set np %d to %d\n",
+ npi.protocol, npi.mode);
+ /* N.B. Why is the busy flag cleared here? */
+ ppp2dev(ppp)->tbusy = 0;
+ mark_bh(NET_BH);
+ error = 0;
}
break;
/*
@@ -2542,15 +2522,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
break;
case FIONREAD:
- error = verify_area (VERIFY_WRITE,
- (void *) param3,
- sizeof (int));
- if (error == 0) {
+ {
int count = ppp->ubuf->tail - ppp->ubuf->head;
if (count < 0)
count += (ppp->ubuf->size + 1);
-
- put_user (count, (int *) param3);
+ error = put_user(count, (int *) param3);
}
break;
/*
@@ -2558,11 +2534,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
*/
default:
if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
- param2,
- param3);
-
+ printk (KERN_WARNING "ppp_tty_ioctl: "
+ "invalid ioctl=%x, addr=%lx\n", param2, param3);
error = -ENOIOCTLCMD;
break;
}
@@ -2581,13 +2554,14 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
struct ppp *ppp = tty2ppp (tty);
unsigned int mask = 0;
- if(ppp && ppp->magic == PPP_MAGIC) {
+ if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) {
CHECK_PPP (0);
- poll_wait(&ppp->read_wait, wait);
- poll_wait(&ppp->write_wait, wait);
+ poll_wait(filp, &ppp->read_wait, wait);
+ poll_wait(filp, &ppp->write_wait, wait);
/* Must lock the user buffer area while checking. */
+ CHECK_BUF_MAGIC(ppp->ubuf);
if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) {
if(ppp->ubuf->head != ppp->ubuf->tail)
mask |= POLLIN | POLLRDNORM;
@@ -2621,8 +2595,7 @@ ppp_dev_open (struct device *dev)
struct ppp *ppp = dev2ppp (dev);
if (ppp2tty (ppp) == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
+ printk (KERN_ERR
"ppp: %s not connected to a TTY! can't go open!\n",
dev->name);
return -ENXIO;
@@ -2647,10 +2620,6 @@ ppp_dev_close (struct device *dev)
struct ppp *ppp = dev2ppp (dev);
if (ppp2tty (ppp) == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp: %s not connected to a TTY! can't go down!\n",
- dev->name);
return -ENXIO;
}
/*
@@ -2673,20 +2642,14 @@ static int
ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
{
int error;
- int len;
- char *result;
-/*
- * Must have write access to the buffer.
- */
- result = (char *) ifr->ifr_ifru.ifru_data;
- len = strlen (szVersion) + 1;
- error = verify_area (VERIFY_WRITE, result, len);
+ char *result = (char *) ifr->ifr_ifru.ifru_data;
+ int len = strlen (szVersion) + 1;
/*
* Move the version data
*/
- if (error == 0)
- copy_to_user (result, szVersion, len);
-
+ error = -EFAULT;
+ if (!copy_to_user(result, szVersion, len))
+ error = 0;
return error;
}
@@ -2700,18 +2663,11 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
struct ppp_stats *result, temp;
int error;
/*
- * Must have write access to the buffer.
- */
- result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
- error = verify_area (VERIFY_WRITE,
- result,
- sizeof (temp));
-/*
* Supply the information for the caller. First move the version data
* then move the ppp stats; and finally the vj stats.
*/
memset (&temp, 0, sizeof(temp));
- if (error == 0 && dev->flags & IFF_UP) {
+ if (dev->flags & IFF_UP) {
memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
if (ppp->slcomp != NULL) {
temp.vj.vjs_packets = ppp->slcomp->sls_o_compressed+
@@ -2726,8 +2682,11 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
}
}
- if (error == 0)
- copy_to_user (result, &temp, sizeof (temp));
+ result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+
+ error = -EFAULT;
+ if (!copy_to_user(result, &temp, sizeof (temp)))
+ error = 0;
return error;
}
@@ -2741,17 +2700,10 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev
struct ppp_comp_stats *result, temp;
int error;
/*
- * Must have write access to the buffer.
- */
- result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
- error = verify_area (VERIFY_WRITE,
- result,
- sizeof (temp));
-/*
* Supply the information for the caller.
*/
memset (&temp, 0, sizeof(temp));
- if (error == 0 && dev->flags & IFF_UP) {
+ if (dev->flags & IFF_UP) {
if (ppp->sc_xc_state != NULL)
(*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
&temp.c);
@@ -2763,8 +2715,11 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev
/*
* Move the data to the caller's buffer
*/
- if (error == 0)
- copy_to_user (result, &temp, sizeof (temp));
+ result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
+
+ error = -EFAULT;
+ if (!copy_to_user(result, &temp, sizeof (temp)))
+ error = 0;
return error;
}
@@ -2777,6 +2732,8 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
{
struct ppp *ppp = dev2ppp (dev);
int error;
+
+ CHECK_PPP_MAGIC(ppp);
/*
* Process the requests
*/
@@ -2805,102 +2762,56 @@ ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
*
* Return 0 if frame was queued for transmission.
* 1 if frame must be re-queued for later driver support.
+ * -1 if frame should be dropped.
*/
static int
-ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, __u8 *data)
+ppp_dev_xmit_ip (struct ppp *ppp, struct ppp_buffer *buf,
+ __u8 *data, int len, enum NPmode npmode)
{
- int proto = PPP_IP;
- int len;
- struct ppp_hdr *hdr;
- struct tty_struct *tty = ppp2tty (ppp);
-/*
- * Obtain the length from the IP header.
- */
- len = ((struct iphdr *)data) -> tot_len;
- len = ntohs (len);
-/*
- * Validate the tty interface
- */
- if (tty == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_dev_xmit: %s not connected to a TTY!\n",
- dev->name);
- return 0;
- }
-/*
- * Ensure that the PPP device is still up
- */
- if (!(dev->flags & IFF_UP)) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_dev_xmit: packet sent on interface %s,"
- " which is down for IP\n",
- dev->name);
- return 0;
- }
+ int proto = PPP_IP;
+ __u8 *hdr;
/*
* Branch on the type of processing for the IP frame.
*/
- switch (ppp->sc_npmode[NP_IP]) {
+ switch (npmode) {
case NPMODE_PASS:
break;
- case NPMODE_ERROR:
+ case NPMODE_QUEUE:
+ /*
+ * We may not send the packet now, so drop it.
+ * XXX It would be nice to be able to return it to the
+ * network system to be queued and retransmitted later.
+ */
if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_dev_xmit: npmode = NPMODE_ERROR on %s\n",
- dev->name);
- return 0;
+ printk(KERN_DEBUG "%s: returning frame\n",
+ ppp->name);
+ return -1;
+ case NPMODE_ERROR:
case NPMODE_DROP:
if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_dev_xmit: npmode = NPMODE_DROP on %s\n",
- dev->name);
- return 0;
-
- case NPMODE_QUEUE:
- break;
+ printk (KERN_DEBUG
+ "ppp_dev_xmit: npmode = %d on %s\n",
+ ppp->sc_npmode[NP_IP], ppp->name);
+ return -1;
default:
if (ppp->flags & SC_DEBUG)
printk (KERN_WARNING
"ppp_dev_xmit: unknown npmode %d on %s\n",
- ppp->sc_npmode[NP_IP],
- dev->name);
- return 0;
+ ppp->sc_npmode[NP_IP], ppp->name);
+ return -1;
}
/*
- * Detect a change in the transfer size
- */
- if (ppp->mtu != ppp2dev (ppp)->mtu) {
- ppp_changedmtu (ppp,
- ppp2dev (ppp)->mtu,
- ppp->mru);
- }
-/*
- * Acquire the lock on the transmission buffer. If the buffer was busy then
- * mark the device as busy.
- */
- if (lock_buffer (ppp->wbuf) != 0) {
- dev->tbusy = 1;
- return 1;
- }
-/*
- * Print the frame being sent
- */
- if (ppp->flags & SC_LOG_OUTPKT)
- ppp_print_buffer ("ppp outpkt", data, len);
-/*
* At this point, the buffer will be transmitted. There is no other exit.
*
* Try to compress the header.
*/
if (ppp->flags & SC_COMP_TCP) {
len = slhc_compress (ppp->slcomp, data, len,
- buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
+ buf_base (ppp->cbuf) + PPP_HDRLEN,
&data,
(ppp->flags & SC_NO_TCP_CCID) == 0);
@@ -2916,83 +2827,40 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, __u8 *data)
/*
* Send the frame
*/
- len += PPP_HARD_HDR_LEN;
- hdr = &((struct ppp_hdr *) data)[-1];
+ len += PPP_HDRLEN;
+ hdr = data - PPP_HDRLEN;
- hdr->address = PPP_ALLSTATIONS;
- hdr->control = PPP_UI;
- hdr->protocol[0] = 0;
- hdr->protocol[1] = proto;
+ hdr[0] = PPP_ALLSTATIONS;
+ hdr[1] = PPP_UI;
+ hdr[2] = 0;
+ hdr[3] = proto;
- return ppp_dev_xmit_frame (ppp, ppp->wbuf, (__u8 *) hdr, len);
+ return ppp_dev_xmit_frame (ppp, buf, hdr, len);
}
/*
- * Send an IPX (or any other non-IP) frame to the remote.
+ * Send a non-IP data frame (such as an IPX frame) to the remote.
*
* Return 0 if frame was queued for transmission.
* 1 if frame must be re-queued for later driver support.
*/
static int
-ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+ppp_dev_xmit_other (struct device *dev, struct ppp *ppp,
__u8 *data, int len, int proto)
{
- struct tty_struct *tty = ppp2tty (ppp);
- struct ppp_hdr *hdr;
-/*
- * Validate the tty interface
- */
- if (tty == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_dev_xmit: %s not connected to a TTY!\n",
- dev->name);
- return 0;
- }
-/*
- * Ensure that the PPP device is still up
- */
- if (!(dev->flags & IFF_UP)) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_dev_xmit: packet sent on interface %s,"
- " which is down\n",
- dev->name);
- return 0;
- }
-/*
- * Detect a change in the transfer size
- */
- if (ppp->mtu != ppp2dev (ppp)->mtu) {
- ppp_changedmtu (ppp,
- ppp2dev (ppp)->mtu,
- ppp->mru);
- }
-/*
- * Acquire the lock on the transmission buffer. If the buffer was busy then
- * mark the device as busy.
- */
- if (lock_buffer (ppp->wbuf) != 0) {
- dev->tbusy = 1;
- return 1;
- }
-/*
- * Print the frame being sent
- */
- if (ppp->flags & SC_LOG_OUTPKT)
- ppp_print_buffer ("ppp outpkt", data, len);
+ __u8 *hdr;
/*
* Send the frame
*/
- len += PPP_HARD_HDR_LEN;
- hdr = &((struct ppp_hdr *) data)[-1];
+ len += PPP_HDRLEN;
+ hdr = data - PPP_HDRLEN;
- hdr->address = PPP_ALLSTATIONS;
- hdr->control = PPP_UI;
- hdr->protocol[0] = proto >> 8;
- hdr->protocol[1] = proto;
+ hdr[0] = PPP_ALLSTATIONS;
+ hdr[1] = PPP_UI;
+ hdr[2] = proto >> 8;
+ hdr[3] = proto;
- return ppp_dev_xmit_frame (ppp, ppp->wbuf, (__u8 *) hdr, len);
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, hdr, len);
}
/*
@@ -3014,25 +2882,14 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
return 0;
}
-
/*
* Avoid timing problem should tty hangup while data is queued to be sent
*/
if (!ppp->inuse) {
- dev_kfree_skb (skb, FREE_WRITE);
- printk(KERN_WARNING "ppp: I am dying to know, are you still alive?\n");
-#if 0
- dev_close (dev);
-#endif
+ dev_kfree_skb (skb);
return 0;
}
/*
- * Validate the tty linkage
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
- dev->name, skb);
-/*
* Validate the tty interface
*/
if (tty == NULL) {
@@ -3040,7 +2897,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
printk (KERN_ERR
"ppp_dev_xmit: %s not connected to a TTY!\n",
dev->name);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
/*
@@ -3048,13 +2905,36 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
*/
len = skb->len;
data = skb_data(skb);
+
+ if (data == (__u8 *) 0) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n",
+ dev->name);
+ dev_kfree_skb (skb);
+ return 0;
+ }
/*
- * Bug trap for null data. Release the skb and bail out.
+ * Detect a change in the transfer size
*/
- if(data == NULL) {
- printk("ppp_dev_xmit: data=NULL before ppp_dev_xmit_ip.\n");
- dev_kfree_skb (skb, FREE_WRITE);
- return 0;
+ if (ppp->mtu != ppp2dev (ppp)->mtu) {
+ ppp_changedmtu (ppp,
+ ppp2dev (ppp)->mtu,
+ ppp->mru);
+ }
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy.
+ * We also require that ppp->tbuf be unlocked, in order to serialize
+ * calls to ppp_dev_xmit_frame (which does compression) and the output
+ * of frames w.r.t. tty writes from pppd.
+ */
+ CHECK_BUF_MAGIC(ppp->wbuf);
+ if (ppp->tbuf->locked || lock_buffer (ppp->wbuf) != 0) {
+ dev->tbusy = 1;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "dev_xmit blocked, t=%lu w=%lu\n",
+ ppp->tbuf->locked, ppp->wbuf->locked);
+ return 1;
}
/*
* Look at the protocol in the skb to determine the difference between
@@ -3062,23 +2942,34 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
*/
switch (ntohs (skb->protocol)) {
case ETH_P_IPX:
- answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
+ answer = ppp_dev_xmit_other (dev, ppp, data, len, PPP_IPX);
break;
case ETH_P_IP:
- answer = ppp_dev_xmit_ip (dev, ppp, data);
+ answer = ppp_dev_xmit_ip (ppp, ppp->wbuf, data, len,
+ ppp->sc_npmode[NP_IP]);
break;
default: /* All others have no support at this time. */
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
/*
* This is the end of the transmission. Release the buffer if it was sent.
*/
if (answer == 0) {
- dev_kfree_skb (skb, FREE_WRITE);
- ppp->ddinfo.xmit_idle = jiffies;
+ /* packet queued OK */
+ dev_kfree_skb (skb);
+ } else {
+ ppp->wbuf->locked = 0;
+ if (answer < 0) {
+ /* packet should be dropped */
+ dev_kfree_skb (skb);
+ answer = 0;
+ } else {
+ /* packet should be queued for later */
+ dev->tbusy = 1;
+ }
}
return answer;
}
@@ -3091,29 +2982,15 @@ static struct net_device_stats *
ppp_dev_stats (struct device *dev)
{
struct ppp *ppp = dev2ppp (dev);
- static struct net_device_stats ppp_stats;
-
- ppp_stats.rx_packets = ppp->stats.ppp_ipackets;
- ppp_stats.rx_errors = ppp->stats.ppp_ierrors;
- ppp_stats.rx_dropped = ppp->stats.ppp_ierrors;
- ppp_stats.rx_fifo_errors = 0;
- ppp_stats.rx_length_errors = 0;
- ppp_stats.rx_over_errors = 0;
- ppp_stats.rx_crc_errors = 0;
- ppp_stats.rx_frame_errors = 0;
- ppp_stats.tx_packets = ppp->stats.ppp_opackets;
- ppp_stats.tx_errors = ppp->stats.ppp_oerrors;
- ppp_stats.tx_dropped = 0;
- ppp_stats.tx_fifo_errors = 0;
- ppp_stats.collisions = 0;
- ppp_stats.tx_carrier_errors = 0;
- ppp_stats.tx_aborted_errors = 0;
- ppp_stats.tx_window_errors = 0;
- ppp_stats.tx_heartbeat_errors = 0;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp_dev_stats called");
- return &ppp_stats;
+ ppp->estats.rx_packets = ppp->stats.ppp_ipackets;
+ ppp->estats.rx_errors = ppp->stats.ppp_ierrors;
+ ppp->estats.tx_packets = ppp->stats.ppp_opackets;
+ ppp->estats.tx_errors = ppp->stats.ppp_oerrors;
+ ppp->estats.rx_bytes = ppp->stats.ppp_ibytes;
+ ppp->estats.tx_bytes = ppp->stats.ppp_obytes;
+
+ return &ppp->estats;
}
/*************************************************************
@@ -3125,95 +3002,108 @@ ppp_dev_stats (struct device *dev)
static struct ppp *
ppp_find (int pid_value)
{
- int if_num;
- ppp_ctrl_t *ctl;
struct ppp *ppp;
- /* try to find the exact same free device which we had before */
- ctl = ppp_list;
- if_num = 0;
+ /* try to find the device which this pid is already using */
+ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
+ if (ppp->inuse && ppp->sc_xfer == pid_value) {
+ ppp->sc_xfer = 0;
+ break;
+ }
+ }
+ return ppp;
+}
- while (ctl) {
- ppp = ctl2ppp (ctl);
- if (!test_and_set_bit(0, &ppp->inuse)) {
- if (ppp->sc_xfer == pid_value) {
- ppp->sc_xfer = 0;
- return (ppp);
- }
- clear_bit (0, &ppp->inuse);
+/* Collect hanged up channels */
+
+static void ppp_sync(void)
+{
+ struct device *dev;
+ struct ppp *ppp;
+
+ rtnl_lock();
+ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
+ if (!ppp->inuse) {
+ dev = ppp2dev(ppp);
+ if (dev->flags&IFF_UP)
+ dev_close(dev);
}
- ctl = ctl->next;
- if (++if_num == max_dev)
- break;
}
- return NULL;
+ rtnl_unlock();
}
+
/* allocate or create a PPP channel */
static struct ppp *
ppp_alloc (void)
{
int if_num;
int status;
- ppp_ctrl_t *ctl;
struct device *dev;
struct ppp *ppp;
+ ppp_sync();
+
/* try to find an free device */
- ctl = ppp_list;
- if_num = 0;
+ if_num = 0;
+ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
+ if (!test_and_set_bit(0, &ppp->inuse)) {
+
+ /* Reregister device */
+
+ dev = ppp2dev(ppp);
+ unregister_netdev (dev);
- while (ctl) {
- ppp = ctl2ppp (ctl);
- if (!test_and_set_bit(0, &ppp->inuse))
- return (ppp);
- ctl = ctl->next;
- if (++if_num == max_dev)
- return (NULL);
+ if (register_netdev (dev)) {
+ printk(KERN_DEBUG "cannot reregister ppp device\n");
+ return NULL;
+ }
+ return ppp;
+ }
+ ++if_num;
}
/*
- * There are no available items. Allocate a device from the system pool
+ * There are no available units, so make a new one.
*/
- ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
- if (ctl) {
- (void) memset(ctl, 0, sizeof(ppp_ctrl_t));
- ppp = ctl2ppp (ctl);
- dev = ctl2dev (ctl);
-
- /* initialize channel control data */
- set_bit(0, &ppp->inuse);
-
- ppp->line = if_num;
- ppp->tty = NULL;
- ppp->dev = dev;
-
- dev->next = NULL;
- dev->init = ppp_init_dev;
- dev->name = ctl->name;
- dev->base_addr = (__u32) if_num;
- dev->priv = (void *) ppp;
-
- sprintf (dev->name, "ppp%d", if_num);
-
- /* link in the new channel */
- ctl->next = ppp_list;
- ppp_list = ctl;
-
- /* register device so that we can be ifconfig'd */
- /* ppp_init_dev() will be called as a side-effect */
+ ppp = (struct ppp *) kmalloc (sizeof(struct ppp), GFP_KERNEL);
+ if (ppp == 0)
+ return 0;
+ memset(ppp, 0, sizeof(*ppp));
- status = register_netdev (dev);
- if (status == 0) {
- printk (KERN_INFO "registered device %s\n", dev->name);
- return (ppp);
- }
+ /* initialize channel control data */
+ set_bit(0, &ppp->inuse);
+ ppp->line = if_num;
+ ppp->tty = NULL;
+ ppp->backup_tty = NULL;
+ if (ppp_last == 0)
+ ppp_list = ppp;
+ else
+ ppp_last->next = ppp;
+ ppp_last = ppp;
+ ppp->next = 0;
+
+ dev = ppp2dev(ppp);
+ dev->next = NULL;
+ dev->init = ppp_init_dev;
+ dev->name = ppp->name;
+ sprintf(dev->name, "ppp%d", if_num);
+ dev->base_addr = (__u32) if_num;
+ dev->priv = (void *) ppp;
+
+ /* register device so that we can be ifconfig'd */
+ /* ppp_init_dev() will be called as a side-effect */
+ status = register_netdev (dev);
+ if (status == 0) {
+ printk (KERN_INFO "registered device %s\n", dev->name);
+ } else {
printk (KERN_ERR
"ppp_alloc - register_netdev(%s) = %d failure.\n",
dev->name, status);
+ ppp = NULL;
/* This one will forever be busy as it is not initialized */
}
- return (NULL);
+ return ppp;
}
/*
@@ -3292,7 +3182,7 @@ static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
static struct compressor *find_compressor (int type)
{
struct compressor_link *lnk;
- __u32 flags;
+ unsigned long flags;
save_flags(flags);
cli();
@@ -3310,12 +3200,10 @@ static struct compressor *find_compressor (int type)
return (struct compressor *) 0;
}
-#ifdef CONFIG_MODULES
-
static int ppp_register_compressor (struct compressor *cp)
{
struct compressor_link *new;
- __u32 flags;
+ unsigned long flags;
new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
@@ -3343,7 +3231,7 @@ static void ppp_unregister_compressor (struct compressor *cp)
{
struct compressor_link *prev = (struct compressor_link *) 0;
struct compressor_link *lnk;
- __u32 flags;
+ unsigned long flags;
save_flags(flags);
cli();
@@ -3364,8 +3252,6 @@ static void ppp_unregister_compressor (struct compressor *cp)
restore_flags(flags);
}
-#endif
-
/*************************************************************
* Module support routines
*************************************************************/
@@ -3381,7 +3267,6 @@ init_module(void)
if (status != 0)
printk (KERN_INFO
"PPP: ppp_init() failure %d\n", status);
-
return (status);
}
@@ -3389,27 +3274,23 @@ void
cleanup_module(void)
{
int status;
- ppp_ctrl_t *ctl, *next_ctl;
struct device *dev;
- struct ppp *ppp;
+ struct ppp *ppp, *next_ppp;
int busy_flag = 0;
/*
* Ensure that the devices are not in operation.
*/
- ctl = ppp_list;
- while (ctl) {
- ppp = ctl2ppp (ctl);
+ for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
if (ppp->inuse && ppp->tty != NULL) {
busy_flag = 1;
break;
}
- dev = ctl2dev (ctl);
+ dev = ppp2dev (ppp);
if (dev->start || dev->flags & IFF_UP) {
busy_flag = 1;
break;
}
- ctl = ctl->next;
}
/*
* Ensure that there are no compressor modules registered
@@ -3437,16 +3318,11 @@ cleanup_module(void)
/*
* De-register the devices so that there is no problem with them
*/
- next_ctl = ppp_list;
- while (next_ctl) {
- ctl = next_ctl;
- next_ctl = ctl->next;
- ppp = ctl2ppp (ctl);
- dev = ctl2dev (ctl);
-
- ppp_release (ppp);
- unregister_netdev (dev);
- kfree (ctl);
+ for (ppp = ppp_list; ppp != 0; ppp = next_ppp) {
+ next_ppp = ppp->next;
+ ppp_release (ppp);
+ unregister_netdev (&ppp->dev);
+ kfree (ppp);
}
}
#endif
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 754ec7c21..edb3d10f7 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -55,11 +55,7 @@
#include <linux/ioctl.h>
#include <linux/ppp_defs.h>
-
-#undef PACKETPTR
-#define PACKETPTR 1
#include <linux/ppp-comp.h>
-#undef PACKETPTR
#include "zlib.c"
@@ -192,20 +188,20 @@ z_comp_alloc(options, opt_len)
struct ppp_deflate_state *state;
int w_size;
+ MOD_INC_USE_COUNT;
if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
|| options[1] != CILEN_DEFLATE
|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
|| options[3] != DEFLATE_CHK_SEQUENCE)
- return NULL;
+ goto out_fail;
w_size = DEFLATE_SIZE(options[2]);
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
- return NULL;
+ goto out_fail;
state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
- return NULL;
+ goto out_fail;
- MOD_INC_USE_COUNT;
memset (state, 0, sizeof (struct ppp_deflate_state));
state->strm.next_in = NULL;
state->strm.zalloc = zalloc_init;
@@ -214,13 +210,16 @@ z_comp_alloc(options, opt_len)
if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
- != Z_OK) {
- z_comp_free(state);
- return NULL;
- }
-
+ != Z_OK)
+ goto out_free;
state->strm.zalloc = zalloc;
return (void *) state;
+
+out_free:
+ z_comp_free(state);
+out_fail:
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
static int
@@ -373,33 +372,35 @@ z_decomp_alloc(options, opt_len)
struct ppp_deflate_state *state;
int w_size;
+ MOD_INC_USE_COUNT;
if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE
|| options[1] != CILEN_DEFLATE
|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
|| options[3] != DEFLATE_CHK_SEQUENCE)
- return NULL;
+ goto out_fail;
w_size = DEFLATE_SIZE(options[2]);
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
- return NULL;
+ goto out_fail;
state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
- return NULL;
-
- MOD_INC_USE_COUNT;
+ goto out_fail;
memset (state, 0, sizeof (struct ppp_deflate_state));
state->w_size = w_size;
state->strm.next_out = NULL;
state->strm.zalloc = zalloc_init;
state->strm.zfree = zfree;
- if (inflateInit2(&state->strm, -w_size) != Z_OK) {
- z_decomp_free(state);
- return NULL;
- }
-
+ if (inflateInit2(&state->strm, -w_size) != Z_OK)
+ goto out_free;
state->strm.zalloc = zalloc;
return (void *) state;
+
+out_free:
+ z_decomp_free(state);
+out_fail:
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
static int
diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c
index c9684f678..1186d587c 100644
--- a/drivers/net/sdla.c
+++ b/drivers/net/sdla.c
@@ -32,6 +32,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h> /* for CONFIG_DLCI_MAX */
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c
index fd7173b45..e30bede48 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/sdla_fr.c
@@ -1,7 +1,8 @@
-/*****************************************************************************
+/****************************************************************************
* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
*
-* Author: Gene Kozin <genek@compuserve.com>
+* Author(s): Gene Kozin
+* Jaspreet Singh <jaspreet@sangoma.com>
*
* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
@@ -10,26 +11,52 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-*
-* Jun 29, 1997 Alan Cox o Hacked up vendor source 1.0.3 to remove
-* C++ style comments, and a massive security
-* hole (the UDP management junk).
-*
+* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards
+* o Added Cli() to protect enabling of interrupts
+* while polling is called.
+* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts
+* when they have been disabled by another
+* interface or routine (eg. wpf_poll).
+* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling
+* routine disable interrupts during interrupt
+* testing.
+* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time.
+* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow
+* control by avoiding RACE conditions. The
+* cli() and restore_flags() are taken out.
+* The fr_channel structure is appended for
+* Driver Statistics.
+* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX
+* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti()
+* o Abstracted the UDP management stuff
+* o Now use tbusy and critical more intelligently
+* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393
+* through router.conf.
+* o Protected calls to sdla_peek() by adDing
+* save_flags(), cli() and restore_flags().
+* o Added error message for Inactive DLCIs in
+* fr_event() and update_chan_state().
+* o Fixed freeing up of buffers using kfree()
+* when packets are received.
+* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets
+* o Added ability to discard multicast and
+* broadcast source addressed packets
+* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities
+* New case (0x44) statement in if_send routine * Added a global variable rCount to keep track
+* of FT1 status enabled on the board.
* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem
* With multiple boards a problem was seen where
* the second board always stopped transmitting
* packet after running for a while. The code
* got into a stage where the interrupts were
* disabled and dev->tbusy was set to 1.
-* This caused the If_send() routine to get into
-* the if clause for set_bit(0,dev->tbusy)
+* This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy)
* forever.
* The code got into this stage due to an
* interrupt occuring within the if clause for
* set_bit(0,dev->tbusy). Since an interrupt
* disables furhter transmit interrupt and
-* makes dev->tbusy = 0, this effect was undone
-* by making dev->tbusy = 1 in the if clause.
+* makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause.
* The Fix checks to see if Transmit interrupts
* are disabled then do not make dev->tbusy = 1
* Introduced a global variable: int_occur and
@@ -51,7 +78,7 @@
* Jan 30, 1997 Gene Kozin Version 3.1.0
* o implemented exec() entry point
* o fixed a bug causing driver configured as
-* a FR switch to be stuck in WAN_DISCONNECTED
+* a FR switch to be stuck in WAN_
* mode
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
@@ -60,115 +87,237 @@
#error This code MUST be compiled as a kernel module!
#endif
+#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/string.h> /* inline memset(), etc. */
#include <linux/malloc.h> /* kmalloc(), kfree() */
+#include <linux/init.h> /* __initfunc */
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <linux/init.h> /* __initfunc et al. */
#include <asm/byteorder.h> /* htons(), etc. */
#include <asm/io.h> /* for inb(), outb(), etc. */
#include <asm/uaccess.h>
+#include <linux/time.h> /* for do_gettimeofday */
#define _GNUC_
#include <linux/sdla_fr.h> /* frame relay firmware API definitions */
-
/****** Defines & Macros ****************************************************/
-#define CMD_OK 0 /* normal firmware return code */
-#define CMD_TIMEOUT 0xFF /* firmware command timed out */
-#define MAX_CMD_RETRY 10 /* max number of firmware retries */
+#define MAX_CMD_RETRY 10 /* max number of firmware retries */
-#define FR_HEADER_LEN 8 /* max encapsulation header size */
-#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
+#define FR_HEADER_LEN 8 /* max encapsulation header size */
+#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
/* Q.922 frame types */
-#define Q922_UI 0x03 /* Unnumbered Info frame */
-#define Q922_XID 0xAF /* ??? */
+#define Q922_UI 0x03 /* Unnumbered Info frame */
+#define Q922_XID 0xAF /* ??? */
+
+/* DLCI configured or not */
+#define DLCI_NOT_CONFIGURED 0x00
+#define DLCI_CONFIG_PENDING 0x01
+#define DLCI_CONFIGURED 0x02
+
+/* CIR enabled or not */
+#define CIR_ENABLED 0x00
+#define CIR_DISABLED 0x01
+
+/* Interrupt mode for DLCI = 0 */
+#define BUFFER_INTR_MODE 0x00
+#define DLCI_LIST_INTR_MODE 0x01
+/* Transmit Interrupt Status */
+#define DISABLED 0x00
+#define WAITING_TO_BE_ENABLED 0x01
+
+/* For handle_IPXWAN() */
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
/****** Data Structures *****************************************************/
/* This is an extention of the 'struct device' we create for each network
* interface to keep the rest of channel-specific data.
*/
-typedef struct fr_channel {
- char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */
- unsigned dlci; /* logical channel number */
- unsigned cir; /* committed information rate */
- char state; /* channel state */
+typedef struct fr_channel
+{
+ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
+ unsigned dlci_configured ; /* check whether configured or not */
+ unsigned cir_status; /* check whether CIR enabled or not */
+ unsigned dlci; /* logical channel number */
+ unsigned cir; /* committed information rate */
+ unsigned bc; /* committed burst size */
+ unsigned be; /* excess burst size */
+ unsigned mc; /* multicast support on or off */
+ unsigned tx_int_status; /* Transmit Interrupt Status */
+ unsigned short pkt_length; /* Packet Length */
+ unsigned long router_start_time;/* Router start time in seconds */
+ unsigned long tick_counter; /* counter for transmit time out */
+ char dev_pending_devtint; /* interface pending dev_tint() */
+ char state; /* channel state */
+ void* dlci_int_interface; /* pointer to the DLCI Interface */
+ unsigned long IB_addr; /* physical address of Interface Byte */
unsigned long state_tick; /* time of the last state change */
- sdla_t *card; /* -> owner */
- struct enet_statistics ifstats; /* interface statistics */
+ sdla_t* card; /* -> owner */
+ struct enet_statistics ifstats; /* interface statistics */
+
+ unsigned long if_send_entry;
+ unsigned long if_send_skb_null;
+ unsigned long if_send_broadcast;
+ unsigned long if_send_multicast;
+ unsigned long if_send_critical_ISR;
+ unsigned long if_send_critical_non_ISR;
+ unsigned long if_send_busy;
+ unsigned long if_send_busy_timeout;
+ unsigned long if_send_FPIPE_request;
+ unsigned long if_send_DRVSTATS_request;
+ unsigned long if_send_wan_disconnected;
+ unsigned long if_send_dlci_disconnected;
+ unsigned long if_send_no_bfrs;
+ unsigned long if_send_adptr_bfrs_full;
+ unsigned long if_send_bfrs_passed_to_adptr;
+
+ unsigned long rx_intr_no_socket;
+ unsigned long rx_intr_dev_not_started;
+ unsigned long rx_intr_FPIPE_request;
+ unsigned long rx_intr_DRVSTATS_request;
+ unsigned long rx_intr_bfr_not_passed_to_stack;
+ unsigned long rx_intr_bfr_passed_to_stack;
+
+ unsigned long UDP_FPIPE_mgmt_kmalloc_err;
+ unsigned long UDP_FPIPE_mgmt_direction_err;
+ unsigned long UDP_FPIPE_mgmt_adptr_type_err;
+ unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
+ unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
+ unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
+ unsigned long UDP_FPIPE_mgmt_passed_to_stack;
+ unsigned long UDP_FPIPE_mgmt_no_socket;
+ unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
+ unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
+ unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+ unsigned long UDP_DRVSTATS_mgmt_no_socket;
+ unsigned long router_up_time;
} fr_channel_t;
-typedef struct dlci_status {
- unsigned short dlci PACKED;
- unsigned char state PACKED;
+typedef struct dlci_status
+{
+ unsigned short dlci PACKED;
+ unsigned char state PACKED;
} dlci_status_t;
+typedef struct dlci_IB_mapping
+{
+ unsigned short dlci PACKED;
+ unsigned long addr_value PACKED;
+} dlci_IB_mapping_t;
+
+/* This structure is used for DLCI list Tx interrupt mode. It is used to
+ enable interrupt bit and set the packet length for transmission
+ */
+typedef struct fr_dlci_interface
+{
+ unsigned char gen_interrupt PACKED;
+ unsigned short packet_length PACKED;
+ unsigned char reserved PACKED;
+} fr_dlci_interface_t;
+
+static unsigned short num_frames;
+static unsigned long curr_trace_addr;
+static unsigned long start_trace_addr;
+static unsigned short available_buffer_space;
static char TracingEnabled;
-/* variable for checking interrupts within the ISR routine */
-static int int_occur = 0;
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
+static int rCount = 0;
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
+/* variable for keeping track of number of interrupts generated during
+ * interrupt test routine
+ */
+static int Intr_test_counter;
+
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t * wandev);
-static int new_if(wan_device_t * wandev, struct device *dev,
- wanif_conf_t * conf);
-static int del_if(wan_device_t * wandev, struct device *dev);
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+ wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
/* WANPIPE-specific entry points */
-static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
+static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data);
/* Network device interface */
-static int if_init(struct device *dev);
-static int if_open(struct device *dev);
-static int if_close(struct device *dev);
-static int if_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics *if_stats(struct device *dev);
+static int if_init (struct device* dev);
+static int if_open (struct device* dev);
+static int if_close (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+ unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
/* Interrupt handlers */
-static void fr502_isr(sdla_t * card);
-static void fr508_isr(sdla_t * card);
-static void fr502_rx_intr(sdla_t * card);
-static void fr508_rx_intr(sdla_t * card);
-static void tx_intr(sdla_t * card);
-static void spur_intr(sdla_t * card);
+static void fr502_isr (sdla_t* card);
+static void fr508_isr (sdla_t* card);
+static void fr502_rx_intr (sdla_t* card);
+static void fr508_rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
+static void spur_intr (sdla_t* card);
/* Background polling routines */
-static void wpf_poll(sdla_t * card);
+static void wpf_poll (sdla_t* card);
/* Frame relay firmware interface functions */
-static int fr_read_version(sdla_t * card, char *str);
-static int fr_configure(sdla_t * card, fr_conf_t * conf);
-static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu);
-static int fr_comm_enable(sdla_t * card);
-static int fr_comm_disable(sdla_t * card);
-static int fr_get_err_stats(sdla_t * card);
-static int fr_get_stats(sdla_t * card);
-static int fr_add_dlci(sdla_t * card, int dlci, int num);
-static int fr_activate_dlci(sdla_t * card, int dlci, int num);
-static int fr_issue_isf(sdla_t * card, int isf);
-static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf);
-static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf);
+static int fr_read_version (sdla_t* card, char* str);
+static int fr_configure (sdla_t* card, fr_conf_t *conf);
+static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci);
+static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu);
+static int fr_comm_enable (sdla_t* card);
+static int fr_comm_disable (sdla_t* card);
+static int fr_get_err_stats (sdla_t* card);
+static int fr_get_stats (sdla_t* card);
+static int fr_add_dlci (sdla_t* card, int dlci, int num);
+static int fr_activate_dlci (sdla_t* card, int dlci, int num);
+static int fr_issue_isf (sdla_t* card, int isf);
+static int fr502_send (sdla_t* card, int dlci, int attr, int len, void *buf);
+static int fr508_send (sdla_t* card, int dlci, int attr, int len, void *buf);
/* Firmware asynchronous event handlers */
-static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox);
-static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox);
-static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox);
+static int fr_event (sdla_t* card, int event, fr_mbox_t* mbox);
+static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox);
+static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox);
/* Miscellaneous functions */
-static int update_chan_state(struct device *dev);
-static void set_chan_state(struct device *dev, int state);
-static struct device *find_channel(sdla_t * card, unsigned dlci);
-static int is_tx_ready(sdla_t * card);
-static unsigned int dec_to_uint(unsigned char *str, int len);
+static int update_chan_state (struct device* dev);
+static void set_chan_state (struct device* dev, int state);
+static struct device* find_channel (sdla_t* card, unsigned dlci);
+static int is_tx_ready (sdla_t* card, fr_channel_t* chan);
+static unsigned int dec_to_uint (unsigned char* str, int len);
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+
+static int intr_test( sdla_t* card );
+static void init_chan_statistics( fr_channel_t* chan );
+static void init_global_statistics( sdla_t* card );
+static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
+
+/* Udp management functions */
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, int dlci, fr_channel_t* chan);
+static int udp_pkt_type( struct sk_buff *skb, sdla_t* card );
+
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number);
/****** Public Functions ****************************************************/
@@ -198,22 +347,23 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
return -EINVAL;
}
/* Initialize protocol-specific fields of adapter data space */
- switch (card->hw.fwid) {
- case SFID_FR502:
- card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS);
- card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS);
- card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS);
- card->isr = &fr502_isr;
- break;
+ switch (card->hw.fwid)
+ {
+ case SFID_FR502:
+ card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS);
+ card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS);
+ card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS);
+ card->isr = &fr502_isr;
+ break;
- case SFID_FR508:
- card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS);
- card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS);
- card->isr = &fr508_isr;
- break;
+ case SFID_FR508:
+ card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS);
+ card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS);
+ card->isr = &fr508_isr;
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
/* Read firmware version. Note that when adapter initializes, it
@@ -243,21 +393,28 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
u.cfg.cir_fwd = 16;
u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd;
u.cfg.options = 0x0081; /* direct Rx, no CIR check */
- switch (conf->u.fr.signalling) {
- case WANOPT_FR_Q933:
- u.cfg.options |= 0x0200;
- break;
- case WANOPT_FR_LMI:
- u.cfg.options |= 0x0400;
- break;
+
+ switch (conf->u.fr.signalling)
+ {
+ case WANOPT_FR_Q933:
+ u.cfg.options |= 0x0200;
+ break;
+ case WANOPT_FR_LMI:
+ u.cfg.options |= 0x0400;
+ break;
}
- if (conf->station == WANOPT_CPE) {
+
+ if (conf->station == WANOPT_CPE)
+ {
u.cfg.options |= 0x8000; /* auto config DLCI */
- } else {
+ }
+ else
+ {
u.cfg.station = 1; /* switch emulation mode */
card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16;
card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100);
}
+
if (conf->clocking == WANOPT_INTERNAL)
u.cfg.port |= 0x0001
;
@@ -279,7 +436,8 @@ __initfunc(int wpf_init(sdla_t * card, wandev_conf_t * conf))
return -EIO
;
- if (card->hw.fwid == SFID_FR508) {
+ if (card->hw.fwid == SFID_FR508)
+ {
fr_buf_info_t *buf_info =
(void *) (card->hw.dpmbase + FR508_RXBC_OFFS);
@@ -392,6 +550,32 @@ static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf
kfree(chan);
return err;
}
+
+ /* place cir,be,bc and other channel specific information into the
+ * chan structure
+ */
+ if (conf->cir)
+ {
+ chan->cir = max( 1, min( conf->cir, 512 ) );
+ chan->cir_status = CIR_ENABLED;
+
+ if (conf->bc)
+ chan->bc = max( 1, min( conf->bc, 512 ) );
+ if (conf->be)
+ chan->be = max( 0, min( conf->be, 511) );
+
+ }
+ else
+ chan->cir_status = CIR_DISABLED;
+
+ chan->mc = conf->mc;
+
+ chan->dlci_configured = DLCI_NOT_CONFIGURED;
+
+ chan->tx_int_status = DISABLED;
+
+ init_chan_statistics( chan );
+
/* prepare network device data space for registration */
dev->name = chan->name;
dev->init = &if_init;
@@ -489,9 +673,8 @@ static int if_init(struct device *dev)
/* Set transmit buffer queue length */
dev->tx_queue_len = 30;
- /* Initialize socket buffers */
- for (i = 0; i < DEV_NUMBUFFS; ++i)
- skb_queue_head_init(&dev->buffs[i]);
+ dev_init_buffers(dev);
+
set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -503,34 +686,146 @@ static int if_init(struct device *dev)
*
* Return 0 if O.k. or errno.
*/
+
static int if_open(struct device *dev)
{
fr_channel_t *chan = dev->priv;
sdla_t *card = chan->card;
+ struct device *dev2;
int err = 0;
-
+ fr508_flags_t *flags = card->flags;
+ struct timeval tv;
+
if (dev->start)
- return -EBUSY /* only one open is allowed */
- ;
+ return -EBUSY; /* only one open is allowed */
+
if (test_and_set_bit(0, (void *) &card->wandev.critical))
return -EAGAIN;
- ;
- if (!card->open_cnt) {
- if ((fr_comm_enable(card)) ||
- (fr_set_intr_mode(card, 0x03, card->wandev.mtu))) {
+
+ if (!card->open_cnt)
+ {
+ Intr_test_counter = 0;
+ card->intr_mode = INTR_TEST_MODE;
+ err = intr_test( card );
+
+ if ((err) || (Intr_test_counter !=(MAX_INTR_TEST_COUNTER +1))) {
+ printk(KERN_INFO
+ "%s: Interrupt Test Failed, Counter: %i\n",
+ card->devname, Intr_test_counter);
err = -EIO;
- goto done;
+ card->wandev.critical = 0;
+ return err;
+ }
+
+ printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n"
+ ,card->devname, Intr_test_counter);
+
+ /* The following allocates and intializes a circular
+ * link list of interfaces per card.
+ */
+
+ card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL);
+ if (card->devs_struct == NULL)
+ return -ENOMEM;
+ card->dev_to_devtint_next = card->devs_struct;
+
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
+ (card->devs_struct)->dev_ptr = dev2;
+ if(dev2->slave == NULL)
+ (card->devs_struct)->next = card->dev_to_devtint_next;
+ else {
+ (card->devs_struct)->next = kmalloc(
+ sizeof(load_sharing_t), GFP_KERNEL);
+ if ((card->devs_struct)->next == NULL)
+ return -ENOMEM;
+ card->devs_struct = (card->devs_struct)->next;
+ }
+ }
+
+ card->devs_struct = card->dev_to_devtint_next;
+
+ card->intr_mode = BUFFER_INTR_MODE;
+
+ /*
+ check all the interfaces for the device to see if CIR has
+ been enabled for any DLCI(s). If so then use the DLCI list
+ Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode
+ */
+
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
+
+ if( ((fr_channel_t *)dev2->priv)->cir_status
+ == CIR_ENABLED) {
+ card->intr_mode = DLCI_LIST_INTR_MODE;
+ break;
+ }
+ }
+
+ /*
+ * If you enable comms and then set ints, you get a Tx int as you
+ * perform the SET_INT_TRIGGERS command. So, we only set int
+ * triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms.
+ */
+ if (card->intr_mode == BUFFER_INTR_MODE)
+ {
+ if (fr_set_intr_mode(card, 0x03, card->wandev.mtu))
+ {
+ err = -EIO;
+ card->wandev.critical = 0;
+ return err;
+ }
+
+ printk( KERN_INFO
+ "%s: Global Buffering Tx Interrupt Mode\n"
+ , card->devname);
+
+ }
+ else if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ {
+ if (fr_set_intr_mode(card, 0x83, card->wandev.mtu))
+ {
+ err = -EIO;
+ card->wandev.critical = 0;
+ return err;
+ }
+
+ printk( KERN_INFO "%s: DLCI list Tx Interrupt Mode\n",
+ card->devname);
+
}
+
+ flags->imask &= ~0x02;
+
+ if (fr_comm_enable(card))
+ {
+ err = -EIO;
+ card->wandev.critical = 0;
+ return err;
+ }
+
wanpipe_set_state(card, WAN_CONNECTED);
- if (card->wandev.station == WANOPT_CPE) {
+ if (card->wandev.station == WANOPT_CPE)
+ {
/* CPE: issue full status enquiry */
fr_issue_isf(card, FR_ISF_FSE);
- } else { /* FR switch: activate DLCI(s) */
- fr_add_dlci(card,
- card->u.f.node_dlci, card->u.f.dlci_num);
- fr_activate_dlci(card,
- card->u.f.node_dlci, card->u.f.dlci_num);
+ }
+ else
+ { /* FR switch: activate DLCI(s) */
+
+ /* For Switch emulation we have to ADD and ACTIVATE
+ * the DLCI(s) that were configured with the SET_DLCI_
+ * CONFIGURATION command. Add and Activate will fail if
+ * DLCI specified is not included in the list.
+ *
+ * Also If_open is called once for each interface. But
+ * it does not get in here for all the interface. So
+ * we have to pass the entire list of DLCI(s) to add
+ * activate routines.
+ */
+
+ fr_add_dlci(card, card->u.f.node_dlci[0], card->u.f.dlci_num);
+ fr_activate_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num);
}
}
dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
@@ -540,7 +835,8 @@ static int if_open(struct device *dev)
wanpipe_open(card);
update_chan_state(dev);
- done:
+ do_gettimeofday( &tv );
+ chan->router_start_time = tv.tv_sec;
card->wandev.critical = 0;
return err;
}
@@ -636,69 +932,257 @@ static int if_send(struct sk_buff *skb, struct device *dev)
sdla_t *card = chan->card;
int retry = 0, err;
struct device *dev2;
+ fr508_flags_t* adptr_flags = card->flags;
+ fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
+ unsigned long host_cpu_flags;
+ int send_data = 0;
+ ++chan->if_send_entry;
+
+ if (dev->tbusy)
+ {
+ /* If our device stays busy for at least 5 seconds then we will
+ * kick start the device by making dev->tbusy = 0. We expect
+ * that our device never stays busy more than 5 seconds. So this * is only used as a last resort.
+ */
+
+ ++chan->if_send_busy;
+ ++chan->ifstats.collisions;
+
+ if ((jiffies - chan->tick_counter) < (5*HZ))
+ return 1;
+
+ printk(KERN_INFO "%s: Transmit timed out\n", chan->name);
+
+ ++chan->if_send_busy_timeout;
+
+ /* unbusy all the interfaces on the card */
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ dev2->tbusy = 0;
+ }
if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
#ifdef _DEBUG_
printk(KERN_INFO "%s: if_send() hit critical section!\n",
card->devname);
#endif
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}
- if (test_and_set_bit(0, (void *) &dev->tbusy)) {
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: Tx collision on interface %s!\n",
- card->devname, dev->name);
-#endif
- ++chan->ifstats.collisions;
- ++card->wandev.stats.collisions;
-
- retry = 1;
- if (card->wandev.tx_int_enabled) {
- for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
- dev2->tbusy = 1;
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_if_send_count;
+
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ {
+ if (card->wandev.critical == CRITICAL_IN_ISR)
+ {
+ ++chan->if_send_critical_ISR;
+
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ {
+ /* The enable_tx_int flag is set here so that if
+ * the critical flag is set due to an interrupt
+ * then we want to enable transmit interrupts
+ * again.
+ */
+
+ card->wandev.enable_tx_int = 1;
+
+ /* Setting this flag to WAITING_TO_BE_ENABLED
+ * specifies that interrupt bit has to be
+ * enabled for that particular interface.
+ * (delayed interrupt)
+ */
+
+ chan->tx_int_status = WAITING_TO_BE_ENABLED;
+
+ /* This is used for enabling dynamic calculation
+ * of CIRs relative to the packet length.
+ */
+
+ chan->pkt_length = skb->len;
+ dev->tbusy = 1;
+ chan->tick_counter = jiffies;
}
+ else
+ {
+ card->wandev.enable_tx_int = 1;
+ dev->tbusy = 1;
+ chan->tick_counter = jiffies;
+ }
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+ return 1;
}
- } else if (card->wandev.state != WAN_CONNECTED) {
+
+ ++chan->if_send_critical_non_ISR;
+ ++chan->ifstats.tx_dropped;
+ dev_kfree_skb(skb);
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+ return 0;
+ }
+
+ card->wandev.critical = 0x21;
+
+ if (card->wandev.state != WAN_CONNECTED)
+ {
+ ++chan->if_send_wan_disconnected;
++chan->ifstats.tx_dropped;
++card->wandev.stats.tx_dropped;
- } else if (chan->state != WAN_CONNECTED) {
+ }
+ else if (chan->state != WAN_CONNECTED)
+ {
+ ++chan->if_send_dlci_disconnected;
update_chan_state(dev);
++chan->ifstats.tx_dropped;
++card->wandev.stats.tx_dropped;
- } else if (!is_tx_ready(card)) {
+ }
+ else if (!is_tx_ready(card, chan))
+ {
+ if (card->intr_mode == DLCI_LIST_INTR_MODE )
+ {
+ dlci_interface->gen_interrupt |= 0x40;
+ dlci_interface->packet_length = skb->len;
+ }
+ dev->tbusy = 1;
+ chan->tick_counter = jiffies;
+
+ adptr_flags->imask |= 0x02;
+
+ ++ chan->if_send_no_bfrs;
retry = 1;
- if (card->wandev.tx_int_enabled) {
- for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) {
- dev2->tbusy = 1;
+ }
+ else
+ {
+ send_data = 1;
+ /* If it's an IPX packet */
+ if( sendpacket[1] == 0x00 &&
+ sendpacket[2] == 0x80 &&
+ sendpacket[6] == 0x81 &&
+ sendpacket[7] == 0x37)
+ {
+ if( card->wandev.enable_IPX )
+ {
+ switch_net_numbers(sendpacket,
+ card->wandev.network_number, 0);
+ }
+ else
+ {
+ /* increment some statistic here! */
+ send_data = 0;
}
}
- } else {
- err = (card->hw.fwid == SFID_FR508) ?
- fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
- fr502_send(card, chan->dlci, 0, skb->len, skb->data);
- if (err) {
- ++chan->ifstats.tx_errors;
- ++card->wandev.stats.tx_errors;
- } else {
- ++chan->ifstats.tx_packets;
- ++card->wandev.stats.tx_packets;
+
+ if (send_data)
+ {
+ err = (card->hw.fwid == SFID_FR508) ?
+ fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
+ fr502_send(card, chan->dlci, 0, skb->len, skb->data);
+
+ if (err)
+ {
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ {
+ dlci_interface->gen_interrupt |= 0x40;
+ dlci_interface->packet_length = skb->len;
+ }
+ dev->tbusy = 1;
+ chan->tick_counter = jiffies;
+ adptr_flags->imask |= 0x02;
+ retry = 1;
+ ++ chan->if_send_adptr_bfrs_full;
+ ++ chan->ifstats.tx_errors;
+ ++ card->wandev.stats.tx_errors;
+ }
+ else
+ {
+ ++ chan->if_send_bfrs_passed_to_adptr;
+ ++chan->ifstats.tx_packets;
+ ++card->wandev.stats.tx_packets;
+ }
}
}
- if (!retry) {
- dev_kfree_skb(skb, FREE_WRITE);
- dev->tbusy = 0;
- }
+
+ if (!retry)
+ dev_kfree_skb(skb);
+
card->wandev.critical = 0;
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
return retry;
}
+/*
+ * If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+ * if incoming is 1 - if the net number is 0 make it ours
+ *
+ */
+
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+ unsigned long pnetwork_number;
+
+ pnetwork_number = (unsigned long)((sendpacket[14] << 24) +
+ (sendpacket[15] << 16) + (sendpacket[16] << 8) +
+ sendpacket[17]);
+
+ if (!incoming) {
+ if( pnetwork_number == network_number) {
+ sendpacket[14] = sendpacket[15] = sendpacket[16] =
+ sendpacket[17] = 0x00;
+ }
+ } else {
+ if( pnetwork_number == 0) {
+ sendpacket[14] = (unsigned char)(network_number >> 24);
+ sendpacket[15] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[16] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[17] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+
+
+ pnetwork_number = (unsigned long)((sendpacket[26] << 24) +
+ (sendpacket[27] << 16) + (sendpacket[28] << 8) +
+ sendpacket[29]);
+
+ if( !incoming ) {
+ if( pnetwork_number == network_number) {
+ sendpacket[26] = sendpacket[27] = sendpacket[28] =
+ sendpacket[29] = 0x00;
+ }
+ } else {
+ if( pnetwork_number == 0 ) {
+ sendpacket[26] = (unsigned char)(network_number >> 24);
+ sendpacket[27] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[28] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[29] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+} /* switch_net_numbers */
+
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
-static struct enet_statistics *if_stats(struct device *dev)
+static struct net_device_stats *if_stats(struct device *dev)
{
fr_channel_t *chan = dev->priv;
@@ -714,18 +1198,19 @@ static void fr502_isr(sdla_t * card)
{
fr502_flags_t *flags = card->flags;
- switch (flags->iflag) {
- case 0x01: /* receive interrupt */
- fr502_rx_intr(card);
- break;
+ switch (flags->iflag)
+ {
+ case 0x01: /* receive interrupt */
+ fr502_rx_intr(card);
+ break;
- case 0x02: /* transmit interrupt */
- flags->imask &= ~0x02;
- tx_intr(card);
- break;
+ case 0x02: /* transmit interrupt */
+ flags->imask &= ~0x02;
+ tx_intr(card);
+ break;
- default:
- spur_intr(card);
+ default:
+ spur_intr(card);
}
flags->iflag = 0;
}
@@ -737,36 +1222,186 @@ static void fr508_isr(sdla_t * card)
{
fr508_flags_t *flags = card->flags;
fr_buf_ctl_t *bctl;
+ char *ptr = &flags->iflag;
+ struct device* dev = card->wandev.dev;
+ struct device* dev2;
+ int i;
+ unsigned long host_cpu_flags;
+ unsigned disable_tx_intr =1;
+ fr_channel_t* chan;
+ fr_dlci_interface_t* dlci_interface;
- if (int_occur) {
-#ifdef _DEBUG_
- printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n", card->devname);
-#endif
+ /* This flag prevents nesting of interrupts. See sdla_isr() routine
+ * in sdlamain.c.
+ */
+ card->in_isr = 1;
+
+ ++card->statistics.isr_entry;
+
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ {
+ printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag);
+ ++card->statistics.isr_already_critical;
+ card->in_isr = 0;
return;
}
int_occur = 1;
+
+ /* For all interrupts set the critical flag to CRITICAL_RX_INTR.
+ * If the if_send routine is called with this flag set it will set
+ * the enable transmit flag to 1. (for a delayed interrupt)
+ */
+ card->wandev.critical = CRITICAL_IN_ISR;
+
+ card->dlci_int_mode_unbusy = 0;
+ card->buff_int_mode_unbusy = 0;
+
switch (flags->iflag) {
- case 0x01: /* receive interrupt */
- fr508_rx_intr(card);
- break;
+ case 0x01: /* receive interrupt */
+ ++card->statistics.isr_rx;
+ fr508_rx_intr(card);
+ break;
+
+ case 0x02: /* transmit interrupt */
+ ++card->statistics.isr_tx;
+ bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
+ card->hw.dpmbase);
+ bctl->flag = 0xA0;
+
+ if (card->intr_mode == DLCI_LIST_INTR_MODE )
+ {
+ /* Find the structure and make it unbusy */
+ dev = find_channel( card, flags->dlci);
+ dev->tbusy = 0;
+
+ /* This is used to perform devtint at the
+ * end of the isr
+ */
+ card->dlci_int_mode_unbusy = 1;
+
+ /* check to see if any other interfaces are
+ * busy. If so then do not disable the tx
+ * interrupts
+ */
+ for (dev2 = card->wandev.dev; dev2;
+ dev2 = dev2->slave)
+ {
+ if ( dev2->tbusy == 1)
+ {
+ disable_tx_intr = 0;
+ break;
+ }
+ }
+ if (disable_tx_intr)
+ flags->imask &= ~0x02;
+
+ }
+ else if (card->intr_mode == BUFFER_INTR_MODE)
+ {
+ for (dev2 = card->wandev.dev; dev2;
+ dev2 = dev2->slave)
+ {
+ if ( !dev2 || !dev2->start )
+ {
+ ++card->statistics.
+ tx_intr_dev_not_started;
+ continue;
+ }
+ if(dev2->tbusy)
+ {
+ card->buff_int_mode_unbusy = 1;
+ ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 1;
+ dev2->tbusy = 0;
+ } else
+ ((fr_channel_t*)dev2->priv)->dev_pending_devtint = 0;
+ }
+ flags->imask &= ~0x02;
+ }
+ break;
+
+ case 0x08:
+ Intr_test_counter++;
+ ++card->statistics.isr_intr_test;
+ break;
+
+ default:
+ ++card->statistics.isr_spurious;
+ spur_intr(card);
+ printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
+ card->devname, flags->iflag);
+
+ printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
+
+ break;
+ }
+
+ card->wandev.critical = CRITICAL_INTR_HANDLED;
+ if (card->wandev.enable_tx_int)
+ {
+ if( card->intr_mode == DLCI_LIST_INTR_MODE )
+ {
+ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ {
+ chan = dev2->priv;
+ if ( chan->tx_int_status ==
+ WAITING_TO_BE_ENABLED )
+ {
+ dlci_interface =
+ chan->dlci_int_interface;
+ dlci_interface->gen_interrupt |= 0x40;
+ dlci_interface->packet_length =
+ chan->pkt_length;
+ chan->tx_int_status = DISABLED;
+ }
+ }
+ }
+ card->wandev.enable_tx_int = 0;
+ flags->imask |= 0x02;
+ ++card->statistics.isr_enable_tx_int;
+ }
+ save_flags(host_cpu_flags);
+ cli();
+ card->in_isr = 0;
+ card->wandev.critical = 0xD1;
+ flags->iflag = 0;
+ card->wandev.critical = 0;
+ restore_flags(host_cpu_flags);
- case 0x02: /* transmit interrupt */
- bctl = (void *) (flags->tse_offs - FR_MB_VECTOR +
- card->hw.dpmbase);
- bctl->flag = 0x90; /* disable further Tx interrupts */
- tx_intr(card);
- break;
+ /*
+ * Device is now ready to send. The instant this is executed the If_Send
+ * routine is called. That is why this is put at the bottom of the ISR
+ * to prevent a endless loop condition caused by repeated Interrupts and
+ * enable_tx_int flag.
+ */
- default:
- spur_intr(card);
+ if(card->dlci_int_mode_unbusy)
+ dev_tint(dev);
+
+ if(card->buff_int_mode_unbusy)
+ {
+ for (;;)
+ {
+ if (((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1){
+
+ ((fr_channel_t*)((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint=0;
+ dev_tint((card->devs_struct)->dev_ptr);
+ }
+ if ((card->devs_struct)->next == card->dev_to_devtint_next)
+ break;
+ card->devs_struct = (card->devs_struct)->next;
+ }
+ card->devs_struct = (card->dev_to_devtint_next)->next;
+ card->dev_to_devtint_next = card->devs_struct;
}
- int_occur = 0;
- flags->iflag = 0;
}
/*============================================================================
* Receive interrupt handler.
*/
+
static void fr502_rx_intr(sdla_t * card)
{
fr_mbox_t *mbox = card->rxmb;
@@ -787,12 +1422,12 @@ static void fr502_rx_intr(sdla_t * card)
/* Invalid channel, discard packet */
printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
card->devname, dlci);
- goto rx_done;
+ sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
chan = dev->priv;
if (!dev->start) {
++chan->ifstats.rx_dropped;
- goto rx_done;
+ sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
/* Allocate socket buffer */
skb = dev_alloc_skb(len);
@@ -800,7 +1435,7 @@ static void fr502_rx_intr(sdla_t * card)
printk(KERN_INFO "%s: no socket buffers available!\n",
card->devname);
++chan->ifstats.rx_dropped;
- goto rx_done;
+ sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
/* Copy data to the socket buffer */
buf = skb_put(skb, len);
@@ -812,7 +1447,7 @@ static void fr502_rx_intr(sdla_t * card)
buf = skb_pull(skb, 1); /* remove hardware header */
if (!wan_type_trans(skb, dev)) {
/* can't decapsulate packet */
- dev_kfree_skb(skb, FREE_READ);
+ dev_kfree_skb(skb);
++chan->ifstats.rx_errors;
++card->wandev.stats.rx_errors;
} else {
@@ -820,7 +1455,6 @@ static void fr502_rx_intr(sdla_t * card)
++chan->ifstats.rx_packets;
++card->wandev.stats.rx_packets;
}
- rx_done:
sdla_mapmem(&card->hw, FR_MB_VECTOR);
}
@@ -835,68 +1469,133 @@ static void fr508_rx_intr(sdla_t * card)
fr_channel_t *chan;
unsigned dlci, len, offs;
void *buf;
+ unsigned rx_count = 0;
+ fr508_flags_t* flags = card->flags;
+ char *ptr = &flags->iflag;
+ int i, err;
if (frbuf->flag != 0x01) {
printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
card->devname, (unsigned) frbuf);
+ printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
+
+ ++card->statistics.rx_intr_corrupt_rx_bfr;
return;
}
- len = frbuf->length;
- dlci = frbuf->dlci;
- offs = frbuf->offset;
- /* Find network interface for this packet */
- dev = find_channel(card, dlci);
- if (dev == NULL) {
- /* Invalid channel, discard packet */
- printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n",
- card->devname, dlci);
- goto rx_done;
- }
- chan = dev->priv;
- if (!dev->start) {
- ++chan->ifstats.rx_dropped;
- goto rx_done;
- }
- /* Allocate socket buffer */
- skb = dev_alloc_skb(len);
- if (skb == NULL) {
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- ++chan->ifstats.rx_dropped;
- goto rx_done;
- }
- /* Copy data to the socket buffer */
- if ((offs + len) > card->u.f.rx_top + 1) {
- unsigned tmp = card->u.f.rx_top - offs + 1;
+ do
+ {
+ len = frbuf->length;
+ dlci = frbuf->dlci;
+ offs = frbuf->offset;
+
+ /* Find network interface for this packet */
+ dev = find_channel(card, dlci);
+ chan = dev->priv;
+
+ if (dev == NULL)
+ {
+ /* Invalid channel, discard packet */
+ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n"
+ , card->devname, dlci);
+ ++card->statistics.rx_intr_on_orphaned_DLCI;
+ }
+ else
+ {
+ skb = dev_alloc_skb(len);
+ if (!dev->start || (skb == NULL))
+ {
+ ++chan->ifstats.rx_dropped;
+ if(dev->start)
+ {
+ printk(KERN_INFO
+ "%s: no socket buffers available!\n",
+ card->devname);
+ ++chan->rx_intr_no_socket;
+
+ }
+ else
+ ++ chan->rx_intr_dev_not_started;
+ }
+ else
+ {
+ /* Copy data to the socket buffer */
+ if ((offs + len) > card->u.f.rx_top + 1)
+ {
+ unsigned tmp = card->u.f.rx_top -
+ offs + 1;
+
+ buf = skb_put(skb, tmp);
+ sdla_peek(&card->hw, offs, buf, tmp);
+ offs = card->u.f.rx_base;
+ len -= tmp;
+ }
+
+ buf = skb_put(skb, len);
+ sdla_peek(&card->hw, offs, buf, len);
+#ifdef CONFIG_SANGOMA_MANAGER
+ if (management_check(skb,card))
+ {
+ ++chan->rx_intr_DRVSTATS_request;
+ }
+ else
+#endif
+ if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number))
+ {
+ if (card->wandev.enable_IPX)
+ {
+ fr508_send(card, dlci, 0, skb->len, skb->data);
+ } else {
+ /* increment some statistic! */
+ }
+ }
+ else
+ {
+ /* Decapsulate packet and pass it up the
+ protocol stack */
+ skb->dev = dev;
+
+ /* remove hardware header */
+ buf = skb_pull(skb, 1);
+
+ if (!wan_type_trans(skb, dev))
+ {
+ /* can't decapsulate packet */
+ dev_kfree_skb(skb);
+ ++chan->rx_intr_bfr_not_passed_to_stack;
+ ++chan->ifstats.rx_errors;
+ ++card->wandev.stats.rx_errors;
+ }
+ else
+ {
+ netif_rx(skb);
+ ++ chan->rx_intr_bfr_passed_to_stack;
+ ++ chan->ifstats.rx_packets;
+ ++ card->wandev.stats.rx_packets;
+ }
+ }
+ }
+ }
+
+ /* Release buffer element and calculate a pointer to the next
+ one */
+ frbuf->flag = 0;
+ card->rxmb = ++frbuf;
+
+ if ((void*)frbuf > card->u.f.rxmb_last)
+ card->rxmb = card->u.f.rxmb_base;
+
+ /* The loop put in is temporary, that is why the break is
+ * placed here. (?????)
+ */
+ break;
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, offs, buf, tmp);
- offs = card->u.f.rx_base;
- len -= tmp;
- }
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, offs, buf, len);
- /* Decapsulate packet and pass it up the protocol stack */
- skb->dev = dev;
- buf = skb_pull(skb, 1); /* remove hardware header */
- if (!wan_type_trans(skb, dev)) {
- /* can't decapsulate packet */
- dev_kfree_skb(skb, FREE_READ);
- ++chan->ifstats.rx_errors;
- ++card->wandev.stats.rx_errors;
- } else {
- netif_rx(skb);
- ++chan->ifstats.rx_packets;
- ++card->wandev.stats.rx_packets;
- }
- rx_done:
- /* Release buffer element and calculate a pointer to the next one */
- frbuf->flag = 0;
- card->rxmb = ++frbuf;
- if ((void *) frbuf > card->u.f.rxmb_last)
- card->rxmb = card->u.f.rxmb_base
- ;
+ frbuf = card->rxmb;
+
+ } while (frbuf->flag && ((++ rx_count) < 4));
}
/*============================================================================
@@ -908,20 +1607,26 @@ static void fr508_rx_intr(sdla_t * card)
static void tx_intr(sdla_t * card)
{
struct device *dev = card->wandev.dev;
- int v = 0;
- for (; dev; dev = dev->slave) {
- if (!dev || !dev->start)
- continue;
- v += dev->tbusy;
+ if (card->intr_mode == BUFFER_INTR_MODE)
+ {
+ for (; dev; dev = dev->slave)
+ {
+ if ( !dev || !dev->start )
+ {
+ ++ card->statistics.tx_intr_dev_not_started;
+ continue;
+ }
+
+ dev->tbusy = 0;
+ dev_tint(dev);
+ }
+ }
+ else
+ {
dev->tbusy = 0;
+ dev_tint(dev);
}
- card->wandev.tx_int_enabled = 0;
- if (v)
- mark_bh(NET_BH);
-/*
- printk(KERN_INFO "%s: transmit interrupt!\n", card->devname);
- */
}
/*============================================================================
@@ -935,6 +1640,105 @@ static void spur_intr(sdla_t * card)
printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
}
+/*
+ Return 0 for non-IPXWAN packet
+ 1 for IPXWAN packet or IPX is not enabled!
+
+*/
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number)
+{
+ int i;
+
+ if( sendpacket[1] == 0x00 &&
+ sendpacket[2] == 0x80 &&
+ sendpacket[6] == 0x81 &&
+ sendpacket[7] == 0x37) {
+
+ if(!enable_IPX) {
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+
+ if( sendpacket[24] == 0x90 &&
+ sendpacket[25] == 0x04)
+ {
+ if( sendpacket[10] == 0x02 &&
+ sendpacket[42] == 0x00)
+ {
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+ for(i = 49; sendpacket[i] == 0x00; i += 5)
+ {
+ if( sendpacket[i + 4] != 0x02)
+ {
+ sendpacket[i + 1] = 0;
+ }
+ }
+
+ if( sendpacket[i] == 0x04 )
+ {
+ i += 8;
+ }
+
+ for(; sendpacket[i] == 0x80 ;)
+ {
+ sendpacket[i + 1] = 0;
+ i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+ }
+
+ sendpacket[42] = 0x01;
+
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+ }
+ else if( sendpacket[42] == 0x02 )
+ {
+ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
+ sendpacket[42] = 0x03;
+
+ sendpacket[59] = 'F';
+ sendpacket[60] = 'P';
+ sendpacket[61] = 'I';
+ sendpacket[62] = 'P';
+ sendpacket[63] = 'E';
+ sendpacket[64] = '-';
+ sendpacket[65] = CVHexToAscii(network_number >> 28);
+ sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+ sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+ sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+ sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+ sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+ sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+ sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
+ for(i = 73; i < 107; i+= 1)
+ {
+ sendpacket[i] = 0;
+ }
+
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
+ }
+ else
+ {
+ printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
+ return 0;
+ }
+
+ sendpacket[43] = (unsigned char)(network_number >> 24);
+ sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+ sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+ sendpacket[46] = (unsigned char)(network_number & 0x000000FF);
+
+ return 1;
+ }
+
+ switch_net_numbers(sendpacket, network_number ,1);
+ return 0;
+}
+
+
/****** Background Polling Routines ****************************************/
/*============================================================================
@@ -948,18 +1752,40 @@ static void spur_intr(sdla_t * card)
* 1. This routine may be called on interrupt context with all interrupts
* enabled. Beware!
*/
+
static void wpf_poll(sdla_t * card)
{
- static unsigned long last_poll;
- fr502_flags_t *flags;
+ fr508_flags_t *flags;
+ unsigned long host_cpu_flags;
- if ((jiffies - last_poll) < HZ)
- return
- ;
+ ++card->statistics.poll_entry;
+
+ if (((jiffies - card->state_tick) < HZ) ||
+ (card->intr_mode == INTR_TEST_MODE))
+ return;
+
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_poll_count;
+
+ if (test_and_set_bit(0, (void *)&card->wandev.critical))
+ {
+ ++ card->statistics.poll_already_critical;
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) &&
+ (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return;
+ }
+
+ card->wandev.critical = 0x11;
+
+ ++ card->statistics.poll_processed;
- flags = card->flags;
if (flags->event) {
- fr_mbox_t *mbox = card->mbox;
+ fr_mbox_t* mbox = card->mbox;
int err;
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
@@ -968,9 +1794,19 @@ static void wpf_poll(sdla_t * card)
if (err)
fr_event(card, err, mbox);
}
- last_poll = jiffies;
+
+ card->wandev.critical = 0;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ card->state_tick = jiffies;
}
+
/****** Frame Relay Firmware-Specific Functions *****************************/
/*============================================================================
@@ -1005,17 +1841,17 @@ static int fr_configure(sdla_t * card, fr_conf_t * conf)
{
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
- int dlci = card->u.f.node_dlci;
int dlci_num = card->u.f.dlci_num;
int err, i;
do {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
memcpy(mbox->data, conf, sizeof(fr_conf_t));
- if (dlci_num)
- for (i = 0; i < dlci_num; ++i)
- ((fr_conf_t *) mbox->data)->dlci[i] = dlci + i
- ;
+
+ if (dlci_num) for (i = 0; i < dlci_num; ++i)
+ ((fr_conf_t*)mbox->data)->dlci[i] =
+ card->u.f.node_dlci[i];
+
mbox->cmd.command = FR_SET_CONFIG;
mbox->cmd.length =
sizeof(fr_conf_t) + dlci_num * sizeof(short);
@@ -1026,6 +1862,30 @@ static int fr_configure(sdla_t * card, fr_conf_t * conf)
}
/*============================================================================
+ * Set DLCI configuration.
+ */
+static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci)
+{
+ fr_mbox_t* mbox = card->mbox;
+ int retry = MAX_CMD_RETRY;
+ int err;
+
+ do
+ {
+ memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+ memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
+ mbox->cmd.dlci = (unsigned short) dlci;
+ mbox->cmd.command = FR_SET_CONFIG;
+ mbox->cmd.length = 0x0E;
+
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+ } while (err && retry--);
+
+ return err;
+}
+
+/*============================================================================
* Set interrupt mode.
*/
static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu)
@@ -1112,12 +1972,12 @@ static int fr_get_err_stats(sdla_t * card)
while (err && retry-- && fr_event(card, err, mbox));
if (!err) {
- fr_comm_stat_t *stats = (void *) mbox->data;
+ fr_comm_stat_t* stats = (void*)mbox->data;
- card->wandev.stats.rx_over_errors = stats->rx_overruns;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_aborts;
- card->wandev.stats.rx_length_errors = stats->rx_too_long;
+ card->wandev.stats.rx_over_errors = stats->rx_overruns;
+ card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+ card->wandev.stats.rx_missed_errors = stats->rx_aborts;
+ card->wandev.stats.rx_length_errors = stats->rx_too_long;
card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
}
return err;
@@ -1153,6 +2013,7 @@ static int fr_get_stats(sdla_t * card)
/*============================================================================
* Add DLCI(s) (Access Node only!).
*/
+
static int fr_add_dlci(sdla_t * card, int dlci, int num)
{
fr_mbox_t *mbox = card->mbox;
@@ -1164,8 +2025,8 @@ static int fr_add_dlci(sdla_t * card, int dlci, int num)
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
for (i = 0; i < num; ++i)
- dlci_list[i] = dlci + i
- ;
+ dlci_list[i] = card->u.f.node_dlci[i];
+
mbox->cmd.length = num * sizeof(short);
mbox->cmd.command = FR_ADD_DLCI;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
@@ -1188,8 +2049,8 @@ static int fr_activate_dlci(sdla_t * card, int dlci, int num)
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
for (i = 0; i < num; ++i)
- dlci_list[i] = dlci + i
- ;
+ dlci_list[i] = card->u.f.node_dlci[i];
+
mbox->cmd.length = num * sizeof(short);
mbox->cmd.command = FR_ACTIVATE_DLCI;
err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
@@ -1262,13 +2123,8 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
if (!err) {
fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data -
FR_MB_VECTOR + card->hw.dpmbase);
- unsigned long flags;
-
- save_flags(flags);
- cli();
sdla_poke(&card->hw, frbuf->offset, buf, len);
frbuf->flag = 0x01;
- restore_flags(flags);
}
return err;
}
@@ -1284,33 +2140,51 @@ static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf)
*/
static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox)
{
- switch (event) {
- case FRRES_MODEM_FAILURE:
- return fr_modem_failure(card, mbox);
+ fr508_flags_t* flags = card->flags;
+ char *ptr = &flags->iflag;
+ int i;
- case FRRES_CHANNEL_DOWN:
- wanpipe_set_state(card, WAN_DISCONNECTED);
- return 1;
+ switch (event)
+ {
+ case FRRES_MODEM_FAILURE:
+ return fr_modem_failure(card, mbox);
- case FRRES_CHANNEL_UP:
- wanpipe_set_state(card, WAN_CONNECTED);
- return 1;
+ case FRRES_CHANNEL_DOWN:
+ wanpipe_set_state(card, WAN_DISCONNECTED);
+ return 1;
- case FRRES_DLCI_CHANGE:
- return fr_dlci_change(card, mbox);
+ case FRRES_CHANNEL_UP:
+ wanpipe_set_state(card, WAN_CONNECTED);
+ return 1;
- case FRRES_DLCI_MISMATCH:
- printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname);
- return 1;
+ case FRRES_DLCI_CHANGE:
+ return fr_dlci_change(card, mbox);
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, mbox->cmd.command);
- break;
+ case FRRES_DLCI_MISMATCH:
+ printk(KERN_INFO "%s: DLCI list mismatch!\n", card->devname);
+ return 1;
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, mbox->cmd.command, event);
+ case CMD_TIMEOUT:
+ printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+ card->devname, mbox->cmd.command);
+ printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
+ break;
+
+ case FRRES_DLCI_INACTIVE:
+ printk(KERN_ERR "%s: DLCI %u is inactive!\n",
+ card->devname, mbox->cmd.dlci);
+ break;
+
+ case FRRES_CIR_OVERFLOW:
+ break;
+ case FRRES_BUFFER_OVERFLOW:
+ break;
+ default:
+ printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
+ card->devname, mbox->cmd.command, event);
}
return 0;
}
@@ -1324,10 +2198,11 @@ static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox)
{
printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
card->devname, mbox->data[0]);
- switch (mbox->cmd.command) {
- case FR_WRITE:
- case FR_READ:
- return 0;
+ switch (mbox->cmd.command)
+ {
+ case FR_WRITE:
+ case FR_READ:
+ return 0;
}
return 1;
}
@@ -1341,25 +2216,91 @@ static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox)
{
dlci_status_t *status = (void *) mbox->data;
int cnt = mbox->cmd.length / sizeof(dlci_status_t);
-
+ fr_dlc_conf_t cfg;
+ fr_channel_t *chan;
+ struct device* dev2;
+
for (; cnt; --cnt, ++status) {
unsigned short dlci = status->dlci;
struct device *dev = find_channel(card, dlci);
- if (status->state & 0x01) {
- printk(KERN_INFO
- "%s: DLCI %u has been deleted!\n",
- card->devname, dlci);
- if (dev && dev->start)
- set_chan_state(dev, WAN_DISCONNECTED);
- } else if (status->state & 0x02) {
- printk(KERN_INFO
- "%s: DLCI %u becomes active!\n",
- card->devname, dlci);
- if (dev && dev->start)
- set_chan_state(dev, WAN_CONNECTED);
+ if (dev == NULL)
+ {
+ printk(KERN_INFO "%s: CPE contains unconfigured DLCI= %d\n",
+ card->devname, dlci);
+ }
+ else
+ {
+ if (status->state & 0x01)
+ {
+ printk(KERN_INFO
+ "%s: DLCI %u has been deleted!\n",
+ card->devname, dlci);
+ if (dev && dev->start)
+ set_chan_state(dev, WAN_DISCONNECTED);
+ }
+ else if (status->state & 0x02)
+ {
+ printk(KERN_INFO
+ "%s: DLCI %u becomes active!\n",
+ card->devname, dlci);
+ chan = dev->priv;
+ /* This flag is used for configuring specific
+ DLCI(s) when they become active.
+ */
+ chan->dlci_configured = DLCI_CONFIG_PENDING;
+
+ if (dev && dev->start)
+ set_chan_state(dev, WAN_CONNECTED);
+ }
}
}
+
+ for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave)
+ {
+ chan = dev2->priv;
+
+ if (chan->dlci_configured == DLCI_CONFIG_PENDING)
+ {
+ memset(&cfg, 0, sizeof(cfg));
+
+ if ( chan->cir_status == CIR_DISABLED)
+ {
+ cfg.cir_fwd = cfg.cir_bwd = 16;
+ cfg.bc_fwd = cfg.bc_bwd = 16;
+ cfg.conf_flags = 0x0001;
+ printk(KERN_INFO "%s: CIR Disabled for %s\n",
+ card->devname, chan->name);
+ }
+ else if (chan->cir_status == CIR_ENABLED)
+ {
+ cfg.cir_fwd = cfg.cir_bwd = chan->cir;
+ cfg.bc_fwd = cfg.bc_bwd = chan->bc;
+ cfg.be_fwd = cfg.be_bwd = chan->be;
+ cfg.conf_flags = 0x0000;
+ printk(KERN_INFO "%s: CIR Enabled for %s\n",
+ card->devname, chan->name);
+
+ }
+
+ if (fr_dlci_configure( card, &cfg , chan->dlci))
+ {
+ printk(KERN_INFO
+ "%s: DLCI Configure failed for %d\n",
+ card->devname, chan->dlci);
+ return 1;
+ }
+
+ chan->dlci_configured = DLCI_CONFIGURED;
+
+ /*
+ * Read the interface byte mapping into the channel
+ * structure.
+ */
+ if (card->intr_mode == DLCI_LIST_INTR_MODE)
+ read_DLCI_IB_mapping( card, chan );
+ }
+ }
return 1;
}
@@ -1375,6 +2316,7 @@ static int update_chan_state(struct device *dev)
fr_mbox_t *mbox = card->mbox;
int retry = MAX_CMD_RETRY;
int err;
+ int dlci_found = 0;
do {
memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
@@ -1387,12 +2329,19 @@ static int update_chan_state(struct device *dev)
unsigned short *list = (void *) mbox->data;
int cnt = mbox->cmd.length / sizeof(short);
- for (; cnt; --cnt, ++list) {
- if (*list == chan->dlci) {
+ for (; cnt; --cnt, ++list)
+ {
+ if (*list == chan->dlci)
+ {
+ dlci_found = 1;
set_chan_state(dev, WAN_CONNECTED);
break;
}
}
+
+ if(!dlci_found)
+ printk(KERN_INFO "%s: DLCI %u is inactive\n",
+ card->devname, chan->dlci);
}
return err;
}
@@ -1408,22 +2357,25 @@ static void set_chan_state(struct device *dev, int state)
save_flags(flags);
cli();
- if (chan->state != state) {
- switch (state) {
- case WAN_CONNECTED:
- printk(KERN_INFO "%s: interface %s connected!\n",
- card->devname, dev->name);
- break;
-
- case WAN_CONNECTING:
- printk(KERN_INFO "%s: interface %s connecting...\n",
- card->devname, dev->name);
- break;
- case WAN_DISCONNECTED:
- printk(KERN_INFO "%s: interface %s disconnected!\n",
- card->devname, dev->name);
- break;
+ if (chan->state != state)
+ {
+ switch (state)
+ {
+ case WAN_CONNECTED:
+ printk(KERN_INFO "%s: interface %s connected!\n"
+ , card->devname, dev->name);
+ break;
+ case WAN_CONNECTING:
+ printk(KERN_INFO
+ "%s: interface %s connecting...\n",
+ card->devname, dev->name);
+ break;
+ case WAN_DISCONNECTED:
+ printk (KERN_INFO
+ "%s: interface %s disconnected!\n",
+ card->devname, dev->name);
+ break;
}
chan->state = state;
}
@@ -1452,20 +2404,19 @@ static struct device *find_channel(sdla_t * card, unsigned dlci)
* Return: 1 - Tx buffer(s) available
* 0 - no buffers available
*/
+
static int is_tx_ready(sdla_t * card)
{
- if (card->hw.fwid == SFID_FR508) {
- fr508_flags_t *flags = card->flags;
+ if (card->hw.fwid == SFID_FR508)
+ {
unsigned char sb = inb(card->hw.port);
if (sb & 0x02)
return 1;
- flags->imask |= 0x02;
- card->wandev.tx_int_enabled = 1;
} else {
- fr502_flags_t *flags = card->flags;
+ fr502_flags_t* flags = card->flags;
- if (flags->tx_ready)
+ if (flags->tx_ready)
return 1;
flags->imask |= 0x02;
}
@@ -1487,4 +2438,110 @@ static unsigned int dec_to_uint(unsigned char *str, int len)
return val;
}
+/*==============================================================================
+ * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
+ * TEST_COUNTER times.
+ */
+static int intr_test( sdla_t* card )
+{
+ fr_mbox_t* mb = card->mbox;
+ int err,i;
+
+ /*
+ * The critical flag is unset here because we want to get into the
+ * ISR without the flag already set. The If_open sets the flag.
+ */
+
+ card->wandev.critical = 0;
+
+ err = fr_set_intr_mode( card, 0x08, card->wandev.mtu );
+
+ if (err == CMD_OK)
+ {
+ for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ )
+ {
+ /* Run command READ_CODE_VERSION */
+ memset(&mb->cmd, 0, sizeof(fr_cmd_t));
+ mb->cmd.length = 0;
+ mb->cmd.command = 0x40;
+ err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+ if (err != CMD_OK)
+ fr_event(card, err, mb);
+ }
+ }
+ else
+ return err;
+
+ err = fr_set_intr_mode( card, 0, card->wandev.mtu );
+
+ if( err != CMD_OK )
+ return err;
+
+ card->wandev.critical = 1;
+ return 0;
+}
+
+/*==============================================================================
+ * Initializes the Statistics values in the Sdla_t structure.
+ */
+
+void init_global_statistics( sdla_t* card )
+{
+ /* Intialize global statistics for a card */
+ card->statistics.isr_entry = 0;
+ card->statistics.isr_already_critical = 0;
+ card->statistics.isr_rx = 0;
+ card->statistics.isr_tx = 0;
+ card->statistics.isr_intr_test = 0;
+ card->statistics.isr_spurious = 0;
+ card->statistics.isr_enable_tx_int = 0;
+ card->statistics.rx_intr_corrupt_rx_bfr = 0;
+ card->statistics.rx_intr_on_orphaned_DLCI = 0;
+ card->statistics.tx_intr_dev_not_started = 0;
+ card->statistics.poll_entry = 0;
+ card->statistics.poll_already_critical = 0;
+ card->statistics.poll_processed = 0;
+}
+
+static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan )
+{
+ fr_mbox_t* mbox = card->mbox;
+ int retry = MAX_CMD_RETRY;
+ dlci_IB_mapping_t* result;
+ int err, counter, found;
+
+ do {
+ memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+ mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
+
+ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+
+ } while (err && retry-- && fr_event(card, err, mbox));
+
+ if( mbox->cmd.result != 0)
+ printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n",
+ chan->name);
+
+ counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
+ result = (void *)mbox->data;
+
+ found = 0;
+ for (; counter; --counter, ++result) {
+ if ( result->dlci == chan->dlci ) {
+ printk( KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n"
+ ,card->devname,result->dlci, result->addr_value
+ ,chan->name);
+ chan->IB_addr = result->addr_value;
+ chan->dlci_int_interface = (void*)(card->hw.dpmbase +
+ ( chan->IB_addr & 0x00001FFF));
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
+ card->devname, chan->dlci);
+}
+
/****** End *****************************************************************/
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c
index 9158c0d09..9d3e52fb0 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/sdla_ppp.c
@@ -1,7 +1,7 @@
/*****************************************************************************
* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
*
-* Author: Gene Kozin <genek@compuserve.com>
+* Author: Jaspreet Singh <jaspreet@sangoma.com>
*
* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
@@ -10,8 +10,31 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
-* Jun 29, 1997 Alan Cox o Dumped the idiot UDP management system.
-*
+* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
+* while they have been disabled.
+* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by
+* disabling and enabling of irqs.
+* o Added new counters for stats on disable/enable* IRQs.
+* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data'
+* before every netif_rx().
+* o Free up the device structure in del_if().
+* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing
+* command.
+* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time.
+* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow
+* control by avoiding RACE conditions. The
+* cli() and restore_flags() are taken out.
+* A new structure, "ppp_private_area", is added
+* to provide Driver Statistics.
+* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding
+* save_flags(), cli() and restore_flags().
+* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets
+* o Added ability to discard mulitcast and
+* broacast source addressed packets.
+* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities
+* New case (0x25) statement in if_send routine.
+* Added a global variable rCount to keep track
+* of FT1 status enabled on the board.
* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for
* 508 card to reflect changes in the new
* ppp508.sfm for supporting:continous transmission
@@ -36,6 +59,7 @@
#error This code MUST be compiled as a kernel module!
#endif
+#include <linux/config.h> /* CONFIG_SANGOMA_MANAGER */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
@@ -59,65 +83,146 @@
#define STATIC static
#endif
-#define CMD_OK 0 /* normal firmware return code */
-#define CMD_TIMEOUT 0xFF /* firmware command timed out */
-
-#define PPP_DFLT_MTU 1500 /* default MTU */
-#define PPP_MAX_MTU 4000 /* maximum MTU */
+#define PPP_DFLT_MTU 1500 /* default MTU */
+#define PPP_MAX_MTU 4000 /* maximum MTU */
#define PPP_HDR_LEN 1
-#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
-#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
+#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
+#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
+
+/* For handle_IPXWAN() */
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
+/******Data Structures*****************************************************/
+
+/* This structure is placed in the private data area of the device structure.
+ * The card structure used to occupy the private area but now the following
+ * structure will incorporate the card structure along with PPP specific data
+ */
+
+typedef struct ppp_private_area
+{
+ sdla_t* card;
+ unsigned long router_start_time; /*router start time in sec */
+ unsigned long tick_counter; /*used for 5 second counter*/
+ unsigned mc; /*multicast support on or off*/
+ /* PPP specific statistics */
+ unsigned long if_send_entry;
+ unsigned long if_send_skb_null;
+ unsigned long if_send_broadcast;
+ unsigned long if_send_multicast;
+ unsigned long if_send_critical_ISR;
+ unsigned long if_send_critical_non_ISR;
+ unsigned long if_send_busy;
+ unsigned long if_send_busy_timeout;
+ unsigned long if_send_DRVSTATS_request;
+ unsigned long if_send_PTPIPE_request;
+ unsigned long if_send_wan_disconnected;
+ unsigned long if_send_adptr_bfrs_full;
+ unsigned long if_send_protocol_error;
+ unsigned long if_send_tx_int_enabled;
+ unsigned long if_send_bfr_passed_to_adptr;
+
+ unsigned long rx_intr_no_socket;
+ unsigned long rx_intr_DRVSTATS_request;
+ unsigned long rx_intr_PTPIPE_request;
+ unsigned long rx_intr_bfr_not_passed_to_stack;
+ unsigned long rx_intr_bfr_passed_to_stack;
+
+ unsigned long UDP_PTPIPE_mgmt_kmalloc_err;
+ unsigned long UDP_PTPIPE_mgmt_adptr_type_err;
+ unsigned long UDP_PTPIPE_mgmt_direction_err;
+ unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_PTPIPE_mgmt_passed_to_adptr;
+ unsigned long UDP_PTPIPE_mgmt_passed_to_stack;
+ unsigned long UDP_PTPIPE_mgmt_no_socket;
+
+ unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_type_err;
+ unsigned long UDP_DRVSTATS_mgmt_direction_err;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr;
+ unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+ unsigned long UDP_DRVSTATS_mgmt_no_socket;
+
+ unsigned long router_up_time;
+
+}ppp_private_area_t;
+
+/* variable for keeping track of enabling/disabling FT1 monitor status */
+static int rCount = 0;
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t * wandev);
-static int new_if(wan_device_t * wandev, struct device *dev,
- wanif_conf_t * conf);
-static int del_if(wan_device_t * wandev, struct device *dev);
+static int update (wan_device_t* wandev);
+static int new_if (wan_device_t* wandev, struct device* dev,
+ wanif_conf_t* conf);
+static int del_if (wan_device_t* wandev, struct device* dev);
/* WANPIPE-specific entry points */
-static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data);
+static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data);
/* Network device interface */
-static int if_init(struct device *dev);
-static int if_open(struct device *dev);
-static int if_close(struct device *dev);
-static int if_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len);
-static int if_rebuild_hdr(struct sk_buff *skb);
-static int if_send(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics *if_stats(struct device *dev);
+static int if_init (struct device* dev);
+static int if_open (struct device* dev);
+static int if_close (struct device* dev);
+static int if_header (struct sk_buff* skb, struct device* dev,
+ unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_rebuild_hdr (struct sk_buff* skb);
+static int if_send (struct sk_buff* skb, struct device* dev);
+static struct enet_statistics* if_stats (struct device* dev);
+
/* PPP firmware interface functions */
-static int ppp_read_version(sdla_t * card, char *str);
-static int ppp_configure(sdla_t * card, void *data);
-static int ppp_set_intr_mode(sdla_t * card, unsigned mode);
-static int ppp_comm_enable(sdla_t * card);
-static int ppp_comm_disable(sdla_t * card);
-static int ppp_get_err_stats(sdla_t * card);
-static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto);
-static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb);
+static int ppp_read_version (sdla_t* card, char* str);
+static int ppp_configure (sdla_t* card, void* data);
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode);
+static int ppp_comm_enable (sdla_t* card);
+static int ppp_comm_disable (sdla_t* card);
+static int ppp_get_err_stats (sdla_t* card);
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto);
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb);
/* Interrupt handlers */
-STATIC void wpp_isr(sdla_t * card);
-static void rx_intr(sdla_t * card);
-static void tx_intr(sdla_t * card);
+STATIC void wpp_isr (sdla_t* card);
+static void rx_intr (sdla_t* card);
+static void tx_intr (sdla_t* card);
/* Background polling routines */
-static void wpp_poll(sdla_t * card);
-static void poll_active(sdla_t * card);
-static void poll_connecting(sdla_t * card);
-static void poll_disconnected(sdla_t * card);
+static void wpp_poll (sdla_t* card);
+static void poll_active (sdla_t* card);
+static void poll_connecting (sdla_t* card);
+static void poll_disconnected (sdla_t* card);
/* Miscellaneous functions */
-static int config502(sdla_t * card);
-static int config508(sdla_t * card);
-static void show_disc_cause(sdla_t * card, unsigned cause);
-static unsigned char bps_to_speed_code(unsigned long bps);
-
+static int config502 (sdla_t* card);
+static int config508 (sdla_t* card);
+static void show_disc_cause (sdla_t* card, unsigned cause);
+static unsigned char bps_to_speed_code (unsigned long bps);
+static int reply_udp( unsigned char *data, unsigned int mbox_len );
+static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area);
+static int process_udp_driver_call(char udp_pkt_src, sdla_t* card, struct sk_buff *skb, struct device* dev, ppp_private_area_t* ppp_priv_area);
+static void init_ppp_tx_rx_buff( sdla_t* card );
+static int intr_test( sdla_t* card );
+static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
+static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area);
+static void init_global_statistics( sdla_t* card );
+
+static int Intr_test_counter;
static char TracingEnabled;
+static unsigned long curr_trace_addr;
+static unsigned long start_trace_addr;
+static unsigned short available_buffer_space;
+
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
/****** Public Functions ****************************************************/
/*============================================================================
@@ -132,32 +237,38 @@ static char TracingEnabled;
* Return: 0 o.k.
* < 0 failure.
*/
-__initfunc(int wpp_init(sdla_t * card, wandev_conf_t * conf))
+int wpp_init (sdla_t* card, wandev_conf_t* conf)
{
- union {
+ union
+ {
char str[80];
} u;
/* Verify configuration ID */
if (conf->config_id != WANCONFIG_PPP) {
+
printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
+ card->devname, conf->config_id);
return -EINVAL;
+
}
+
/* Initialize protocol-specific fields */
switch (card->hw.fwid) {
- case SFID_PPP502:
- card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS);
- card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS);
- break;
- case SFID_PPP508:
- card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS);
- card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS);
- break;
+ case SFID_PPP502:
+ card->mbox =(void*)(card->hw.dpmbase + PPP502_MB_OFFS);
+ card->flags=(void*)(card->hw.dpmbase + PPP502_FLG_OFFS);
+ break;
+
+ case SFID_PPP508:
+ card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS);
+ card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
+ break;
+
+ default:
+ return -EINVAL;
- default:
- return -EINVAL;
}
/* Read firmware version. Note that when adapter initializes, it
@@ -166,28 +277,39 @@ __initfunc(int wpp_init(sdla_t * card, wandev_conf_t * conf))
* around this, we execute the first command twice.
*/
if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
- return -EIO
- ;
- printk(KERN_INFO "%s: running PPP firmware v%s\n",
- card->devname, u.str);
-
+ return -EIO;
+
+ printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str);
/* Adjust configuration and set defaults */
card->wandev.mtu = (conf->mtu) ?
- min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU
- ;
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = &wpp_isr;
- card->poll = &wpp_poll;
- card->exec = &wpp_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- card->wandev.state = WAN_DISCONNECTED;
- card->wandev.udp_port = conf->udp_port;
- TracingEnabled = '0';
+ min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
+
+ card->wandev.bps = conf->bps;
+ card->wandev.interface = conf->interface;
+ card->wandev.clocking = conf->clocking;
+ card->wandev.station = conf->station;
+ card->isr = &wpp_isr;
+ card->poll = &wpp_poll;
+ card->exec = &wpp_exec;
+ card->wandev.update = &update;
+ card->wandev.new_if = &new_if;
+ card->wandev.del_if = &del_if;
+ card->wandev.state = WAN_DISCONNECTED;
+ card->wandev.udp_port = conf->udp_port;
+ card->wandev.ttl = conf->ttl;
+ card->irq_dis_if_send_count = 0;
+ card->irq_dis_poll_count = 0;
+ TracingEnabled = 0;
+
+ card->wandev.enable_IPX = conf->enable_IPX;
+ if (conf->network_number)
+ card->wandev.network_number = conf->network_number;
+ else
+ card->wandev.network_number = 0xDEADBEEF;
+
+ /* initialize global statistics */
+ init_global_statistics( card );
+
return 0;
}
@@ -229,33 +351,59 @@ static int update(wan_device_t * wandev)
* Return: 0 o.k.
* < 0 failure (channel will not be created)
*/
-static int new_if(wan_device_t * wandev, struct device *dev, wanif_conf_t * conf)
+static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
{
- sdla_t *card = wandev->private;
+ sdla_t* card = wandev->private;
+ ppp_private_area_t* ppp_priv_area;
if (wandev->ndev)
- return -EEXIST
- ;
+ return -EEXIST;
+
if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
+
printk(KERN_INFO "%s: invalid interface name!\n",
- card->devname);
+ card->devname);
return -EINVAL;
+
}
+
+ /* allocate and initialize private data */
+ ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
+
+ if( ppp_priv_area == NULL )
+ return -ENOMEM;
+
+ memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
+
+ ppp_priv_area->card = card;
+
/* initialize data */
strcpy(card->u.p.if_name, conf->name);
+ /* initialize data in ppp_private_area structure */
+
+ init_ppp_priv_struct( ppp_priv_area );
+
+ ppp_priv_area->mc = conf->mc;
+
/* prepare network device data space for registration */
dev->name = card->u.p.if_name;
dev->init = &if_init;
- dev->priv = card;
+ dev->priv = ppp_priv_area;
return 0;
}
/*============================================================================
* Delete logical channel.
*/
-static int del_if(wan_device_t * wandev, struct device *dev)
+static int del_if (wan_device_t* wandev, struct device* dev)
{
+ if (dev->priv) {
+
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
+
return 0;
}
@@ -298,39 +446,41 @@ static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
* interface registration. Returning anything but zero will fail interface
* registration.
*/
-static int if_init(struct device *dev)
+static int if_init (struct device* dev)
{
- sdla_t *card = dev->priv;
- wan_device_t *wandev = &card->wandev;
+ ppp_private_area_t* ppp_priv_area = dev->priv;
+ sdla_t* card = ppp_priv_area->card;
+ wan_device_t* wandev = &card->wandev;
int i;
/* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
+ dev->open = &if_open;
+ dev->stop = &if_close;
+ dev->hard_header = &if_header;
+ dev->rebuild_header = &if_rebuild_hdr;
+ dev->hard_start_xmit = &if_send;
+ dev->get_stats = &if_stats;
+
/* Initialize media-specific parameters */
- dev->family = AF_INET; /* address family */
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- dev->mtu = wandev->mtu;
- dev->hard_header_len = PPP_HDR_LEN; /* media header length */
+ dev->family = AF_INET; /* address family */
+ dev->type = ARPHRD_PPP; /* ARP h/w type */
+ dev->mtu = wandev->mtu;
+ dev->hard_header_len = PPP_HDR_LEN; /* media header length */
/* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 30;
-
+ dev->irq = wandev->irq;
+ dev->dma = wandev->dma;
+ dev->base_addr = wandev->ioport;
+ dev->mem_start = wandev->maddr;
+ dev->mem_end = wandev->maddr + wandev->msize - 1;
+
+ /* Set transmit buffer queue length */
+ dev->tx_queue_len = 100;
+
/* Initialize socket buffers */
- for (i = 0; i < DEV_NUMBUFFS; ++i)
- skb_queue_head_init(&dev->buffs[i]);
+ dev_init_buffers(dev);
+
return 0;
}
@@ -341,64 +491,73 @@ static int if_init(struct device *dev)
*
* Return 0 if O.k. or errno.
*/
-static int if_open(struct device *dev)
+static int if_open (struct device* dev)
{
- sdla_t *card = dev->priv;
+ ppp_private_area_t* ppp_priv_area = dev->priv;
+ sdla_t* card = ppp_priv_area->card;
+ ppp_flags_t* flags = card->flags;
+ struct timeval tv;
int err = 0;
if (dev->start)
- return -EBUSY /* only one open is allowed */
- ;
- if (test_and_set_bit(0, (void *) &card->wandev.critical))
+ return -EBUSY; /* only one open is allowed */
+
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
- ;
- if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {
+
+ if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)){
+
+ err = -EIO;
+ card->wandev.critical = 0;
+ return err;
+
+ }
+
+ Intr_test_counter = 0;
+ err = intr_test( card );
+
+ if( (err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {
+
+ printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",
+ card->devname, Intr_test_counter);
err = -EIO;
- goto split;
+ card->wandev.critical = 0;
+ return err;
+
}
+
+ printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
+ card->devname, Intr_test_counter);
+
/* Initialize Rx/Tx buffer control fields */
- if (card->hw.fwid == SFID_PPP502) {
- ppp502_buf_info_t *info =
- (void *) (card->hw.dpmbase + PPP502_BUF_OFFS);
-
- card->u.p.txbuf_base = (void *) (card->hw.dpmbase +
- info->txb_offs);
- card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
- (info->txb_num - 1);
- card->u.p.rxbuf_base = (void *) (card->hw.dpmbase +
- info->rxb_offs);
- card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
- (info->rxb_num - 1);
- } else {
- ppp508_buf_info_t *info =
- (void *) (card->hw.dpmbase + PPP508_BUF_OFFS);
-
- card->u.p.txbuf_base = (void *) (card->hw.dpmbase +
- (info->txb_ptr - PPP508_MB_VECT));
- card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base +
- (info->txb_num - 1);
- card->u.p.rxbuf_base = (void *) (card->hw.dpmbase +
- (info->rxb_ptr - PPP508_MB_VECT));
- card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base +
- (info->rxb_num - 1);
- card->u.p.rx_base = info->rxb_base;
- card->u.p.rx_top = info->rxb_end;
+ init_ppp_tx_rx_buff( card );
+
+ if (ppp_set_intr_mode(card, 0x03)) {
+
+ err = -EIO;
+ card->wandev.critical = 0;
+ return err;
+
}
- card->u.p.txbuf = card->u.p.txbuf_base;
- card->rxmb = card->u.p.rxbuf_base;
- if (ppp_set_intr_mode(card, 0x03) || ppp_comm_enable(card)) {
+ flags->imask &= ~0x02;
+
+ if (ppp_comm_enable(card)) {
+
err = -EIO;
- goto split;
+ card->wandev.critical = 0;
+ return err;
+
}
+
wanpipe_set_state(card, WAN_CONNECTING);
wanpipe_open(card);
dev->mtu = min(dev->mtu, card->wandev.mtu);
dev->interrupt = 0;
dev->tbusy = 0;
dev->start = 1;
-
- split:
+ do_gettimeofday( &tv );
+ ppp_priv_area->router_start_time = tv.tv_sec;
card->wandev.critical = 0;
return err;
}
@@ -408,13 +567,14 @@ static int if_open(struct device *dev)
* o if this is the last open, then disable communications and interrupts.
* o reset flags.
*/
-static int if_close(struct device *dev)
+static int if_close (struct device* dev)
{
- sdla_t *card = dev->priv;
+ ppp_private_area_t* ppp_priv_area = dev->priv;
+ sdla_t* card = ppp_priv_area->card;
- if (test_and_set_bit(0, (void *) &card->wandev.critical))
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
return -EAGAIN;
- ;
+
dev->start = 0;
wanpipe_close(card);
wanpipe_set_state(card, WAN_DISCONNECTED);
@@ -433,18 +593,21 @@ static int if_close(struct device *dev)
*
* Return: media header length.
*/
-static int if_header(struct sk_buff *skb, struct device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+static int if_header (struct sk_buff* skb, struct device* dev,
+ unsigned short type, void* daddr, void* saddr, unsigned len)
{
- switch (type) {
- case ETH_P_IP:
- case ETH_P_IPX:
- skb->protocol = type;
- break;
-
- default:
- skb->protocol = 0;
+ switch (type)
+ {
+ case ETH_P_IP:
+
+ case ETH_P_IPX:
+ skb->protocol = type;
+ break;
+
+ default:
+ skb->protocol = 0;
}
+
return PPP_HDR_LEN;
}
@@ -454,12 +617,13 @@ static int if_header(struct sk_buff *skb, struct device *dev,
* Return: 1 physical address resolved.
* 0 physical address not resolved
*/
-static int if_rebuild_hdr(struct sk_buff *skb)
+static int if_rebuild_hdr (struct sk_buff* skb)
{
- sdla_t *card = skb->dev->priv;
+ ppp_private_area_t* ppp_priv_area = skb->dev->priv;
+ sdla_t* card = ppp_priv_area->card;
printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, skb->dev->name);
+ card->devname, dev->name);
return 1;
}
@@ -480,55 +644,238 @@ static int if_rebuild_hdr(struct sk_buff *skb)
* 2. Setting tbusy flag will inhibit further transmit requests from the
* protocol stack and can be used for flow control with protocol layer.
*/
-static int if_send(struct sk_buff *skb, struct device *dev)
+static int if_send (struct sk_buff* skb, struct device* dev)
{
- sdla_t *card = dev->priv;
+ ppp_private_area_t* ppp_priv_area = dev->priv;
+ sdla_t* card = ppp_priv_area->card;
+ unsigned char *sendpacket;
+ unsigned long check_braddr, check_mcaddr;
+ unsigned long host_cpu_flags;
+ ppp_flags_t* flags = card->flags;
int retry = 0;
+ int err, udp_type;
+
+ ++ppp_priv_area->if_send_entry;
+
+ if (skb == NULL) {
+
+ /* If we get here, some higher layer thinks we've missed an
+ * tx-done interrupt.
+ */
+ printk(KERN_INFO "%s: interface %s got kicked!\n",
+ card->devname, dev->name);
+
+ ++ppp_priv_area->if_send_skb_null;
+
+ dev_tint(dev);
+ return 0;
- if (test_and_set_bit(0, (void *) &card->wandev.critical)) {
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: if_send() hit critical section!\n",
- card->devname);
-#endif
- return 1;
}
- if (test_and_set_bit(0, (void *) &dev->tbusy)) {
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: Tx collision on interface %s!\n",
- card->devname, dev->name);
-#endif
- ++card->wandev.stats.collisions;
- retry = 1;
- } else if (card->wandev.state != WAN_CONNECTED)
- ++card->wandev.stats.tx_dropped
- ;
- else if (!skb->protocol)
- ++card->wandev.stats.tx_errors
- ;
- else if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
- ppp_flags_t *flags = card->flags;
- flags->imask |= 0x02; /* unmask Tx interrupts */
- retry = 1;
- } else
- ++card->wandev.stats.tx_packets;
+ if (dev->tbusy) {
+
+ /* If our device stays busy for at least 5 seconds then we will
+ * kick start the device by making dev->tbusy = 0. We expect
+ * that our device never stays busy more than 5 seconds. So this
+ * is only used as a last resort.
+ */
+
+ ++ppp_priv_area->if_send_busy;
+ ++card->wandev.stats.collisions;
- if (!retry) {
- dev_kfree_skb(skb, FREE_WRITE);
+ if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) {
+ return 1;
+ }
+
+ printk (KERN_INFO "%s: Transmit times out\n",card->devname);
+
+ ++ppp_priv_area->if_send_busy_timeout;
+
+ /* unbusy the card (because only one interface per card)*/
dev->tbusy = 0;
+ }
+ sendpacket = skb->data;
+#ifdef CONFIG_SANGOMA_MANAGER
+ if(sangoma_ppp_manager(skb,card))
+ {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+#endif
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_if_send_count;
+
+ if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ {
+ if (card->wandev.critical == CRITICAL_IN_ISR)
+ {
+ /* If the critical flag is set due to an Interrupt
+ * then set enable transmit interrupt flag to enable
+ * transmit interrupt. (delay interrupt)
+ */
+ card->wandev.enable_tx_int = 1;
+ dev->tbusy = 1;
+
+ /* set the counter to see if we get the interrupt in
+ * 5 seconds.
+ */
+ ppp_priv_area->tick_counter = jiffies;
+ ++ppp_priv_area->if_send_critical_ISR;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return 1;
+
+ }
+
+ dev_kfree_skb(skb);
+ ++ppp_priv_area->if_send_critical_non_ISR;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return 0;
+ }
+
+
+ if (card->wandev.state != WAN_CONNECTED) {
+
+ ++ppp_priv_area->if_send_wan_disconnected;
+ ++card->wandev.stats.tx_dropped;
+
+ } else if (!skb->protocol) {
+ ++ppp_priv_area->if_send_protocol_error;
+ ++card->wandev.stats.tx_errors;
+
+ } else {
+
+ /*If it's IPX change the network numbers to 0 if they're ours.*/
+ if( skb->protocol == ETH_P_IPX ) {
+ if(card->wandev.enable_IPX) {
+ switch_net_numbers( skb->data,
+ card->wandev.network_number, 0);
+ } else {
+ ++card->wandev.stats.tx_dropped;
+ goto tx_done;
+ }
+ }
+
+ if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
+
+ retry = 1;
+ dev->tbusy = 1;
+ ++ppp_priv_area->if_send_adptr_bfrs_full;
+ ++ppp_priv_area->if_send_tx_int_enabled;
+ ppp_priv_area->tick_counter = jiffies;
+ ++card->wandev.stats.tx_errors;
+ flags->imask |= 0x02; /* unmask Tx interrupts */
+
+ } else {
+ ++ppp_priv_area->if_send_bfr_passed_to_adptr;
+ ++card->wandev.stats.tx_packets;
+ }
+ }
+
+tx_done:
+ if (!retry){
+ dev_kfree_skb(skb);
}
+
card->wandev.critical = 0;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
return retry;
}
+/*
+ If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+ if incoming is 1 - if the net number is 0 make it ours
+
+*/
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+ unsigned long pnetwork_number;
+
+ pnetwork_number = (unsigned long)((sendpacket[6] << 24) +
+ (sendpacket[7] << 16) + (sendpacket[8] << 8) +
+ sendpacket[9]);
+
+ if (!incoming)
+ {
+ /* If the destination network number is ours, make it 0 */
+ if( pnetwork_number == network_number)
+ {
+ sendpacket[6] = sendpacket[7] = sendpacket[8] =
+ sendpacket[9] = 0x00;
+ }
+ }
+ else
+ {
+ /* If the incoming network is 0, make it ours */
+ if( pnetwork_number == 0)
+ {
+ sendpacket[6] = (unsigned char)(network_number >> 24);
+ sendpacket[7] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[8] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[9] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+
+
+ pnetwork_number = (unsigned long)((sendpacket[18] << 24) +
+ (sendpacket[19] << 16) + (sendpacket[20] << 8) +
+ sendpacket[21]);
+
+ if( !incoming )
+ {
+ /* If the source network is ours, make it 0 */
+ if( pnetwork_number == network_number)
+ {
+ sendpacket[18] = sendpacket[19] = sendpacket[20] =
+ sendpacket[21] = 0x00;
+ }
+ }
+ else
+ {
+ /* If the source network is 0, make it ours */
+ if( pnetwork_number == 0 )
+ {
+ sendpacket[18] = (unsigned char)(network_number >> 24);
+ sendpacket[19] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[20] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[21] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+} /* switch_net_numbers */
+
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
-
-static struct enet_statistics *if_stats(struct device *dev)
+static struct net_device_stats* if_stats (struct device* dev)
{
- sdla_t *card = dev->priv;
+ ppp_private_area_t* ppp_priv_area = dev->priv;
+ sdla_t* card = ppp_priv_area->card;
return &card->wandev.stats;
}
@@ -539,125 +886,146 @@ static struct enet_statistics *if_stats(struct device *dev)
* Read firmware code version.
* Put code version as ASCII string in str.
*/
-static int ppp_read_version(sdla_t * card, char *str)
+static int ppp_read_version (sdla_t* card, char* str)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_READ_CODE_VERSION;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
if (err != CMD_OK)
+
ppp_error(card, err, mb);
+
else if (str) {
+
int len = mb->cmd.length;
memcpy(str, mb->data, len);
str[len] = '\0';
+
}
+
return err;
}
/*============================================================================
* Configure PPP firmware.
*/
-static int ppp_configure(sdla_t * card, void *data)
+static int ppp_configure (sdla_t* card, void* data)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int data_len = (card->hw.fwid == SFID_PPP502) ?
- sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
+ sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t);
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
memcpy(mb->data, data, data_len);
- mb->cmd.length = data_len;
+ mb->cmd.length = data_len;
mb->cmd.command = PPP_SET_CONFIG;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
+
+ if (err != CMD_OK)
ppp_error(card, err, mb);
+
return err;
}
/*============================================================================
* Set interrupt mode.
*/
-static int ppp_set_intr_mode(sdla_t * card, unsigned mode)
+static int ppp_set_intr_mode (sdla_t* card, unsigned mode)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->data[0] = mode;
- switch (card->hw.fwid) {
- case SFID_PPP502:
- mb->cmd.length = 1;
- break;
-
- case SFID_PPP508:
- default:
- mb->data[1] = card->hw.irq;
- mb->cmd.length = 2;
+
+ switch (card->hw.fwid)
+ {
+ case SFID_PPP502:
+ mb->cmd.length = 1;
+ break;
+
+ case SFID_PPP508:
+
+ default:
+ mb->data[1] = card->hw.irq;
+ mb->cmd.length = 2;
}
+
mb->cmd.command = PPP_SET_INTR_FLAGS;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
+
+ if (err != CMD_OK)
ppp_error(card, err, mb);
+
return err;
}
/*============================================================================
* Enable communications.
*/
-static int ppp_comm_enable(sdla_t * card)
+static int ppp_comm_enable (sdla_t* card)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_COMM_ENABLE;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
+
+ if (err != CMD_OK)
ppp_error(card, err, mb);
+
return err;
}
/*============================================================================
* Disable communications.
*/
-static int ppp_comm_disable(sdla_t * card)
+static int ppp_comm_disable (sdla_t* card)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_COMM_DISABLE;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
+
+ if (err != CMD_OK)
ppp_error(card, err, mb);
+
return err;
}
/*============================================================================
* Get communications error statistics.
*/
-static int ppp_get_err_stats(sdla_t * card)
+static int ppp_get_err_stats (sdla_t* card)
{
- ppp_mbox_t *mb = card->mbox;
+ ppp_mbox_t* mb = card->mbox;
int err;
memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
mb->cmd.command = PPP_READ_ERROR_STATS;
err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err == CMD_OK) {
- ppp_err_stats_t *stats = (void *) mb->data;
-
- card->wandev.stats.rx_over_errors = stats->rx_overrun;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_abort;
- card->wandev.stats.rx_length_errors = stats->rx_lost;
+
+ if (err == CMD_OK)
+ {
+ ppp_err_stats_t* stats = (void*)mb->data;
+ card->wandev.stats.rx_over_errors = stats->rx_overrun;
+ card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
+ card->wandev.stats.rx_missed_errors = stats->rx_abort;
+ card->wandev.stats.rx_length_errors = stats->rx_lost;
card->wandev.stats.tx_aborted_errors = stats->tx_abort;
- } else
+
+ } else
ppp_error(card, err, mb);
+
return err;
}
@@ -666,34 +1034,36 @@ static int ppp_get_err_stats(sdla_t * card)
* Return: 0 - o.k.
* 1 - no transmit buffers available
*/
-static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
+
+static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto)
{
- ppp_buf_ctl_t *txbuf = card->u.p.txbuf;
- unsigned long addr, cpu_flags;
+ ppp_buf_ctl_t* txbuf = card->u.p.txbuf;
+ unsigned long addr;
if (txbuf->flag)
- return 1
- ;
+ return 1;
+
if (card->hw.fwid == SFID_PPP502)
- addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
- else
+ addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0];
+ else
addr = txbuf->buf.ptr;
- save_flags(cpu_flags);
- cli();
+
sdla_poke(&card->hw, addr, data, len);
- restore_flags(cpu_flags);
- txbuf->length = len; /* frame length */
+
+ txbuf->length = len; /* frame length */
+
if (proto == ETH_P_IPX)
- txbuf->proto = 0x01 /* protocol ID */
- ;
- txbuf->flag = 1; /* start transmission */
+ txbuf->proto = 0x01; /* protocol ID */
+
+ txbuf->flag = 1; /* start transmission */
/* Update transmit buffer control fields */
card->u.p.txbuf = ++txbuf;
- if ((void *) txbuf > card->u.p.txbuf_last)
- card->u.p.txbuf = card->u.p.txbuf_base
- ;
+
+ if ((void*)txbuf > card->u.p.txbuf_last)
+ card->u.p.txbuf = card->u.p.txbuf_base;
+
return 0;
}
@@ -706,20 +1076,23 @@ static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto)
*
* Return zero if previous command has to be cancelled.
*/
-static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
+
+static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb)
{
unsigned cmd = mb->cmd.command;
- switch (err) {
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
+ switch (err)
+ {
+ case CMD_TIMEOUT:
+ printk(KERN_ERR "%s: command 0x%02X timed out!\n",
+ card->devname, cmd);
+ break;
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, cmd, err);
+ default:
+ printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
+ , card->devname, cmd, err);
}
+
return 0;
}
@@ -728,112 +1101,361 @@ static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb)
/*============================================================================
* PPP interrupt service routine.
*/
-STATIC void wpp_isr(sdla_t * card)
+STATIC void wpp_isr (sdla_t* card)
{
- ppp_flags_t *flags = card->flags;
+ ppp_flags_t* flags = card->flags;
+ char *ptr = &flags->iflag;
+ unsigned long host_cpu_flags;
+ struct device* dev = card->wandev.dev;
+ int i;
+
+ card->in_isr = 1;
+
+ ++card->statistics.isr_entry;
+
+ if (set_bit(0, (void*)&card->wandev.critical)) {
+
+ ++card->statistics.isr_already_critical;
+ printk (KERN_INFO "%s: Critical while in ISR!\n",card->devname);
+ card->in_isr = 0;
+ return;
+
+ }
+
+ /* For all interrupts set the critical flag to CRITICAL_IN_ISR.
+ * If the if_send routine is called with this flag set it will set
+ * the enable transmit flag to 1. (for a delayed interrupt)
+ */
+ card->wandev.critical = CRITICAL_IN_ISR;
+
+ card->buff_int_mode_unbusy = 0;
switch (flags->iflag) {
- case 0x01: /* receive interrupt */
- rx_intr(card);
- break;
-
- case 0x02: /* transmit interrupt */
- flags->imask &= ~0x02;
- tx_intr(card);
- break;
-
- default: /* unexpected interrupt */
- printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
- card->devname, flags->iflag);
+
+ case 0x01: /* receive interrupt */
+ ++card->statistics.isr_rx;
+ rx_intr(card);
+ break;
+
+ case 0x02: /* transmit interrupt */
+ ++card->statistics.isr_tx;
+ flags->imask &= ~0x02;
+ dev->tbusy = 0;
+ card->buff_int_mode_unbusy = 1;
+ break;
+
+ case 0x08:
+ ++Intr_test_counter;
+ ++card->statistics.isr_intr_test;
+ break;
+
+ default: /* unexpected interrupt */
+ ++card->statistics.isr_spurious;
+ printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
+ card->devname, flags->iflag);
+ printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+ for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
+ }
+
+ /* The critical flag is set to CRITICAL_INTR_HANDLED to let the
+ * if_send call know that the interrupt is handled so that
+ * transmit interrupts are not enabled again.
+ */
+
+ card->wandev.critical = CRITICAL_INTR_HANDLED;
+
+ /* If the enable transmit interrupt flag is set then enable transmit
+ * interrupt on the board. This only goes through if if_send is called
+ * and the critical flag is set due to an Interrupt.
+ */
+ if(card->wandev.enable_tx_int) {
+
+ flags->imask |= 0x02;
+ card->wandev.enable_tx_int = 0;
+ ++card->statistics.isr_enable_tx_int;
+
}
+ save_flags(host_cpu_flags);
+ cli();
+ card->in_isr = 0;
flags->iflag = 0;
+ card->wandev.critical = 0;
+ restore_flags(host_cpu_flags);
+
+ if(card->buff_int_mode_unbusy)
+ mark_bh(NET_BH);
+
}
/*============================================================================
* Receive interrupt handler.
*/
-static void rx_intr(sdla_t * card)
+static void rx_intr (sdla_t* card)
{
- ppp_buf_ctl_t *rxbuf = card->rxmb;
- struct device *dev = card->wandev.dev;
- struct sk_buff *skb;
+ ppp_buf_ctl_t* rxbuf = card->rxmb;
+ struct device* dev = card->wandev.dev;
+ ppp_private_area_t* ppp_priv_area;
+ struct sk_buff* skb;
unsigned len;
- void *buf;
+ void* buf;
+ int i, err;
+ ppp_flags_t* flags = card->flags;
+ char *ptr = &flags->iflag;
+ int udp_type;
+
if (rxbuf->flag != 0x01) {
- printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
- card->devname, (unsigned) rxbuf);
+
+
+ printk(KERN_INFO
+ "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
+ card->devname, (unsigned)rxbuf, rxbuf->flag);
+
+ printk(KERN_INFO "%s: ID Bytes = ",card->devname);
+
+ for(i = 0; i < 8; i ++)
+ printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
+ printk(KERN_INFO "\n");
+
+ ++card->statistics.rx_intr_corrupt_rx_bfr;
return;
- }
- if (!dev || !dev->start)
- goto rx_done
- ;
- len = rxbuf->length;
- /* Allocate socket buffer */
- skb = dev_alloc_skb(len);
- if (skb == NULL) {
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- ++card->wandev.stats.rx_dropped;
- goto rx_done;
}
- /* Copy data to the socket buffer */
- if (card->hw.fwid == SFID_PPP502) {
- unsigned addr = (rxbuf->buf.o_p[1] << 8) + rxbuf->buf.o_p[0];
-
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, addr, buf, len);
- } else {
- unsigned addr = rxbuf->buf.ptr;
-
- if ((addr + len) > card->u.p.rx_top + 1) {
- unsigned tmp = card->u.p.rx_top - addr + 1;
+
+
+ if (dev && dev->start) {
+
+ len = rxbuf->length;
+ ppp_priv_area = dev->priv;
+
+ /* Allocate socket buffer */
+ skb = dev_alloc_skb(len);
+
+ if (skb != NULL) {
+
+ /* Copy data to the socket buffer */
+ if (card->hw.fwid == SFID_PPP502) {
+
+ unsigned addr = (rxbuf->buf.o_p[1] << 8) +
+ rxbuf->buf.o_p[0];
+ buf = skb_put(skb, len);
+ sdla_peek(&card->hw, addr, buf, len);
+
+ } else {
+
+ unsigned addr = rxbuf->buf.ptr;
+
+ if ((addr + len) > card->u.p.rx_top + 1) {
+
+ unsigned tmp = card->u.p.rx_top - addr
+ + 1;
+ buf = skb_put(skb, tmp);
+ sdla_peek(&card->hw, addr, buf, tmp);
+ addr = card->u.p.rx_base;
+ len -= tmp;
+
+ }
+
+ buf = skb_put(skb, len);
+ sdla_peek(&card->hw, addr, buf, len);
+ }
+
+ /* Decapsulate packet */
+ switch (rxbuf->proto) {
+
+ case 0x00:
+ skb->protocol = htons(ETH_P_IP);
+ break;
+
+ case 0x01:
+ skb->protocol = htons(ETH_P_IPX);
+ break;
+ }
+#ifdef CONFIG_SANGOMA_MANAGER
+ udp_type = udp_pkt_type( skb, card );
+
+ if (udp_type == UDP_DRVSTATS_TYPE){
+ ++ppp_priv_area->rx_intr_DRVSTATS_request;
+ process_udp_driver_call(
+ UDP_PKT_FRM_NETWORK, card, skb,
+ dev, ppp_priv_area);
+ dev_kfree_skb(skb);
+
+ } else if (udp_type == UDP_PTPIPE_TYPE){
+ ++ppp_priv_area->rx_intr_PTPIPE_request;
+ err = process_udp_mgmt_pkt(
+ UDP_PKT_FRM_NETWORK, card,
+ skb, dev, ppp_priv_area);
+ dev_kfree_skb(skb);
+ } else
+#endif
+ if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) {
+
+ if( card->wandev.enable_IPX) {
+ ppp_send(card, skb->data, skb->len, ETH_P_IPX);
+ dev_kfree_skb(skb);
+
+ } else {
+ ++card->wandev.stats.rx_dropped;
+ }
+ } else {
+ /* Pass it up the protocol stack */
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ ++card->wandev.stats.rx_packets;
+ ++ppp_priv_area->rx_intr_bfr_passed_to_stack;
+ }
+
+ } else {
+
+ printk(KERN_INFO "%s: no socket buffers available!\n",
+ card->devname);
+ ++card->wandev.stats.rx_dropped;
+ ++ppp_priv_area->rx_intr_no_socket;
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, addr, buf, tmp);
- addr = card->u.p.rx_base;
- len -= tmp;
}
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, addr, buf, len);
- }
- /* Decapsulate packet */
- switch (rxbuf->proto) {
- case 0x00:
- skb->protocol = htons(ETH_P_IP);
- break;
-
- case 0x01:
- skb->protocol = htons(ETH_P_IPX);
- break;
- }
+ } else
+ ++card->statistics.rx_intr_dev_not_started;
- /* Pass it up the protocol stack */
- skb->dev = dev;
- netif_rx(skb);
- ++card->wandev.stats.rx_packets;
- rx_done:
/* Release buffer element and calculate a pointer to the next one */
rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
card->rxmb = ++rxbuf;
- if ((void *) rxbuf > card->u.p.rxbuf_last)
- card->rxmb = card->u.p.rxbuf_base
- ;
+
+ if ((void*)rxbuf > card->u.p.rxbuf_last)
+ card->rxmb = card->u.p.rxbuf_base;
}
/*============================================================================
* Transmit interrupt handler.
*/
-static void tx_intr(sdla_t * card)
+static void tx_intr (sdla_t* card)
{
- struct device *dev = card->wandev.dev;
+ struct device* dev = card->wandev.dev;
+
+ if (!dev || !dev->start)
+ {
+ ++card->statistics.tx_intr_dev_not_started;
+ return;
+ }
- if (!dev || !dev->start)
- return;
dev->tbusy = 0;
- mark_bh(NET_BH);
+ dev_tint(dev);
+}
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
+{
+ int i;
+
+ if( proto == htons(ETH_P_IPX) )
+ {
+ /* It's an IPX packet */
+ if(!enable_IPX)
+ {
+ //Return 1 so we don't pass it up the stack.
+ return 1;
+ }
+ }
+ else
+ {
+ /* It's not IPX so pass it up the stack. */
+ return 0;
+ }
+
+ if( sendpacket[16] == 0x90 &&
+ sendpacket[17] == 0x04)
+ {
+ /* It's IPXWAN */
+
+ if( sendpacket[2] == 0x02 &&
+ sendpacket[34] == 0x00)
+ {
+ /* It's a timer request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+ /* Go through the routing options and answer no to every */
+ /* option except Unnumbered RIP/SAP */
+ for(i = 41; sendpacket[i] == 0x00; i += 5)
+ {
+ /* 0x02 is the option for Unnumbered RIP/SAP */
+ if( sendpacket[i + 4] != 0x02)
+ {
+ sendpacket[i + 1] = 0;
+ }
+ }
+
+ /* Skip over the extended Node ID option */
+ if( sendpacket[i] == 0x04 )
+ {
+ i += 8;
+ }
+
+ /* We also want to turn off all header compression opt. */
+ for(; sendpacket[i] == 0x80 ;)
+ {
+ sendpacket[i + 1] = 0;
+ i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+ }
+
+ /* Set the packet type to timer response */
+ sendpacket[34] = 0x01;
+
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+ }
+ else if( sendpacket[34] == 0x02 )
+ {
+ /* This is an information request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
+ /* Set the packet type to information response */
+ sendpacket[34] = 0x03;
+
+ /* Set the router name */
+ sendpacket[51] = 'P';
+ sendpacket[52] = 'T';
+ sendpacket[53] = 'P';
+ sendpacket[54] = 'I';
+ sendpacket[55] = 'P';
+ sendpacket[56] = 'E';
+ sendpacket[57] = '-';
+ sendpacket[58] = CVHexToAscii(network_number >> 28);
+ sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+ sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+ sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+ sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+ sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+ sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
+ for(i = 66; i < 99; i+= 1)
+ {
+ sendpacket[i] = 0;
+ }
+
+ printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
+ }
+ else
+ {
+ printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
+ return 0;
+ }
+
+ /* Set the WNodeID to our network address */
+ sendpacket[35] = (unsigned char)(network_number >> 24);
+ sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+ sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+ sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
+
+ return 1;
+ } else {
+ /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */
+
+ /* switch the network numbers */
+ switch_net_numbers(sendpacket, network_number, 1);
+ return 0;
+ }
}
/****** Background Polling Routines ****************************************/
@@ -847,33 +1469,100 @@ static void tx_intr(sdla_t * card)
* 1. This routine may be called on interrupt context with all interrupts
* enabled. Beware!
*/
-static void wpp_poll(sdla_t * card)
+static void wpp_poll (sdla_t* card)
{
- switch (card->wandev.state) {
- case WAN_CONNECTED:
- poll_active(card);
- break;
-
- case WAN_CONNECTING:
- poll_connecting(card);
- break;
-
- case WAN_DISCONNECTED:
- poll_disconnected(card);
- break;
+ struct device* dev = card->wandev.dev;
+ ppp_flags_t* adptr_flags = card->flags;
+ unsigned long host_cpu_flags;
+
+ ++card->statistics.poll_entry;
+
+ /* The wpp_poll is called continously by the WANPIPE thread to allow
+ * for line state housekeeping. However if we are in a connected state
+ * then we do not need to go through all the checks everytime. When in
+ * connected state execute wpp_poll once every second.
+ */
+
+ if (card->wandev.state == WAN_CONNECTED)
+ {
+ if ((jiffies - card->state_tick) < HZ )
+ return;
+ }
+
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_poll_count;
+
+ if (set_bit(0, (void *)&card->wandev.critical))
+ {
+ ++card->statistics.poll_already_critical;
+ printk(KERN_INFO "%s: critical inside wpp_poll\n",
+ card->devname);
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) &&
+ (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return;
+ }
+
+ ++card->statistics.poll_processed;
+
+ if (dev && dev->tbusy && !(adptr_flags->imask & 0x02))
+ {
+ ++card->statistics.poll_tbusy_bad_status;
+ printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n"
+ , card->devname, adptr_flags->imask);
+ }
+
+ switch(card->wandev.state)
+ {
+ case WAN_CONNECTED:
+ card->state_tick = jiffies;
+ poll_active(card);
+ break;
+
+ case WAN_CONNECTING:
+ poll_connecting(card);
+ break;
+
+ case WAN_DISCONNECTED:
+ poll_disconnected(card);
+ break;
+
+ default:
+ printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n",
+ card->devname, card->wandev.state);
+ break;
}
+
+ card->wandev.critical = 0;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
}
/*============================================================================
* Monitor active link phase.
*/
-static void poll_active(sdla_t * card)
+static void poll_active (sdla_t* card)
{
- ppp_flags_t *flags = card->flags;
+ ppp_flags_t* flags = card->flags;
+
+ /* We check the lcp_state to see if we are in DISCONNECTED state.
+ * We are considered to be connected for lcp states 0x06, 0x07, 0x08
+ * and 0x09.
+ */
+ if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) {
- if (flags->disc_cause & 0x03) {
wanpipe_set_state(card, WAN_DISCONNECTED);
show_disc_cause(card, flags->disc_cause);
+
}
}
@@ -881,13 +1570,16 @@ static void poll_active(sdla_t * card)
* Monitor link establishment phase.
* o if connection timed out, disconnect the link.
*/
-static void poll_connecting(sdla_t * card)
+static void poll_connecting (sdla_t* card)
{
- ppp_flags_t *flags = card->flags;
-
- if (flags->lcp_state == 0x09) {
+ ppp_flags_t* flags = card->flags;
+
+ if (flags->lcp_state == 0x09)
+ {
wanpipe_set_state(card, WAN_CONNECTED);
- } else if (flags->disc_cause & 0x03) {
+ }
+ else if (flags->disc_cause & 0x03)
+ {
wanpipe_set_state(card, WAN_DISCONNECTED);
show_disc_cause(card, flags->disc_cause);
}
@@ -898,14 +1590,16 @@ static void poll_connecting(sdla_t * card)
* o if interface is up and the hold-down timeout has expired, then retry
* connection.
*/
-static void poll_disconnected(sdla_t * card)
+static void poll_disconnected (sdla_t* card)
{
- struct device *dev = card->wandev.dev;
+ struct device* dev = card->wandev.dev;
if (dev && dev->start &&
- ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
- wanpipe_set_state(card, WAN_CONNECTING);
- ppp_comm_enable(card);
+ ((jiffies - card->state_tick) > HOLD_DOWN_TIME))
+ {
+ wanpipe_set_state(card, WAN_CONNECTING);
+ if(ppp_comm_enable(card) == CMD_OK)
+ init_ppp_tx_rx_buff( card );
}
}
@@ -914,7 +1608,7 @@ static void poll_disconnected(sdla_t * card)
/*============================================================================
* Configure S502 adapter.
*/
-static int config502(sdla_t * card)
+static int config502 (sdla_t* card)
{
ppp502_conf_t cfg;
@@ -923,33 +1617,34 @@ static int config502(sdla_t * card)
if (card->wandev.clocking)
cfg.line_speed = bps_to_speed_code(card->wandev.bps);
- cfg.txbuf_num = 4;
- cfg.mtu_local = card->wandev.mtu;
- cfg.mtu_remote = card->wandev.mtu;
- cfg.restart_tmr = 30;
- cfg.auth_rsrt_tmr = 30;
- cfg.auth_wait_tmr = 300;
- cfg.mdm_fail_tmr = 5;
- cfg.dtr_drop_tmr = 1;
- cfg.connect_tmout = 0; /* changed it from 900 */
- cfg.conf_retry = 10;
- cfg.term_retry = 2;
- cfg.fail_retry = 5;
- cfg.auth_retry = 10;
- cfg.ip_options = 0x80;
- cfg.ipx_options = 0xA0;
- cfg.conf_flags |= 0x0E;
+
+ cfg.txbuf_num = 4;
+ cfg.mtu_local = card->wandev.mtu;
+ cfg.mtu_remote = card->wandev.mtu;
+ cfg.restart_tmr = 30;
+ cfg.auth_rsrt_tmr = 30;
+ cfg.auth_wait_tmr = 300;
+ cfg.mdm_fail_tmr = 5;
+ cfg.dtr_drop_tmr = 1;
+ cfg.connect_tmout = 0; /* changed it from 900 */
+ cfg.conf_retry = 10;
+ cfg.term_retry = 2;
+ cfg.fail_retry = 5;
+ cfg.auth_retry = 10;
+ cfg.ip_options = 0x80;
+ cfg.ipx_options = 0xA0;
+ cfg.conf_flags |= 0x0E;
/*
- cfg.ip_local = dev->pa_addr;
- cfg.ip_remote = dev->pa_dstaddr;
- */
+ cfg.ip_local = dev->pa_addr;
+ cfg.ip_remote = dev->pa_dstaddr;
+*/
return ppp_configure(card, &cfg);
}
/*============================================================================
* Configure S508 adapter.
*/
-static int config508(sdla_t * card)
+static int config508 (sdla_t* card)
{
ppp508_conf_t cfg;
@@ -957,111 +1652,275 @@ static int config508(sdla_t * card)
memset(&cfg, 0, sizeof(ppp508_conf_t));
if (card->wandev.clocking)
- cfg.line_speed = card->wandev.bps
- ;
+ cfg.line_speed = card->wandev.bps;
+
if (card->wandev.interface == WANOPT_RS232)
cfg.conf_flags |= 0x0020;
- ;
- cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */
- cfg.txbuf_percent = 60; /* % of Tx bufs */
- cfg.mtu_local = card->wandev.mtu;
- cfg.mtu_remote = card->wandev.mtu;
- cfg.restart_tmr = 30;
- cfg.auth_rsrt_tmr = 30;
- cfg.auth_wait_tmr = 300;
- cfg.mdm_fail_tmr = 5;
- cfg.dtr_drop_tmr = 1;
- cfg.connect_tmout = 0; /* changed it from 900 */
- cfg.conf_retry = 10;
- cfg.term_retry = 2;
- cfg.fail_retry = 5;
- cfg.auth_retry = 10;
- cfg.ip_options = 0x80;
- cfg.ipx_options = 0xA0;
+
+ cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/
+ cfg.txbuf_percent = 60; /* % of Tx bufs */
+ cfg.mtu_local = card->wandev.mtu;
+ cfg.mtu_remote = card->wandev.mtu;
+ cfg.restart_tmr = 30;
+ cfg.auth_rsrt_tmr = 30;
+ cfg.auth_wait_tmr = 300;
+ cfg.mdm_fail_tmr = 100;
+ cfg.dtr_drop_tmr = 1;
+ cfg.connect_tmout = 0; /* changed it from 900 */
+ cfg.conf_retry = 10;
+ cfg.term_retry = 2;
+ cfg.fail_retry = 5;
+ cfg.auth_retry = 10;
+ cfg.ip_options = 0x80;
+ cfg.ipx_options = 0xA0;
/*
- cfg.ip_local = dev->pa_addr;
- cfg.ip_remote = dev->pa_dstaddr;
- */
+ cfg.ip_local = dev->pa_addr;
+ cfg.ip_remote = dev->pa_dstaddr;
+*/
return ppp_configure(card, &cfg);
}
/*============================================================================
* Show disconnection cause.
*/
-static void show_disc_cause(sdla_t * card, unsigned cause)
+static void show_disc_cause (sdla_t* card, unsigned cause)
{
- if (cause & 0x0002)
- printk(KERN_INFO
- "%s: link terminated by peer\n", card->devname);
- else if (cause & 0x0004)
- printk(KERN_INFO
- "%s: link terminated by user\n", card->devname);
- else if (cause & 0x0008)
- printk(KERN_INFO
- "%s: authentication failed\n", card->devname);
+ if (cause & 0x0002)
+ printk(KERN_INFO "%s: link terminated by peer\n",
+ card->devname);
+
+ else if (cause & 0x0004)
+ printk(KERN_INFO "%s: link terminated by user\n",
+ card->devname);
+
+ else if (cause & 0x0008)
+ printk(KERN_INFO "%s: authentication failed\n", card->devname);
+
else if (cause & 0x0010)
+ printk(KERN_INFO
+ "%s: authentication protocol negotiation failed\n",
+ card->devname);
+
+ else if (cause & 0x0020)
printk(KERN_INFO
- "%s: authentication protocol negotiation failed\n",
- card->devname);
- else if (cause & 0x0020)
- printk(KERN_INFO
- "%s: peer's request for authentication rejected\n",
- card->devname);
- else if (cause & 0x0040)
- printk(KERN_INFO
- "%s: MRU option rejected by peer\n", card->devname);
- else if (cause & 0x0080)
- printk(KERN_INFO
- "%s: peer's MRU was too small\n", card->devname);
- else if (cause & 0x0100)
- printk(KERN_INFO
- "%s: failed to negotiate peer's LCP options\n",
- card->devname);
- else if (cause & 0x0200)
- printk(KERN_INFO
- "%s: failed to negotiate peer's IPCP options\n",
- card->devname);
- else if (cause & 0x0400)
- printk(KERN_INFO
- "%s: failed to negotiate peer's IPXCP options\n",
- card->devname);
+ "%s: peer's request for authentication rejected\n",
+ card->devname);
+
+ else if (cause & 0x0040)
+ printk(KERN_INFO "%s: MRU option rejected by peer\n",
+ card->devname);
+
+ else if (cause & 0x0080)
+ printk(KERN_INFO "%s: peer's MRU was too small\n",
+ card->devname);
+
+ else if (cause & 0x0100)
+ printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n",
+ card->devname);
+
+ else if (cause & 0x0200)
+ printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n"
+ , card->devname);
+
+ else if (cause & 0x0400)
+ printk(KERN_INFO
+ "%s: failed to negotiate peer's IPXCP options\n",
+ card->devname);
}
/*============================================================================
* Convert line speed in bps to a number used by S502 code.
*/
-static unsigned char bps_to_speed_code(unsigned long bps)
+static unsigned char bps_to_speed_code (unsigned long bps)
{
- unsigned char number;
+ unsigned char number;
- if (bps <= 1200)
+ if (bps <= 1200)
number = 0x01;
- else if (bps <= 2400)
+ else if (bps <= 2400)
number = 0x02;
- else if (bps <= 4800)
+ else if (bps <= 4800)
number = 0x03;
- else if (bps <= 9600)
+ else if (bps <= 9600)
number = 0x04;
- else if (bps <= 19200)
+ else if (bps <= 19200)
number = 0x05;
- else if (bps <= 38400)
+ else if (bps <= 38400)
number = 0x06;
- else if (bps <= 45000)
+ else if (bps <= 45000)
number = 0x07;
- else if (bps <= 56000)
+ else if (bps <= 56000)
number = 0x08;
- else if (bps <= 64000)
+ else if (bps <= 64000)
number = 0x09;
- else if (bps <= 74000)
+ else if (bps <= 74000)
number = 0x0A;
- else if (bps <= 112000)
+ else if (bps <= 112000)
number = 0x0B;
- else if (bps <= 128000)
+ else if (bps <= 128000)
number = 0x0C;
- else
+ else
number = 0x0D;
return number;
}
+/*=============================================================================
+ * Initial the ppp_private_area structure.
+ */
+
+static void init_ppp_priv_struct( ppp_private_area_t* ppp_priv_area )
+{
+ ppp_priv_area->if_send_entry = 0;
+ ppp_priv_area->if_send_skb_null = 0;
+ ppp_priv_area->if_send_broadcast = 0;
+ ppp_priv_area->if_send_multicast = 0;
+ ppp_priv_area->if_send_critical_ISR = 0;
+ ppp_priv_area->if_send_critical_non_ISR = 0;
+ ppp_priv_area->if_send_busy = 0;
+ ppp_priv_area->if_send_busy_timeout = 0;
+ ppp_priv_area->if_send_DRVSTATS_request = 0;
+ ppp_priv_area->if_send_PTPIPE_request = 0;
+ ppp_priv_area->if_send_wan_disconnected = 0;
+ ppp_priv_area->if_send_adptr_bfrs_full = 0;
+ ppp_priv_area->if_send_bfr_passed_to_adptr = 0;
+
+ ppp_priv_area->rx_intr_no_socket = 0;
+ ppp_priv_area->rx_intr_DRVSTATS_request = 0;
+ ppp_priv_area->rx_intr_PTPIPE_request = 0;
+ ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0;
+ ppp_priv_area->rx_intr_bfr_passed_to_stack = 0;
+
+ ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0;
+ ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0;
+
+ ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0;
+ ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0;
+}
+
+/*============================================================================
+ * Initialize Global Statistics
+ */
+static void init_global_statistics( sdla_t* card )
+{
+ card->statistics.isr_entry = 0;
+ card->statistics.isr_already_critical = 0;
+ card->statistics.isr_tx = 0;
+ card->statistics.isr_rx = 0;
+ card->statistics.isr_intr_test = 0;
+ card->statistics.isr_spurious = 0;
+ card->statistics.isr_enable_tx_int = 0;
+ card->statistics.rx_intr_corrupt_rx_bfr = 0;
+ card->statistics.rx_intr_dev_not_started= 0;
+ card->statistics.tx_intr_dev_not_started= 0;
+ card->statistics.poll_entry = 0;
+ card->statistics.poll_already_critical = 0;
+ card->statistics.poll_processed = 0;
+ card->statistics.poll_tbusy_bad_status = 0;
+
+}
+
+/*============================================================================
+ * Initialize Receive and Transmit Buffers.
+ */
+static void init_ppp_tx_rx_buff( sdla_t* card )
+{
+
+ if (card->hw.fwid == SFID_PPP502)
+ {
+ ppp502_buf_info_t* info =
+ (void*)(card->hw.dpmbase + PPP502_BUF_OFFS);
+
+ card->u.p.txbuf_base =
+ (void*)(card->hw.dpmbase + info->txb_offs);
+
+ card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+ (info->txb_num - 1);
+
+ card->u.p.rxbuf_base =
+ (void*)(card->hw.dpmbase + info->rxb_offs);
+
+ card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+ (info->rxb_num - 1);
+ }
+ else
+ {
+ ppp508_buf_info_t* info =
+ (void*)(card->hw.dpmbase + PPP508_BUF_OFFS);
+
+ card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
+ (info->txb_ptr - PPP508_MB_VECT));
+
+ card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
+ (info->txb_num - 1);
+
+ card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
+ (info->rxb_ptr - PPP508_MB_VECT));
+
+ card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
+ (info->rxb_num - 1);
+
+ card->u.p.rx_base = info->rxb_base;
+ card->u.p.rx_top = info->rxb_end;
+ }
+
+ card->u.p.txbuf = card->u.p.txbuf_base;
+ card->rxmb = card->u.p.rxbuf_base;
+
+}
+
+/*=============================================================================
+ * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
+ * _TEST_COUNTER times.
+ */
+static int intr_test( sdla_t* card )
+{
+ ppp_mbox_t* mb = card->mbox;
+ int err,i;
+
+ /* The critical flag is unset because during intialization (if_open)
+ * we want the interrupts to be enabled so that when the wpp_isr is
+ * called it does not exit due to critical flag set.
+ */
+
+ card->wandev.critical = 0;
+
+ err = ppp_set_intr_mode( card, 0x08 );
+
+ if ( err == CMD_OK )
+ {
+ for (i=0; i<MAX_INTR_TEST_COUNTER; i++)
+ {
+ /* Run command READ_CODE_VERSION */
+ memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+ mb->cmd.length = 0;
+ mb->cmd.command = 0x10;
+ err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+
+ if (err != CMD_OK)
+ ppp_error(card, err, mb);
+ }
+ }
+ else return err;
+
+ err = ppp_set_intr_mode( card, 0 );
+ if (err != CMD_OK)
+ return err;
+
+ card->wandev.critical = 1;
+ return 0;
+}
+
/****** End *****************************************************************/
diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c
index 77dfc43b0..15844a3ab 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/sdla_x25.c
@@ -10,6 +10,19 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
+* when they are disabled.
+* Nov 17, 1997 Farhan Thawar o Added IPX support
+* o Changed if_send() to now buffer packets when
+* the board is busy
+* o Removed queueing of packets via the polling
+* routing
+* o Changed if_send() critical flags to properly
+* handle race conditions
+* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts
+* o Changed PVC encapsulation to ETH_P_IP
+* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree()
+* when packets are received.
* Mar 11, 1997 Farhan Thawar Version 3.1.1
* o added support for V35
* o changed if_send() to return 0 if
@@ -49,12 +62,15 @@
#define MAX_CMD_RETRY 10 /* max number of firmware retries */
#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */
-#define X25_HRDHDR_SZ 6 /* max encapsulation header size */
+#define X25_HRDHDR_SZ 7 /* max encapsulation header size */
#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */
#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */
#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
+/* For IPXWAN */
+#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
+
/****** Data Structures *****************************************************/
/* This is an extention of the 'struct device' we create for each network
@@ -72,7 +88,10 @@ typedef struct x25_channel
char drop_sequence; /* mark sequence for dropping */
unsigned long state_tick; /* time of the last state change */
unsigned idle_timeout; /* sec, before disconnecting */
+ unsigned long i_timeout_sofar; /* # of sec's we've been idle */
unsigned hold_timeout; /* sec, before re-connecting */
+ unsigned long tick_counter; /* counter for transmit time out */
+ char devtint; /* Weather we should dev_tint() */
struct sk_buff* rx_skb; /* receive socket buffer */
struct sk_buff* tx_skb; /* transmit socket buffer */
sdla_t* card; /* -> owner */
@@ -167,6 +186,13 @@ static unsigned int dec_to_uint (unsigned char* str, int len);
static unsigned int hex_to_uint (unsigned char* str, int len);
static void parse_call_info (unsigned char* str, x25_call_info_t* info);
+/* IPX functions */
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming);
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto);
+
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+
/****** Global Data **********************************************************
* Note: All data must be explicitly initialized!!!
*/
@@ -232,7 +258,7 @@ __initfunc(int wpx_init (sdla_t* card, wandev_conf_t* conf))
u.cfg.hdlcWindow = 7;
u.cfg.pktWindow = 2;
u.cfg.station = 1; /* DTE */
- u.cfg.options = 0x0010; /* disable D-bit pragmatics */
+ u.cfg.options = 0x00B0; /* disable D-bit pragmatics */
u.cfg.ccittCompat = 1988;
u.cfg.t10t20 = 30;
u.cfg.t11t21 = 30;
@@ -243,6 +269,7 @@ __initfunc(int wpx_init (sdla_t* card, wandev_conf_t* conf))
u.cfg.r10r20 = 5;
u.cfg.r12r22 = 5;
u.cfg.r13r23 = 5;
+ u.cfg.responseOpt = 1; /* RR's after every packet */
if (conf->clocking != WANOPT_EXTERNAL)
u.cfg.baudRate = bps_to_speed_code(conf->bps)
@@ -267,7 +294,7 @@ __initfunc(int wpx_init (sdla_t* card, wandev_conf_t* conf))
else if (conf->mtu >= 128)
card->wandev.mtu = 128
;
- else conf->mtu = 64;
+ else card->wandev.mtu = 64;
u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
if (conf->u.x25.hi_pvc)
@@ -322,6 +349,15 @@ __initfunc(int wpx_init (sdla_t* card, wandev_conf_t* conf))
card->wandev.new_if = &new_if;
card->wandev.del_if = &del_if;
card->wandev.state = WAN_DISCONNECTED;
+ card->wandev.enable_tx_int = 0;
+ card->irq_dis_if_send_count = 0;
+ card->irq_dis_poll_count = 0;
+ card->wandev.enable_IPX = conf->enable_IPX;
+
+ if (conf->network_number)
+ card->wandev.network_number = conf->network_number;
+ else
+ card->wandev.network_number = 0xDEADBEEF;
return 0;
}
@@ -386,13 +422,18 @@ static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
memset(chan, 0, sizeof(x25_channel_t));
strcpy(chan->name, conf->name);
chan->card = card;
+ chan->protocol = ETH_P_IP;
+ chan->tx_skb = chan->rx_skb = NULL;
/* verify media address */
if (conf->addr[0] == '@') /* SVC */
{
chan->svc = 1;
- chan->protocol = ETH_P_IP;
strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+
+ /* Set channel timeouts (default if not specified) */
+ chan->idle_timeout = (conf->idle_timeout) ? conf->idle_timeout : 90;
+ chan->hold_timeout = (conf->hold_timeout) ? conf->hold_timeout : 10;
}
else if (is_digit(conf->addr[0])) /* PVC */
{
@@ -435,6 +476,7 @@ static int new_if (wan_device_t* wandev, struct device* dev, wanif_conf_t* conf)
/*============================================================================
* Delete logical channel.
*/
+
static int del_if (wan_device_t* wandev, struct device* dev)
{
if (dev->priv)
@@ -450,6 +492,7 @@ static int del_if (wan_device_t* wandev, struct device* dev)
/*============================================================================
* Execute adapter interface command.
*/
+
static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
{
TX25Mbox* mbox = card->mbox;
@@ -525,10 +568,12 @@ static int if_init (struct device* dev)
dev->mem_start = wandev->maddr;
dev->mem_end = wandev->maddr + wandev->msize - 1;
+ /* Set transmit buffer queue length */
+ dev->tx_queue_len = 10;
+
/* Initialize socket buffers */
- for (i = 0; i < DEV_NUMBUFFS; ++i)
- skb_queue_head_init(&dev->buffs[i])
- ;
+ dev_init_buffers(dev);
+
set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -659,33 +704,86 @@ static int if_send (struct sk_buff* skb, struct device* dev)
{
x25_channel_t* chan = dev->priv;
sdla_t* card = chan->card;
- int queued = 0;
+ struct device *dev2;
+ TX25Status* status = card->flags;
+ unsigned long host_cpu_flags;
- if (test_and_set_bit(0, (void*)&card->wandev.critical))
+ if (skb == NULL)
{
+ /* If we get here, some higher layer thinks we've missed a
+ * tx-done interrupt.
+ */
#ifdef _DEBUG_
- printk(KERN_INFO "%s: if_send() hit critical section!\n",
- card->devname)
+ printk(KERN_INFO "%s: interface %s got kicked!\n",
+ card->devname, dev->name)
;
#endif
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_tint(dev);
return 0;
}
- if (test_and_set_bit(0, (void*)&dev->tbusy))
+ if (dev->tbusy)
{
-#ifdef _DEBUG_
- printk(KERN_INFO "%s: Tx collision on interface %s!\n",
+ ++chan->ifstats.rx_dropped;
+ if ((jiffies - chan->tick_counter) < (5*HZ))
+ {
+ return dev->tbusy;
+ }
+ printk(KERN_INFO "%s: Transmit time out %s!\n",
card->devname, dev->name)
;
-#endif
- ++chan->ifstats.collisions;
- ++card->wandev.stats.collisions;
- dev_kfree_skb(skb, FREE_WRITE);
- card->wandev.critical = 0;
- return 0;
+ for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ {
+ dev2->tbusy = 0;
+ }
+ }
+ chan->tick_counter = jiffies;
+
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_if_send_count;
+
+ if (set_bit(0, (void*)&card->wandev.critical))
+ {
+ printk(KERN_INFO "Hit critical in if_send()!\n");
+ if (card->wandev.critical == CRITICAL_IN_ISR)
+ {
+ card->wandev.enable_tx_int = 1;
+ dev->tbusy = 1;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return dev->tbusy;
+ }
+ dev_kfree_skb(skb);
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) &&
+ (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return dev->tbusy;
+ }
+
+ /* Below is only until we have per-channel IPX going.... */
+ if(!(chan->svc))
+ {
+ chan->protocol = skb->protocol;
+ }
+
+ if (card->wandev.state != WAN_CONNECTED)
+ {
+ ++chan->ifstats.tx_dropped
+ ;
}
- else if (chan->protocol && (chan->protocol != skb->protocol))
+ /* Below is only until we have per-channel IPX going.... */
+ else if ( (chan->svc) && (chan->protocol && (chan->protocol != skb->protocol)))
{
printk(KERN_INFO
"%s: unsupported Ethertype 0x%04X on interface %s!\n",
@@ -693,41 +791,57 @@ static int if_send (struct sk_buff* skb, struct device* dev)
;
++chan->ifstats.tx_errors;
}
- else if (card->wandev.state != WAN_CONNECTED)
- ++chan->ifstats.tx_dropped
- ;
else switch (chan->state)
{
- case WAN_CONNECTED:
- dev->trans_start = jiffies;
- queued = chan_send(dev, skb);
- if (queued) chan->tx_skb = skb;
- break;
-
case WAN_DISCONNECTED:
/* Try to establish connection. If succeded, then start
* transmission, else drop a packet.
*/
- if (chan_connect(dev) == 0)
+ if (chan_connect(dev) != 0)
{
- dev->trans_start = jiffies;
- queued = chan_send(dev, skb);
- if (queued) chan->tx_skb = skb;
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
break;
}
- /* else fall through */
+ /* fall through */
+
+ case WAN_CONNECTED:
+ if( skb->protocol == ETH_P_IPX ) {
+ if(card->wandev.enable_IPX) {
+ switch_net_numbers( skb->data,
+ card->wandev.network_number, 0);
+ } else {
+ ++card->wandev.stats.tx_dropped;
+ ++chan->ifstats.tx_dropped;
+ goto tx_done;
+ }
+ }
+ dev->trans_start = jiffies;
+ if(chan_send(dev, skb))
+ {
+ dev->tbusy = 1;
+ status->imask |= 0x2;
+ }
+ break;
default:
- ++chan->ifstats.tx_dropped;
+ ++chan->ifstats.tx_dropped;
+ ++card->wandev.stats.tx_dropped;
}
- if (!queued)
+tx_done:
+ if (!dev->tbusy)
{
- dev_kfree_skb(skb, FREE_WRITE);
- dev->tbusy = 0;
+ dev_kfree_skb(skb);
}
card->wandev.critical = 0;
- return 0;
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return dev->tbusy;
}
/*============================================================================
@@ -749,6 +863,24 @@ static struct enet_statistics* if_stats (struct device* dev)
static void wpx_isr (sdla_t* card)
{
TX25Status* status = card->flags;
+ struct device *dev;
+ unsigned long host_cpu_flags;
+
+ card->in_isr = 1;
+ card->buff_int_mode_unbusy = 0;
+
+ if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
+
+ printk(KERN_INFO "wpx_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, status->iflags);
+ card->in_isr = 0;
+ return;
+ }
+
+ /* For all interrupts set the critical flag to CRITICAL_RX_INTR.
+ * If the if_send routine is called with this flag set it will set
+ * the enable transmit flag to 1. (for a delayed interrupt)
+ */
+ card->wandev.critical = CRITICAL_IN_ISR;
switch (status->iflags)
{
@@ -758,6 +890,8 @@ static void wpx_isr (sdla_t* card)
case 0x02: /* transmit interrupt */
tx_intr(card);
+ card->buff_int_mode_unbusy = 1;
+ status->imask &= ~0x2;
break;
case 0x04: /* modem status interrupt */
@@ -768,10 +902,33 @@ static void wpx_isr (sdla_t* card)
event_intr(card);
break;
- default: /* unwanter interrupt */
+ default: /* unwanted interrupt */
spur_intr(card);
}
+
+ card->wandev.critical = CRITICAL_INTR_HANDLED;
+ if( card->wandev.enable_tx_int)
+ {
+ card->wandev.enable_tx_int = 0;
+ status->imask |= 0x2;
+ }
+ save_flags(host_cpu_flags);
+ cli();
+ card->in_isr = 0;
status->iflags = 0; /* clear interrupt condition */
+ card->wandev.critical = 0;
+ restore_flags(host_cpu_flags);
+
+ if(card->buff_int_mode_unbusy)
+ {
+ for(dev = card->wandev.dev; dev; dev = dev->slave)
+ {
+ if(((x25_channel_t*)dev->priv)->devtint)
+ {
+ dev_tint(dev);
+ }
+ }
+ }
}
/*============================================================================
@@ -812,6 +969,7 @@ static void rx_intr (sdla_t* card)
}
chan = dev->priv;
+ chan->i_timeout_sofar = jiffies;
if (chan->drop_sequence)
{
if (!(qdm & 0x01)) chan->drop_sequence = 0;
@@ -842,7 +1000,7 @@ static void rx_intr (sdla_t* card)
if (skb_tailroom(skb) < len)
{
/* No room for the packet. Call off the whole thing! */
- dev_kfree_skb(skb, FREE_READ);
+ dev_kfree_skb(skb);
chan->rx_skb = NULL;
if (qdm & 0x01) chan->drop_sequence = 1;
@@ -865,13 +1023,34 @@ static void rx_intr (sdla_t* card)
if (!skb->protocol && !wan_type_trans(skb, dev))
{
/* can't decapsulate packet */
- dev_kfree_skb(skb, FREE_READ);
+ dev_kfree_skb(skb);
++chan->ifstats.rx_errors;
}
else
{
- netif_rx(skb);
- ++chan->ifstats.rx_packets;
+ if( handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol))
+ {
+ if( card->wandev.enable_IPX )
+ {
+ if(chan_send(dev, skb))
+ {
+ chan->tx_skb = skb;
+ }
+ else
+ {
+ dev_kfree_skb(skb);
+ }
+ }
+ else
+ {
+ /* increment IPX packet dropped statistic */
+ }
+ }
+ else
+ {
+ netif_rx(skb);
+ ++chan->ifstats.rx_packets;
+ }
}
}
@@ -882,6 +1061,16 @@ static void rx_intr (sdla_t* card)
*/
static void tx_intr (sdla_t* card)
{
+ struct device *dev;
+
+
+ /* unbusy all devices and then dev_tint(); */
+ for(dev = card->wandev.dev; dev; dev = dev->slave)
+ {
+ ((x25_channel_t*)dev->priv)->devtint = dev->tbusy;
+ dev->tbusy = 0;
+ }
+
}
/*============================================================================
@@ -922,6 +1111,25 @@ static void spur_intr (sdla_t* card)
*/
static void wpx_poll (sdla_t* card)
{
+ unsigned long host_cpu_flags;
+
+ disable_irq(card->hw.irq);
+ ++card->irq_dis_poll_count;
+
+ if (set_bit(0, (void*)&card->wandev.critical)) {
+
+ printk(KERN_INFO "%s: critical in polling!\n",card->devname);
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) &&
+ (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
+ return;
+ }
+
switch(card->wandev.state)
{
case WAN_CONNECTED:
@@ -935,6 +1143,15 @@ static void wpx_poll (sdla_t* card)
case WAN_DISCONNECTED:
poll_disconnected(card);
}
+
+ card->wandev.critical = 0;
+
+ save_flags(host_cpu_flags);
+ cli();
+ if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count)))
+ enable_irq(card->hw.irq);
+ restore_flags(host_cpu_flags);
+
}
/*============================================================================
@@ -948,7 +1165,8 @@ static void poll_connecting (sdla_t* card)
if (status->gflags & X25_HDLC_ABM)
{
wanpipe_set_state(card, WAN_CONNECTED);
- x25_set_intr_mode(card, 0x81); /* enable Rx interrupts */
+ x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */
+ status->imask &= ~0x2; /* mask Tx interupts */
}
else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
disconnect(card)
@@ -993,19 +1211,21 @@ static void poll_active (sdla_t* card)
{
chan->tx_skb = NULL;
dev->tbusy = 0;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
/* If SVC has been idle long enough, close virtual circuit */
-/*
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- restore_flags(flags);
-*/
+ if(( chan->svc )&&( chan->state == WAN_CONNECTED ))
+ {
+ if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout )
+ {
+ //Close svc
+ printk(KERN_INFO "%s: Closing down Idle link %s on LCN %d\n",card->devname,chan->name,chan->lcn);
+ chan->i_timeout_sofar = jiffies;
+ chan_disc(dev);
+ }
+ }
}
}
@@ -1644,7 +1864,10 @@ static int incomming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
accept = 1;
break;
- case NLPID_SNAP:
+ case NLPID_SNAP: /* IPX datagrams */
+ chan->protocol = ETH_P_IPX;
+ accept = 1;
+ break;
default:
printk(KERN_INFO
"%s: unsupported NLPID 0x%02X in incomming call "
@@ -1853,8 +2076,8 @@ static int chan_disc (struct device* dev)
{
x25_channel_t* chan = dev->priv;
- set_chan_state(dev, WAN_DISCONNECTED);
if (chan->svc) x25_clear_call(chan->card, chan->lcn, 0, 0);
+ set_chan_state(dev, WAN_DISCONNECTED);
return 0;
}
@@ -1878,6 +2101,7 @@ static void set_chan_state (struct device* dev, int state)
card->devname, dev->name)
;
*(unsigned short*)dev->dev_addr = htons(chan->lcn);
+ chan->i_timeout_sofar = jiffies;
break;
case WAN_CONNECTING:
@@ -1941,6 +2165,7 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
switch(x25_send(card, chan->lcn, qdm, len, skb->data))
{
case 0x00: /* success */
+ chan->i_timeout_sofar = jiffies;
if (qdm)
{
skb_pull(skb, len);
@@ -1954,6 +2179,7 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
default: /* failure */
++chan->ifstats.tx_errors;
+/* return 1; */
}
return 0;
}
@@ -2081,4 +2307,171 @@ static unsigned int hex_to_uint (unsigned char* str, int len)
return val;
}
+
+static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
+{
+ int i;
+
+ if( proto == htons(ETH_P_IPX) ) {
+ /* It's an IPX packet */
+ if(!enable_IPX) {
+ /* Return 1 so we don't pass it up the stack. */
+ return 1;
+ }
+ } else {
+ /* It's not IPX so pass it up the stack. */
+ return 0;
+ }
+
+ if( sendpacket[16] == 0x90 &&
+ sendpacket[17] == 0x04)
+ {
+ /* It's IPXWAN */
+
+ if( sendpacket[2] == 0x02 &&
+ sendpacket[34] == 0x00)
+ {
+ /* It's a timer request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
+
+ /* Go through the routing options and answer no to every */
+ /* option except Unnumbered RIP/SAP */
+ for(i = 41; sendpacket[i] == 0x00; i += 5)
+ {
+ /* 0x02 is the option for Unnumbered RIP/SAP */
+ if( sendpacket[i + 4] != 0x02)
+ {
+ sendpacket[i + 1] = 0;
+ }
+ }
+
+ /* Skip over the extended Node ID option */
+ if( sendpacket[i] == 0x04 )
+ {
+ i += 8;
+ }
+
+ /* We also want to turn off all header compression opt. */
+ for(; sendpacket[i] == 0x80 ;)
+ {
+ sendpacket[i + 1] = 0;
+ i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
+ }
+
+ /* Set the packet type to timer response */
+ sendpacket[34] = 0x01;
+
+ printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
+ }
+ else if( sendpacket[34] == 0x02 )
+ {
+ /* This is an information request packet */
+ printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
+
+ /* Set the packet type to information response */
+ sendpacket[34] = 0x03;
+
+ /* Set the router name */
+ sendpacket[51] = 'X';
+ sendpacket[52] = 'T';
+ sendpacket[53] = 'P';
+ sendpacket[54] = 'I';
+ sendpacket[55] = 'P';
+ sendpacket[56] = 'E';
+ sendpacket[57] = '-';
+ sendpacket[58] = CVHexToAscii(network_number >> 28);
+ sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
+ sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
+ sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
+ sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
+ sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
+ sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
+ sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
+ for(i = 66; i < 99; i+= 1)
+ {
+ sendpacket[i] = 0;
+ }
+
+ /* printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); */
+ }
+ else
+ {
+ printk(KERN_WARNING "%s: Unknown IPXWAN packet!\n",devname);
+ return 0;
+ }
+
+ /* Set the WNodeID to our network address */
+ sendpacket[35] = (unsigned char)(network_number >> 24);
+ sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
+ sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
+ sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
+
+ return 1;
+ } else {
+ /* If we get here its an IPX-data packet, so it'll get passed up the stack. */
+
+ /* switch the network numbers */
+ switch_net_numbers(sendpacket, network_number, 1);
+ return 0;
+ }
+}
+
+/*
+ If incoming is 0 (outgoing)- if the net numbers is ours make it 0
+ if incoming is 1 - if the net number is 0 make it ours
+
+*/
+static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
+{
+ unsigned long pnetwork_number;
+
+ pnetwork_number = (unsigned long)((sendpacket[6] << 24) +
+ (sendpacket[7] << 16) + (sendpacket[8] << 8) +
+ sendpacket[9]);
+
+ if (!incoming) {
+ /* If the destination network number is ours, make it 0 */
+ if( pnetwork_number == network_number) {
+ sendpacket[6] = sendpacket[7] = sendpacket[8] =
+ sendpacket[9] = 0x00;
+ }
+ } else {
+ /* If the incoming network is 0, make it ours */
+ if( pnetwork_number == 0) {
+ sendpacket[6] = (unsigned char)(network_number >> 24);
+ sendpacket[7] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[8] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[9] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+
+
+ pnetwork_number = (unsigned long)((sendpacket[18] << 24) +
+ (sendpacket[19] << 16) + (sendpacket[20] << 8) +
+ sendpacket[21]);
+
+ if( !incoming ) {
+ /* If the source network is ours, make it 0 */
+ if( pnetwork_number == network_number) {
+ sendpacket[18] = sendpacket[19] = sendpacket[20] =
+ sendpacket[21] = 0x00;
+ }
+ } else {
+ /* If the source network is 0, make it ours */
+ if( pnetwork_number == 0 ) {
+ sendpacket[18] = (unsigned char)(network_number >> 24);
+ sendpacket[19] = (unsigned char)((network_number &
+ 0x00FF0000) >> 16);
+ sendpacket[20] = (unsigned char)((network_number &
+ 0x0000FF00) >> 8);
+ sendpacket[21] = (unsigned char)(network_number &
+ 0x000000FF);
+ }
+ }
+} /* switch_net_numbers */
+
+
/****** End *****************************************************************/
diff --git a/drivers/net/sdladrv.c b/drivers/net/sdladrv.c
index 500c5cb6d..e756d8fdc 100644
--- a/drivers/net/sdladrv.c
+++ b/drivers/net/sdladrv.c
@@ -81,7 +81,6 @@
#if defined(_LINUX_) /****** Linux *******************************/
-#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
diff --git a/drivers/net/sdlamain.c b/drivers/net/sdlamain.c
index eeb0b40f3..eed8c9f36 100644
--- a/drivers/net/sdlamain.c
+++ b/drivers/net/sdlamain.c
@@ -2,6 +2,7 @@
* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module.
*
* Author: Gene Kozin <genek@compuserve.com>
+* Jaspreet Singh <jaspreet@sangoma.com>
*
* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
@@ -10,6 +11,21 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1
+* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags();
+* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0
+* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr
+* assignments are taken out and placed in the
+* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr
+* routines. Took out 'wandev->tx_int_enabled' and
+* replaced it with 'wandev->enable_tx_int'.
+* May 29, 1997 Jaspreet Singh Flow Control Problem
+* added "wandev->tx_int_enabled=1" line in the
+* init module. This line intializes the flag for
+* preventing Interrupt disabled with device set to
+* busy
+* Jan 15, 1997 Gene Kozin Version 3.1.0
+* o added UDP management stuff
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
@@ -39,8 +55,8 @@
#define STATIC static
#endif
-#define DRV_VERSION 3 /* version number */
-#define DRV_RELEASE 0 /* release (minor version) number */
+#define DRV_VERSION 4 /* version number */
+#define DRV_RELEASE 1 /* release (minor version) number */
#define MAX_CARDS 8 /* max number of adapters */
#ifndef CONFIG_WANPIPE_CARDS /* configurable option */
@@ -132,6 +148,7 @@ int init_module (void)
wandev->magic = ROUTER_MAGIC;
wandev->name = card->devname;
wandev->private = card;
+ wandev->enable_tx_int = 0;
wandev->setup = &setup;
wandev->shutdown = &shutdown;
wandev->ioctl = &ioctl;
@@ -388,7 +405,7 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
/****** Driver IOCTL Hanlers ************************************************/
/*============================================================================
- * Dump adpater memory to user buffer.
+ * Dump adapter memory to user buffer.
* o verify request structure
* o copy request structure to kernel data space
* o verify length/offset
@@ -403,6 +420,7 @@ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
sdla_dump_t dump;
unsigned winsize;
unsigned long oldvec; /* DPM window vector */
+ unsigned long flags;
int err = 0;
if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
@@ -413,6 +431,7 @@ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
return -EINVAL;
winsize = card->hw.dpmsize;
+ save_flags(flags);
cli(); /* >>> critical section start <<< */
oldvec = card->hw.vector;
while (dump.length)
@@ -438,7 +457,7 @@ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
(char*)dump.ptr += len;
}
sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */
- sti(); /* >>> critical section end <<< */
+ restore_flags(flags); /* >>> critical section end <<< */
return err;
}
@@ -483,10 +502,10 @@ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
;
return;
}
- card->in_isr = 1;
+
sdla_intack(&card->hw);
- if (card->isr) card->isr(card);
- card->in_isr = 0;
+ if (card->isr)
+ card->isr(card);
#undef card
}
@@ -507,13 +526,13 @@ STATIC void sdla_poll (void* data)
sdla_t* card = &card_array[i];
if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll &&
- !test_and_set_bit(0, (void*)&card->wandev.critical))
+ !card->wandev.critical)
{
card->poll(card);
- card->wandev.critical = 0;
}
}
- if (active) queue_task(&sdla_tq, &tq_scheduler);
+ if (active)
+ queue_task(&sdla_tq, &tq_scheduler);
}
/*============================================================================
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index d8372bf52..d036fabb3 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -209,10 +209,7 @@ __initfunc(static int seeq8005_probe1(struct device *dev, int ioaddr))
#endif
outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
- SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
+ udelay(5);
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
if (net_debug) {
@@ -400,7 +397,7 @@ seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
@@ -626,10 +623,7 @@ void seeq8005_init(struct device *dev, int startp)
int i;
outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
- SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
+ udelay(5);
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
@@ -638,7 +632,7 @@ void seeq8005_init(struct device *dev, int startp)
for(i=0;i<6;i++) { /* set Station address */
outb(dev->dev_addr[i], SEEQ_BUFFER);
- SLOW_DOWN_IO;
+ udelay(2);
}
outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 0602cb4ab..c66f58e7c 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.4 1997/12/06 04:11:41 ralf Exp $
+/* $Id: sgiseeq.c,v 1.5 1997/12/06 23:53:49 ralf Exp $
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -576,7 +576,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct device *dev)
kick_tx(&sp->srings.tx_desc[sp->tx_old], hregs);
dev->trans_start = jiffies;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
if(TX_BUFFS_AVAIL(sp))
dev->tbusy = 0;
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 9bfcb0792..e536318a1 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -70,6 +70,7 @@
#include <linux/if_arp.h>
#include <linux/init.h>
#include <net/dst.h>
+#include <net/arp.h>
#include <linux/if_shaper.h>
int sh_debug; /* Debug flag */
@@ -190,7 +191,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
if(ptr->shapelatency > SHAPER_LATENCY)
{
skb_unlink(ptr);
- dev_kfree_skb(ptr, FREE_WRITE);
+ dev_kfree_skb(ptr);
}
ptr=tmp;
}
@@ -225,7 +226,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
* Queue over time. Spill packet.
*/
if(skb->shapeclock-jiffies > SHAPER_LATENCY)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
else
skb_queue_tail(&shaper->sendq, skb);
}
@@ -235,7 +236,7 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN)
{
ptr=skb_dequeue(&shaper->sendq);
- dev_kfree_skb(ptr, FREE_WRITE);
+ dev_kfree_skb(ptr);
}
shaper_unlock(shaper);
shaper_kick(shaper);
@@ -254,7 +255,6 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
if(newskb)
{
newskb->dev=shaper->dev;
- newskb->arp=1;
newskb->priority=2;
if(sh_debug)
printk("Kick new frame to %s, %d\n",
@@ -262,7 +262,7 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
dev_queue_xmit(newskb);
if(sh_debug)
printk("Kicked new frame out.\n");
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
}
@@ -369,7 +369,7 @@ static void shaper_flush(struct shaper *shaper)
{
struct sk_buff *skb;
while((skb=skb_dequeue(&shaper->sendq))!=NULL)
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
/*
@@ -448,17 +448,18 @@ static int shaper_rebuild_header(struct sk_buff *skb)
return v;
}
-static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh)
+#if 0
+static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh)
{
- struct shaper *sh=dst->dev->priv;
+ struct shaper *sh=neigh->dev->priv;
struct device *tmp;
int ret;
if(sh_debug)
printk("Shaper header cache bind\n");
- tmp=dst->dev;
- dst->dev=sh->dev;
- ret=sh->hard_header_cache(dst,neigh,hh);
- dst->dev=tmp;
+ tmp=neigh->dev;
+ neigh->dev=sh->dev;
+ ret=sh->hard_header_cache(neigh,hh);
+ neigh->dev=tmp;
return ret;
}
@@ -470,6 +471,26 @@ static void shaper_cache_update(struct hh_cache *hh, struct device *dev,
printk("Shaper cache update\n");
sh->header_cache_update(hh, sh->dev, haddr);
}
+#endif
+
+static int shaper_neigh_setup(struct neighbour *n)
+{
+ if (n->nud_state == NUD_NONE) {
+ n->ops = &arp_broken_ops;
+ n->output = n->ops->output;
+ }
+ return 0;
+}
+
+static int shaper_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+ if (p->tbl->family == AF_INET) {
+ p->neigh_setup = shaper_neigh_setup;
+ p->ucast_probes = 0;
+ p->mcast_probes = 0;
+ }
+ return 0;
+}
static int shaper_attach(struct device *shdev, struct shaper *sh, struct device *dev)
{
@@ -513,7 +534,8 @@ static int shaper_attach(struct device *shdev, struct shaper *sh, struct device
#else
shdev->header_cache_update = NULL;
shdev->hard_header_cache = NULL;
-#endif
+#endif
+ shdev->neigh_setup = shaper_neigh_setup_dev;
shdev->hard_header_len=dev->hard_header_len;
shdev->type=dev->type;
@@ -588,8 +610,11 @@ __initfunc(int shaper_probe(struct device *dev))
dev->hard_header = shaper_header;
dev->rebuild_header = shaper_rebuild_header;
+#if 0
dev->hard_header_cache = shaper_cache;
dev->header_cache_update= shaper_cache_update;
+#endif
+ dev->neigh_setup = shaper_neigh_setup_dev;
dev->do_ioctl = shaper_ioctl;
dev->hard_header_len = 0;
dev->type = ARPHRD_ETHER; /* initially */
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index c33e033e8..6ef0a66f8 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -1251,7 +1251,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
dev->tbusy = 0;
}
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
} /* End of SK_send_packet */
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
index b30e62b32..1ba460691 100644
--- a/drivers/net/skeleton.c
+++ b/drivers/net/skeleton.c
@@ -374,7 +374,7 @@ static int net_send_packet(struct sk_buff *skb, struct device *dev)
hardware_send_packet(ioaddr, buf, length);
dev->trans_start = jiffies;
}
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
if (inw(ioaddr) == /*RU*/81)
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index 187e51616..13a020869 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -99,21 +99,18 @@ slhc_init(int rslots, int tslots)
register struct cstate *ts;
struct slcompress *comp;
+ MOD_INC_USE_COUNT;
comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
GFP_KERNEL);
if (! comp)
- return NULL;
-
+ goto out_fail;
memset(comp, 0, sizeof(struct slcompress));
if ( rslots > 0 && rslots < 256 ) {
size_t rsize = rslots * sizeof(struct cstate);
comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
if (! comp->rstate)
- {
- kfree((unsigned char *)comp);
- return NULL;
- }
+ goto out_free;
memset(comp->rstate, 0, rsize);
comp->rslot_limit = rslots - 1;
}
@@ -122,11 +119,7 @@ slhc_init(int rslots, int tslots)
size_t tsize = tslots * sizeof(struct cstate);
comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
if (! comp->tstate)
- {
- kfree((unsigned char *)comp->rstate);
- kfree((unsigned char *)comp);
- return NULL;
- }
+ goto out_free2;
memset(comp->tstate, 0, tsize);
comp->tslot_limit = tslots - 1;
}
@@ -151,8 +144,15 @@ slhc_init(int rslots, int tslots)
ts[0].next = &(ts[comp->tslot_limit]);
ts[0].cs_this = 0;
}
- MOD_INC_USE_COUNT;
return comp;
+
+out_free2:
+ kfree((unsigned char *)comp->rstate);
+out_free:
+ kfree((unsigned char *)comp);
+out_fail:
+ MOD_DEC_USE_COUNT;
+ return NULL;
}
@@ -163,14 +163,14 @@ slhc_free(struct slcompress *comp)
if ( comp == NULLSLCOMPR )
return;
- if ( comp->rstate != NULLSLSTATE )
- kfree( comp->rstate );
-
if ( comp->tstate != NULLSLSTATE )
kfree( comp->tstate );
- MOD_DEC_USE_COUNT;
+ if ( comp->rstate != NULLSLSTATE )
+ kfree( comp->rstate );
+
kfree( comp );
+ MOD_DEC_USE_COUNT;
}
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 9493fe371..fe464965e 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -50,6 +50,8 @@
* from multislip BSDI driver which was written
* by Igor Chechik, RELCOM Corp. Only algorithms
* have been ported to Linux SLIP driver.
+ * Vitaly E. Lavrov : Sane behaviour on tty hangup.
+ * Alexey Kuznetsov : Cleanup interfaces to tty&netdevice modules.
*/
#define SL_CHECK_TRANSMIT
@@ -110,133 +112,139 @@ static void sl_outfill(unsigned long sls);
static int sl_ioctl(struct device *dev,struct ifreq *rq,int cmd);
#endif
-/* Find a free SLIP channel, and link in this `tty' line. */
-static inline struct slip *
-sl_alloc(void)
-{
- slip_ctrl_t *slp = NULL;
- int i;
-
- if (slip_ctrls == NULL) return NULL; /* Master array missing ! */
-
- for (i = 0; i < slip_maxdev; i++) {
- slp = slip_ctrls[i];
- /* Not allocated ? */
- if (slp == NULL)
- break;
- /* Not in use ? */
- if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags))
- break;
- }
- /* SLP is set.. */
-
- /* Sorry, too many, all slots in use */
- if (i >= slip_maxdev) return NULL;
-
- /* If no channels are available, allocate one */
- if (!slp &&
- (slip_ctrls[i] = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),
- GFP_KERNEL)) != NULL) {
- slp = slip_ctrls[i];
- memset(slp, 0, sizeof(slip_ctrl_t));
-
- /* Initialize channel control data */
- set_bit(SLF_INUSE, &slp->ctrl.flags);
- slp->ctrl.tty = NULL;
- sprintf(slp->if_name, "sl%d", i);
- slp->dev.name = slp->if_name;
- slp->dev.base_addr = i;
- slp->dev.priv = (void*)&(slp->ctrl);
- slp->dev.next = NULL;
- slp->dev.init = slip_init;
-/* printk(KERN_INFO "slip: kmalloc()ed SLIP control node for line %s\n",
- slp->if_name); */
- }
- if (slp != NULL) {
-
- /* register device so that it can be ifconfig'ed */
- /* slip_init() will be called as a side-effect */
- /* SIDE-EFFECT WARNING: slip_init() CLEARS slp->ctrl ! */
-
- if (register_netdev(&(slp->dev)) == 0) {
- /* (Re-)Set the INUSE bit. Very Important! */
- set_bit(SLF_INUSE, &slp->ctrl.flags);
- slp->ctrl.dev = &(slp->dev);
- slp->dev.priv = (void*)&(slp->ctrl);
+/********************************
+* Buffer administration routines:
+* sl_alloc_bufs()
+* sl_free_bufs()
+* sl_realloc_bufs()
+*
+* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because
+* sl_realloc_bufs provides strong atomicity and reallocation
+* on actively running device.
+*********************************/
+
+/*
+ Allocate channel buffers.
+ */
-/* printk(KERN_INFO "slip: linked in netdev %s for active use\n",
- slp->if_name); */
+static int
+sl_alloc_bufs(struct slip *sl, int mtu)
+{
+ int err = -ENOBUFS;
+ unsigned long len;
+ char * rbuff = NULL;
+ char * xbuff = NULL;
+#ifdef SL_INCLUDE_CSLIP
+ char * cbuff = NULL;
+ struct slcompress *slcomp = NULL;
+#endif
- return (&(slp->ctrl));
+ /*
+ * Allocate the SLIP frame buffers:
+ *
+ * rbuff Receive buffer.
+ * xbuff Transmit buffer.
+ * cbuff Temporary compression buffer.
+ */
+ len = mtu * 2;
- } else {
- clear_bit(SLF_INUSE,&(slp->ctrl.flags));
- printk("sl_alloc() - register_netdev() failure.\n");
- }
+ /*
+ * allow for arrival of larger UDP packets, even if we say not to
+ * also fixes a bug in which SunOS sends 512-byte packets even with
+ * an MSS of 128
+ */
+ if (len < 576 * 2)
+ len = 576 * 2;
+ rbuff = kmalloc(len + 4, GFP_KERNEL);
+ if (rbuff == NULL)
+ goto err_exit;
+ xbuff = kmalloc(len + 4, GFP_KERNEL);
+ if (xbuff == NULL)
+ goto err_exit;
+#ifdef SL_INCLUDE_CSLIP
+ cbuff = kmalloc(len + 4, GFP_KERNEL);
+ if (cbuff == NULL)
+ goto err_exit;
+ slcomp = slhc_init(16, 16);
+ if (slcomp == NULL)
+ goto err_exit;
+#endif
+ start_bh_atomic();
+ if (sl->tty == NULL) {
+ end_bh_atomic();
+ err = -ENODEV;
+ goto err_exit;
}
+ sl->mtu = mtu;
+ sl->buffsize = len;
+ sl->rcount = 0;
+ sl->xleft = 0;
+ rbuff = xchg(&sl->rbuff, rbuff);
+ xbuff = xchg(&sl->xbuff, xbuff);
+#ifdef CONFIG_SLIP_MODE_SLIP6
+ cbuff = xchg(&sl->cbuff, cbuff);
+ slcomp = xchg(&sl->slcomp, slcomp);
+ sl->xdata = 0;
+ sl->xbits = 0;
+#endif
+ end_bh_atomic();
+ err = 0;
- return NULL;
+ /* Cleanup */
+err_exit:
+#ifdef SL_INCLUDE_CSLIP
+ if (cbuff)
+ kfree(cbuff);
+ if (slcomp)
+ slhc_free(slcomp);
+#endif
+ if (xbuff)
+ kfree(xbuff);
+ if (rbuff)
+ kfree(rbuff);
+ return err;
}
-
-/* Free a SLIP channel. */
-static inline void
-sl_free(struct slip *sl)
+/* Free a SLIP channel buffers. */
+static void
+sl_free_bufs(struct slip *sl)
{
+ void * tmp;
+
/* Free all SLIP frame buffers. */
- if (sl->rbuff) {
- kfree(sl->rbuff);
- }
- sl->rbuff = NULL;
- if (sl->xbuff) {
- kfree(sl->xbuff);
- }
- sl->xbuff = NULL;
+ if ((tmp = xchg(&sl->rbuff, NULL)) != NULL)
+ kfree(tmp);
+ if ((tmp = xchg(&sl->xbuff, NULL)) != NULL)
+ kfree(tmp);
#ifdef SL_INCLUDE_CSLIP
- /* Save CSLIP statistics */
- if (sl->slcomp) {
- sl->rx_compressed += sl->slcomp->sls_i_compressed;
- sl->rx_dropped += sl->slcomp->sls_i_tossed;
- sl->tx_compressed += sl->slcomp->sls_o_compressed;
- sl->tx_misses += sl->slcomp->sls_o_misses;
- }
- if (sl->cbuff) {
- kfree(sl->cbuff);
- }
- sl->cbuff = NULL;
- if(sl->slcomp)
- slhc_free(sl->slcomp);
- sl->slcomp = NULL;
+ if ((tmp = xchg(&sl->cbuff, NULL)) != NULL)
+ kfree(tmp);
+ if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)
+ slhc_free(tmp);
#endif
-
- if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
- printk("%s: sl_free for already free unit.\n", sl->dev->name);
- }
}
-/* MTU has been changed by the IP layer. Unfortunately we are not told
- about this, but we spot it ourselves and fix things up. We could be
- in an upcall from the tty driver, or in an ip packet queue. */
+/*
+ Reallocate slip channel buffers.
+ */
-static void sl_changedmtu(struct slip *sl)
+static int sl_realloc_bufs(struct slip *sl, int mtu)
{
+ int err = 0;
struct device *dev = sl->dev;
- unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
+ unsigned char *xbuff, *rbuff;
#ifdef SL_INCLUDE_CSLIP
- unsigned char *cbuff, *ocbuff;
+ unsigned char *cbuff;
#endif
- int len;
- unsigned long flags;
+ int len = mtu * 2;
- len = dev->mtu * 2;
/*
* allow for arrival of larger UDP packets, even if we say not to
* also fixes a bug in which SunOS sends 512-byte packets even with
* an MSS of 128
*/
- if (len < 576 * 2) {
+ if (len < 576 * 2)
len = 576 * 2;
- }
xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
@@ -244,37 +252,30 @@ static void sl_changedmtu(struct slip *sl)
cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC);
#endif
+
#ifdef SL_INCLUDE_CSLIP
if (xbuff == NULL || rbuff == NULL || cbuff == NULL) {
#else
if (xbuff == NULL || rbuff == NULL) {
#endif
- printk("%s: unable to grow slip buffers, MTU change cancelled.\n",
- sl->dev->name);
- dev->mtu = sl->mtu;
- if (xbuff != NULL) {
- kfree(xbuff);
- }
- if (rbuff != NULL) {
- kfree(rbuff);
+ if (mtu >= sl->mtu) {
+ printk("%s: unable to grow slip buffers, MTU change cancelled.\n",
+ dev->name);
+ err = -ENOBUFS;
}
-#ifdef SL_INCLUDE_CSLIP
- if (cbuff != NULL) {
- kfree(cbuff);
- }
-#endif
- return;
+ goto done;
}
- save_flags(flags); cli();
+ start_bh_atomic();
+
+ err = -ENODEV;
+ if (sl->tty == NULL)
+ goto done_on_bh;
- oxbuff = sl->xbuff;
- sl->xbuff = xbuff;
- orbuff = sl->rbuff;
- sl->rbuff = rbuff;
+ xbuff = xchg(&sl->xbuff, xbuff);
+ rbuff = xchg(&sl->rbuff, rbuff);
#ifdef SL_INCLUDE_CSLIP
- ocbuff = sl->cbuff;
- sl->cbuff = cbuff;
+ cbuff = xchg(&sl->cbuff, cbuff);
#endif
if (sl->xleft) {
if (sl->xleft <= len) {
@@ -288,30 +289,31 @@ static void sl_changedmtu(struct slip *sl)
if (sl->rcount) {
if (sl->rcount <= len) {
- memcpy(sl->rbuff, orbuff, sl->rcount);
+ memcpy(sl->rbuff, rbuff, sl->rcount);
} else {
sl->rcount = 0;
sl->rx_over_errors++;
set_bit(SLF_ERROR, &sl->flags);
}
}
- sl->mtu = dev->mtu;
-
+ sl->mtu = mtu;
+ dev->mtu = mtu;
sl->buffsize = len;
+ err = 0;
- restore_flags(flags);
+done_on_bh:
+ end_bh_atomic();
- if (oxbuff != NULL) {
- kfree(oxbuff);
- }
- if (orbuff != NULL) {
- kfree(orbuff);
- }
+done:
+ if (xbuff)
+ kfree(xbuff);
+ if (rbuff)
+ kfree(rbuff);
#ifdef SL_INCLUDE_CSLIP
- if (ocbuff != NULL) {
- kfree(ocbuff);
- }
+ if (cbuff)
+ kfree(cbuff);
#endif
+ return err;
}
@@ -398,14 +400,7 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
unsigned char *p;
int actual, count;
-
- if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */
-
- sl_changedmtu(sl);
- }
-
if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */
- len = sl->mtu;
printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
sl->tx_dropped++;
sl_unlock(sl);
@@ -440,8 +435,10 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
#endif
sl->xleft = count - actual;
sl->xhead = sl->xbuff + actual;
+#ifdef CONFIG_SLIP_SMART
/* VSV */
clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */
+#endif
}
/*
@@ -480,8 +477,14 @@ sl_xmit(struct sk_buff *skb, struct device *dev)
if (!dev->start) {
printk("%s: xmit call when iface is down\n", dev->name);
- return 1;
+ dev_kfree_skb(skb);
+ return 0;
}
+ if (sl->tty == NULL) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
/*
* If we are busy already- too bad. We ought to be able
* to queue things at this point, to allow for a little
@@ -518,113 +521,143 @@ sl_xmit(struct sk_buff *skb, struct device *dev)
sl_lock(sl);
sl->tx_bytes+=skb->len;
sl_encaps(sl, skb->data, skb->len);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
return 0;
}
-/* Return the frame type ID. This is normally IP but maybe be AX.25. */
+/******************************************
+ * Routines looking at netdevice side.
+ ******************************************/
+
+/* Netdevice UP -> DOWN routine */
-/* Open the low-level part of the SLIP channel. Easy! */
static int
-sl_open(struct device *dev)
+sl_close(struct device *dev)
{
struct slip *sl = (struct slip*)(dev->priv);
- unsigned long len;
- if (sl->tty == NULL) {
- return -ENODEV;
- }
-
- /*
- * Allocate the SLIP frame buffers:
- *
- * rbuff Receive buffer.
- * xbuff Transmit buffer.
- * cbuff Temporary compression buffer.
- */
- len = dev->mtu * 2;
- /*
- * allow for arrival of larger UDP packets, even if we say not to
- * also fixes a bug in which SunOS sends 512-byte packets even with
- * an MSS of 128
- */
- if (len < 576 * 2) {
- len = 576 * 2;
- }
- sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
- if (sl->rbuff == NULL) {
- goto norbuff;
- }
- sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
- if (sl->xbuff == NULL) {
- goto noxbuff;
- }
-#ifdef SL_INCLUDE_CSLIP
- sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL);
- if (sl->cbuff == NULL) {
- goto nocbuff;
- }
- sl->slcomp = slhc_init(16, 16);
- if (sl->slcomp == NULL) {
- goto noslcomp;
+ start_bh_atomic();
+ if (sl->tty) {
+ /* TTY discipline is running. */
+ sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
}
-#endif
- sl->mtu = dev->mtu;
- sl->buffsize = len;
+ dev->tbusy = 1;
+ dev->start = 0;
sl->rcount = 0;
sl->xleft = 0;
-#ifdef CONFIG_SLIP_MODE_SLIP6
- sl->xdata = 0;
- sl->xbits = 0;
-#endif
- sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
-#ifdef CONFIG_SLIP_SMART
- sl->keepalive=0; /* no keepalive by default = VSV */
- init_timer(&sl->keepalive_timer); /* initialize timer_list struct */
- sl->keepalive_timer.data=(unsigned long)sl;
- sl->keepalive_timer.function=sl_keepalive;
- sl->outfill=0; /* & outfill too */
- init_timer(&sl->outfill_timer);
- sl->outfill_timer.data=(unsigned long)sl;
- sl->outfill_timer.function=sl_outfill;
-#endif
- dev->tbusy = 0;
- dev->start = 1;
+ end_bh_atomic();
+ MOD_DEC_USE_COUNT;
return 0;
+}
- /* Cleanup */
+/* Netdevice DOWN -> UP routine */
+
+static int sl_open(struct device *dev)
+{
+ struct slip *sl = (struct slip*)(dev->priv);
+
+ if (sl->tty==NULL)
+ return -ENODEV;
+
+ sl->flags &= (1 << SLF_INUSE);
+ dev->start = 1;
+ dev->tbusy = 0;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/* Netdevice change MTU request */
+
+static int sl_change_mtu(struct device *dev, int new_mtu)
+{
+ struct slip *sl = (struct slip*)(dev->priv);
+
+ if (new_mtu < 68 || new_mtu > 65534)
+ return -EINVAL;
+
+ if (new_mtu != dev->mtu)
+ return sl_realloc_bufs(sl, new_mtu);
+ return 0;
+}
+
+/* Netdevice get statistics request */
+
+static struct net_device_stats *
+sl_get_stats(struct device *dev)
+{
+ static struct net_device_stats stats;
+ struct slip *sl = (struct slip*)(dev->priv);
#ifdef SL_INCLUDE_CSLIP
-noslcomp:
- kfree(sl->cbuff);
-nocbuff:
+ struct slcompress *comp;
#endif
- kfree(sl->xbuff);
-noxbuff:
- kfree(sl->rbuff);
-norbuff:
- return -ENOMEM;
+
+ memset(&stats, 0, sizeof(struct net_device_stats));
+
+ stats.rx_packets = sl->rx_packets;
+ stats.tx_packets = sl->tx_packets;
+ stats.rx_bytes = sl->rx_bytes;
+ stats.tx_bytes = sl->tx_bytes;
+ stats.rx_dropped = sl->rx_dropped;
+ stats.tx_dropped = sl->tx_dropped;
+ stats.tx_errors = sl->tx_errors;
+ stats.rx_errors = sl->rx_errors;
+ stats.rx_over_errors = sl->rx_over_errors;
+#ifdef SL_INCLUDE_CSLIP
+ stats.rx_fifo_errors = sl->rx_compressed;
+ stats.tx_fifo_errors = sl->tx_compressed;
+ stats.collisions = sl->tx_misses;
+ comp = sl->slcomp;
+ if (comp) {
+ stats.rx_fifo_errors += comp->sls_i_compressed;
+ stats.rx_dropped += comp->sls_i_tossed;
+ stats.tx_fifo_errors += comp->sls_o_compressed;
+ stats.collisions += comp->sls_o_misses;
+ }
+#endif /* CONFIG_INET */
+ return (&stats);
}
+/* Netdevice register callback */
-/* Close the low-level part of the SLIP channel. Easy! */
-static int
-sl_close(struct device *dev)
+static int sl_init(struct device *dev)
{
struct slip *sl = (struct slip*)(dev->priv);
- if (sl->tty == NULL) {
- return -EBUSY;
- }
- sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- dev->tbusy = 1;
- dev->start = 0;
+ /*
+ * Finish setting up the DEVICE info.
+ */
+
+ dev->mtu = sl->mtu;
+ dev->hard_start_xmit = sl_xmit;
+ dev->open = sl_open;
+ dev->stop = sl_close;
+ dev->get_stats = sl_get_stats;
+ dev->change_mtu = sl_change_mtu;
+#ifdef CONFIG_SLIP_SMART
+ dev->do_ioctl = sl_ioctl;
+#endif
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP + sl->mode;
+ dev->tx_queue_len = 10;
+
+ dev_init_buffers(dev);
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
return 0;
}
+
+/******************************************
+ Routines looking at TTY side.
+ ******************************************/
+
+
static int slip_receive_room(struct tty_struct *tty)
{
return 65536; /* We can handle an infinite amount of data. :-) */
@@ -644,15 +677,6 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start)
return;
- /*
- * Argh! mtu change time! - costs us the packet part received
- * at the change
- */
- if (sl->mtu != sl->dev->mtu) {
-
- sl_changedmtu(sl);
- }
-
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
@@ -671,6 +695,127 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
}
}
+/************************************
+ * slip_open helper routines.
+ ************************************/
+
+/* Collect hanged up channels */
+
+static void sl_sync(void)
+{
+ int i;
+
+ for (i = 0; i < slip_maxdev; i++) {
+ slip_ctrl_t *slp = slip_ctrls[i];
+ if (slp == NULL)
+ break;
+ if (slp->ctrl.tty || slp->ctrl.leased)
+ continue;
+ if (slp->dev.flags&IFF_UP)
+ dev_close(&slp->dev);
+ }
+}
+
+/* Find a free SLIP channel, and link in this `tty' line. */
+static struct slip *
+sl_alloc(kdev_t line)
+{
+ struct slip *sl;
+ slip_ctrl_t *slp = NULL;
+ int i;
+ int sel = -1;
+ int score = -1;
+
+ if (slip_ctrls == NULL)
+ return NULL; /* Master array missing ! */
+
+ for (i = 0; i < slip_maxdev; i++) {
+ slp = slip_ctrls[i];
+ if (slp == NULL)
+ break;
+
+ if (slp->ctrl.leased) {
+ if (slp->ctrl.line != line)
+ continue;
+ if (slp->ctrl.tty)
+ return NULL;
+
+ /* Clear ESCAPE & ERROR flags */
+ slp->ctrl.flags &= (1 << SLF_INUSE);
+ return &slp->ctrl;
+ }
+
+ if (slp->ctrl.tty)
+ continue;
+
+ if (current->pid == slp->ctrl.pid) {
+ if (slp->ctrl.line == line && score < 3) {
+ sel = i;
+ score = 3;
+ continue;
+ }
+ if (score < 2) {
+ sel = i;
+ score = 2;
+ }
+ continue;
+ }
+ if (slp->ctrl.line == line && score < 1) {
+ sel = i;
+ score = 1;
+ continue;
+ }
+ if (score < 0) {
+ sel = i;
+ score = 0;
+ }
+ }
+
+ if (sel >= 0) {
+ i = sel;
+ slp = slip_ctrls[i];
+ if (score > 1) {
+ slp->ctrl.flags &= (1 << SLF_INUSE);
+ return &slp->ctrl;
+ }
+ }
+
+ /* Sorry, too many, all slots in use */
+ if (i >= slip_maxdev)
+ return NULL;
+
+ if (slp) {
+ if (test_bit(SLF_INUSE, &slp->ctrl.flags)) {
+ unregister_netdevice(&slp->dev);
+ sl_free_bufs(&slp->ctrl);
+ }
+ } else if ((slp = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),GFP_KERNEL)) == NULL)
+ return NULL;
+
+ memset(slp, 0, sizeof(slip_ctrl_t));
+
+ sl = &slp->ctrl;
+ /* Initialize channel control data */
+ sl->magic = SLIP_MAGIC;
+ sl->dev = &slp->dev;
+ sl->mode = SL_MODE_DEFAULT;
+ sprintf(slp->if_name, "sl%d", i);
+ slp->dev.name = slp->if_name;
+ slp->dev.base_addr = i;
+ slp->dev.priv = (void*)sl;
+ slp->dev.init = sl_init;
+#ifdef CONFIG_SLIP_SMART
+ init_timer(&sl->keepalive_timer); /* initialize timer_list struct */
+ sl->keepalive_timer.data=(unsigned long)sl;
+ sl->keepalive_timer.function=sl_keepalive;
+ init_timer(&sl->outfill_timer);
+ sl->outfill_timer.data=(unsigned long)sl;
+ sl->outfill_timer.function=sl_outfill;
+#endif
+ slip_ctrls[i] = slp;
+ return &slp->ctrl;
+}
+
/*
* Open the high-level part of the SLIP channel.
* This function is called by the TTY module when the
@@ -681,42 +826,98 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
static int
slip_open(struct tty_struct *tty)
{
- struct slip *sl = (struct slip *) tty->disc_data;
+ struct slip *sl;
int err;
+ MOD_INC_USE_COUNT;
+
+ /* RTnetlink lock is misused here to serialize concurrent
+ opens of slip channels. There are better ways, but it is
+ the simplest one.
+ */
+ rtnl_lock();
+
+ /* Collect hanged up channels. */
+ sl_sync();
+
+ sl = (struct slip *) tty->disc_data;
+
+ err = -EEXIST;
/* First make sure we're not already connected. */
- if (sl && sl->magic == SLIP_MAGIC) {
- return -EEXIST;
- }
+ if (sl && sl->magic == SLIP_MAGIC)
+ goto err_exit;
/* OK. Find a free SLIP channel to use. */
- if ((sl = sl_alloc()) == NULL) {
- return -ENFILE;
- }
+ err = -ENFILE;
+ if ((sl = sl_alloc(tty->device)) == NULL)
+ goto err_exit;
sl->tty = tty;
tty->disc_data = sl;
- if (tty->driver.flush_buffer) {
+ sl->line = tty->device;
+ sl->pid = current->pid;
+ if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
- }
- if (tty->ldisc.flush_buffer) {
+ if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
- }
- /* Restore default settings */
- sl->mode = SL_MODE_DEFAULT;
- sl->dev->type = ARPHRD_SLIP + sl->mode;
- /* Perform the low-level SLIP initialization. */
- if ((err = sl_open(sl->dev))) {
- return err;
+ if (!test_bit(SLF_INUSE, &sl->flags)) {
+ /* Perform the low-level SLIP initialization. */
+ if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)
+ goto err_free_chan;
+
+ if (register_netdevice(sl->dev)) {
+ sl_free_bufs(sl);
+ goto err_free_chan;
+ }
+
+ set_bit(SLF_INUSE, &sl->flags);
}
- MOD_INC_USE_COUNT;
+#ifdef CONFIG_SLIP_SMART
+ if (sl->keepalive) {
+ sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
+ add_timer (&sl->keepalive_timer);
+ }
+ if (sl->outfill) {
+ sl->outfill_timer.expires=jiffies+sl->outfill*HZ;
+ add_timer (&sl->outfill_timer);
+ }
+#endif
/* Done. We have linked the TTY line to a channel. */
+ rtnl_unlock();
return sl->dev->base_addr;
+
+err_free_chan:
+ sl->tty = NULL;
+ tty->disc_data = NULL;
+ clear_bit(SLF_INUSE, &sl->flags);
+
+err_exit:
+ rtnl_unlock();
+
+ /* Count references from TTY module */
+ MOD_DEC_USE_COUNT;
+ return err;
}
+/*
+ Let me to blame a bit.
+ 1. TTY module calls this funstion on soft interrupt.
+ 2. TTY module calls this function WITH MASKED INTERRUPTS!
+ 3. TTY module does not notify us about line discipline
+ shutdown,
+
+ Seems, now it is clean. The solution is to consider netdevice and
+ line discipline sides as two independant threads.
+
+ By-product (not desired): sl? does not feel hangups and remains open.
+ It is supposed, that user level program (dip, diald, slattach...)
+ will catch SIGHUP and make the rest of work.
+
+ I see no way to make more with current tty code. --ANK
+ */
/*
* Close down a SLIP channel.
@@ -730,69 +931,26 @@ slip_close(struct tty_struct *tty)
struct slip *sl = (struct slip *) tty->disc_data;
/* First make sure we're connected. */
- if (!sl || sl->magic != SLIP_MAGIC) {
+ if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
return;
- }
-
- rtnl_lock();
- if (sl->dev->flags & IFF_UP)
- {
- /* STRONG layering violation! --ANK */
- (void) dev_close(sl->dev);
- }
tty->disc_data = 0;
sl->tty = NULL;
+ if (!sl->leased)
+ sl->line = 0;
+
/* VSV = very important to remove timers */
#ifdef CONFIG_SLIP_SMART
if (sl->keepalive)
- (void)del_timer (&sl->keepalive_timer);
+ del_timer (&sl->keepalive_timer);
if (sl->outfill)
- (void)del_timer (&sl->outfill_timer);
+ del_timer (&sl->outfill_timer);
#endif
- sl_free(sl);
- unregister_netdevice(sl->dev);
- rtnl_unlock();
- MOD_DEC_USE_COUNT;
-}
-
-static struct net_device_stats *
-sl_get_stats(struct device *dev)
-{
- static struct net_device_stats stats;
- struct slip *sl = (struct slip*)(dev->priv);
-#ifdef SL_INCLUDE_CSLIP
- struct slcompress *comp;
-#endif
-
- memset(&stats, 0, sizeof(struct net_device_stats));
-
- stats.rx_packets = sl->rx_packets;
- stats.tx_packets = sl->tx_packets;
- stats.rx_bytes = sl->rx_bytes;
- stats.tx_bytes = sl->tx_bytes;
- stats.rx_dropped = sl->rx_dropped;
- stats.tx_dropped = sl->tx_dropped;
- stats.tx_errors = sl->tx_errors;
- stats.rx_errors = sl->rx_errors;
- stats.rx_over_errors = sl->rx_over_errors;
-#ifdef SL_INCLUDE_CSLIP
- stats.rx_fifo_errors = sl->rx_compressed;
- stats.tx_fifo_errors = sl->tx_compressed;
- stats.collisions = sl->tx_misses;
- comp = sl->slcomp;
- if (comp) {
- stats.rx_fifo_errors += comp->sls_i_compressed;
- stats.rx_dropped += comp->sls_i_tossed;
- stats.tx_fifo_errors += comp->sls_o_compressed;
- stats.collisions += comp->sls_o_misses;
- }
-#endif /* CONFIG_INET */
- return (&stats);
+ /* Count references from TTY module */
+ MOD_DEC_USE_COUNT;
}
-
/************************************************************************
* STANDARD SLIP ENCAPSULATION *
************************************************************************/
@@ -840,9 +998,11 @@ static void slip_unesc(struct slip *sl, unsigned char s)
switch(s) {
case END:
+#ifdef CONFIG_SLIP_SMART
/* drop keeptest bit = VSV */
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
+#endif
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
@@ -925,9 +1085,11 @@ slip_unesc6(struct slip *sl, unsigned char s)
unsigned char c;
if (s == 0x70) {
+#ifdef CONFIG_SLIP_SMART
/* drop keeptest bit = VSV */
if (test_bit(SLF_KEEPTEST, &sl->flags))
clear_bit(SLF_KEEPTEST, &sl->flags);
+#endif
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) {
sl_bump(sl);
@@ -959,7 +1121,6 @@ static int
slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
struct slip *sl = (struct slip *) tty->disc_data;
- int err;
unsigned int tmp;
/* First make sure we're connected. */
@@ -969,27 +1130,22 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
switch(cmd) {
case SIOCGIFNAME:
- err = verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1);
- if (err) {
- return err;
- }
- copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1);
+ /* Please, do not put this line under copy_to_user,
+ it breaks my old poor gcc on alpha --ANK
+ */
+ tmp = strlen(sl->dev->name) + 1;
+ if (copy_to_user(arg, sl->dev->name, tmp) < 0)
+ return -EFAULT;
return 0;
case SIOCGIFENCAP:
- err = verify_area(VERIFY_WRITE, arg, sizeof(int));
- if (err) {
- return err;
- }
- put_user(sl->mode, (int *)arg);
+ if (put_user(sl->mode, (int *)arg))
+ return -EFAULT;
return 0;
case SIOCSIFENCAP:
- err = verify_area(VERIFY_READ, arg, sizeof(int));
- if (err) {
- return err;
- }
- get_user(tmp,(int *)arg);
+ if (get_user(tmp,(int *)arg))
+ return -EFAULT;
#ifndef SL_INCLUDE_CSLIP
if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) {
return -EINVAL;
@@ -1016,13 +1172,16 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
#ifdef CONFIG_SLIP_SMART
/* VSV changes start here */
case SIOCSKEEPALIVE:
- err = verify_area(VERIFY_READ, arg, sizeof(int));
- if (err) {
- return -err;
- }
- get_user(tmp,(int *)arg);
+ if (get_user(tmp,(int *)arg))
+ return -EFAULT;
if (tmp > 255) /* max for unchar */
return -EINVAL;
+
+ start_bh_atomic();
+ if (!sl->tty) {
+ end_bh_atomic();
+ return -ENODEV;
+ }
if (sl->keepalive)
(void)del_timer (&sl->keepalive_timer);
if ((sl->keepalive = (unchar) tmp) != 0) {
@@ -1030,24 +1189,25 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
add_timer(&sl->keepalive_timer);
set_bit(SLF_KEEPTEST, &sl->flags);
}
+ end_bh_atomic();
+
return 0;
case SIOCGKEEPALIVE:
- err = verify_area(VERIFY_WRITE, arg, sizeof(int));
- if (err) {
- return -err;
- }
- put_user(sl->keepalive, (int *)arg);
+ if (put_user(sl->keepalive, (int *)arg))
+ return -EFAULT;
return 0;
case SIOCSOUTFILL:
- err = verify_area(VERIFY_READ, arg, sizeof(int));
- if (err) {
- return -err;
- }
- get_user(tmp,(int *)arg);
+ if (get_user(tmp,(int *)arg))
+ return -EFAULT;
if (tmp > 255) /* max for unchar */
return -EINVAL;
+ start_bh_atomic();
+ if (!sl->tty) {
+ end_bh_atomic();
+ return -ENODEV;
+ }
if (sl->outfill)
(void)del_timer (&sl->outfill_timer);
if ((sl->outfill = (unchar) tmp) != 0){
@@ -1055,14 +1215,12 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
add_timer(&sl->outfill_timer);
set_bit(SLF_OUTWAIT, &sl->flags);
}
+ end_bh_atomic();
return 0;
case SIOCGOUTFILL:
- err = verify_area(VERIFY_WRITE, arg, sizeof(int));
- if (err) {
- return -err;
- }
- put_user(sl->outfill, (int *)arg);
+ if (put_user(sl->outfill, (int *)arg))
+ return -EFAULT;
return 0;
/* VSV changes end */
#endif
@@ -1090,6 +1248,13 @@ static int sl_ioctl(struct device *dev,struct ifreq *rq,int cmd)
if (sl == NULL) /* Allocation failed ?? */
return -ENODEV;
+ start_bh_atomic(); /* Hangup would kill us */
+
+ if (!sl->tty) {
+ end_bh_atomic();
+ return -ENODEV;
+ }
+
switch(cmd){
case SIOCSKEEPALIVE:
/* max for unchar */
@@ -1123,20 +1288,30 @@ static int sl_ioctl(struct device *dev,struct ifreq *rq,int cmd)
case SIOCGOUTFILL:
rq->ifr_data=(caddr_t)((unsigned long)sl->outfill);
+ break;
+
+ case SIOCSLEASE:
+ /* Resolve race condition, when ioctl'ing hanged up
+ and opened by another process device.
+ */
+ if (sl->tty != current->tty && sl->pid != current->pid) {
+ end_bh_atomic();
+ return -EPERM;
+ }
+ sl->leased = 0;
+ if ((unsigned long)rq->ifr_data)
+ sl->leased = 1;
+ break;
+
+ case SIOCGLEASE:
+ rq->ifr_data=(caddr_t)((unsigned long)sl->leased);
};
+ end_bh_atomic();
return 0;
}
#endif
/* VSV changes end */
-static int sl_open_dev(struct device *dev)
-{
- struct slip *sl = (struct slip*)(dev->priv);
- if(sl->tty==NULL)
- return -ENODEV;
- return 0;
-}
-
/* Initialize SLIP control device -- register SLIP line discipline */
#ifdef MODULE
static int slip_init_ctrl_dev(void)
@@ -1202,45 +1377,7 @@ __initfunc(int slip_init_ctrl_dev(struct device *dummy))
}
-/* Initialise the SLIP driver. Called by the device init code */
-
-int slip_init(struct device *dev)
-{
- struct slip *sl = (struct slip*)(dev->priv);
-
- if (sl == NULL) /* Allocation failed ?? */
- return -ENODEV;
-
- /* Set up the "SLIP Control Block". (And clear statistics) */
- memset(sl, 0, sizeof (struct slip));
- sl->magic = SLIP_MAGIC;
- sl->dev = dev;
-
- /*
- * Finish setting up the DEVICE info.
- */
-
- dev->mtu = SL_MTU;
- dev->hard_start_xmit = sl_xmit;
- dev->open = sl_open_dev;
- dev->stop = sl_close;
- dev->get_stats = sl_get_stats;
-#ifdef CONFIG_SLIP_SMART
- dev->do_ioctl = sl_ioctl;
-#endif
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP + SL_MODE_DEFAULT;
- dev->tx_queue_len = 10;
-
- dev_init_buffers(dev);
-
- /* New-style flags. */
- dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
-
- return 0;
-}
#ifdef MODULE
int
@@ -1254,25 +1391,51 @@ cleanup_module(void)
{
int i;
- if (slip_ctrls != NULL)
- {
- for (i = 0; i < slip_maxdev; i++)
- {
- if (slip_ctrls[i])
- {
- /*
- * VSV = if dev->start==0, then device
- * unregistered while close proc.
- */
- if (slip_ctrls[i]->dev.start)
- unregister_netdev(&(slip_ctrls[i]->dev));
-
- kfree(slip_ctrls[i]);
+ if (slip_ctrls != NULL) {
+ unsigned long start = jiffies;
+ int busy = 0;
+
+ /* First of all: check for active disciplines and hangup them.
+ */
+ do {
+ if (busy) {
+ current->counter = 0;
+ schedule();
+ }
+
+ busy = 0;
+ start_bh_atomic();
+ for (i = 0; i < slip_maxdev; i++) {
+ struct slip_ctrl *slc = slip_ctrls[i];
+ if (slc && slc->ctrl.tty) {
+ busy++;
+ tty_hangup(slc->ctrl.tty);
+ }
+ }
+ end_bh_atomic();
+ } while (busy && jiffies - start < 1*HZ);
+
+ busy = 0;
+ for (i = 0; i < slip_maxdev; i++) {
+ struct slip_ctrl *slc = slip_ctrls[i];
+ if (slc) {
+ unregister_netdev(&slc->dev);
+ if (slc->ctrl.tty) {
+ printk("%s: tty discipline is still running\n", slc->dev.name);
+ /* Pin module forever */
+ MOD_INC_USE_COUNT;
+ busy++;
+ continue;
+ }
+ sl_free_bufs(&slc->ctrl);
+ kfree(slc);
slip_ctrls[i] = NULL;
}
}
- kfree(slip_ctrls);
- slip_ctrls = NULL;
+ if (!busy) {
+ kfree(slip_ctrls);
+ slip_ctrls = NULL;
+ }
}
if ((i = tty_register_ldisc(N_SLIP, NULL)))
{
@@ -1291,7 +1454,7 @@ static void sl_outfill(unsigned long sls)
{
struct slip *sl=(struct slip *)sls;
- if(sls==0L)
+ if (sl==NULL || sl->tty == NULL)
return;
if(sl->outfill)
@@ -1317,15 +1480,13 @@ static void sl_outfill(unsigned long sls)
sl->outfill_timer.expires=jiffies+sl->outfill*HZ;
add_timer(&sl->outfill_timer);
}
- else
- del_timer(&sl->outfill_timer);
}
static void sl_keepalive(unsigned long sls)
{
struct slip *sl=(struct slip *)sls;
- if(sl == NULL)
+ if (sl == NULL || sl->tty == NULL)
return;
if( sl->keepalive)
@@ -1333,7 +1494,6 @@ static void sl_keepalive(unsigned long sls)
if(test_bit(SLF_KEEPTEST, &sl->flags))
{
/* keepalive still high :(, we must hangup */
- (void)del_timer(&sl->keepalive_timer);
if( sl->outfill ) /* outfill timer must be deleted too */
(void)del_timer(&sl->outfill_timer);
printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);
@@ -1343,12 +1503,9 @@ static void sl_keepalive(unsigned long sls)
}
else
set_bit(SLF_KEEPTEST, &sl->flags);
- (void)del_timer(&sl->keepalive_timer);
- sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
+ sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
add_timer(&sl->keepalive_timer);
}
- else
- (void)del_timer(&sl->keepalive_timer);
}
#endif
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index f7569fc12..a5043a7f4 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -97,6 +97,9 @@ struct slip {
#define SLF_OUTWAIT 4 /* is outpacket was flag */
unsigned char mode; /* SLIP mode */
+ unsigned char leased;
+ kdev_t line;
+ pid_t pid;
#define SL_MODE_SLIP 0
#define SL_MODE_CSLIP 1
#define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index d3fe3084a..7a4ceca36 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -367,10 +367,10 @@ void cleanup_module(void)
{
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(ioaddr, ULTRA_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d922eb17c..e1073e2ef 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -75,13 +75,13 @@ static void ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
static void ultra_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ultra_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static void ultra_pio_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ultra_pio_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static int ultra_close_card(struct device *dev);
@@ -385,7 +385,7 @@ static void ultra_pio_input(struct device *dev, int count,
}
static void ultra_pio_output(struct device *dev, int count,
- const unsigned char *buf, const start_page)
+ const unsigned char *buf, int start_page)
{
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */
@@ -475,10 +475,10 @@ cleanup_module(void)
if (dev->priv != NULL) {
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
release_region(ioaddr, ULTRA_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 3db278b38..43cc54640 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -573,7 +573,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct device * dev )
printk(CARDNAME": Far too big packet error. \n");
/* freeing the packet is a good thing here... but should
. any packets of this size get down here? */
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
return 0;
@@ -725,7 +725,7 @@ static void smc_hardware_send_packet( struct device * dev )
PRINTK2((CARDNAME": Sent packet of length %d \n",length));
lp->saved_skb = NULL;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
dev->trans_start = jiffies;
@@ -1246,7 +1246,7 @@ static int smc_send_packet(struct sk_buff *skb, struct device *dev)
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
} else {
/* Well, I want to send the packet.. but I don't know
if I can send it right now... */
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index d785cf8dd..dab3c4c1b 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -404,7 +404,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct device *dev)
*/
if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) {
printk("%s: no VDMA entry for transmit available.\n",dev->name);
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb);
dev->tbusy = 0;
return 1;
}
@@ -520,7 +520,7 @@ sonic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* We must free the original skb */
if (lp->tx_skb[entry]) {
- dev_kfree_skb(lp->tx_skb[entry],FREE_WRITE);
+ dev_kfree_skb(lp->tx_skb[entry]);
lp->tx_skb[entry] = 0;
}
/* and the VDMA address */
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index ce5595dfa..c3b2f994e 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -1575,7 +1575,7 @@ static int strip_xmit(struct sk_buff *skb, struct device *dev)
strip_send(strip_info, skb);
- if (skb) dev_kfree_skb(skb, FREE_WRITE);
+ if (skb) dev_kfree_skb(skb);
return(0);
}
@@ -1631,11 +1631,9 @@ static int strip_header(struct sk_buff *skb, struct device *dev,
static int strip_rebuild_header(struct sk_buff *skb)
{
+#ifdef CONFIG_INET
STRIP_Header *header = (STRIP_Header *)skb->data;
- /*printk(KERN_INFO "%s: strip_rebuild_header\n", skb->dev->name);*/
-
-#ifdef CONFIG_INET
/* Arp find returns zero if if knows the address, */
/* or if it doesn't know the address it sends an ARP packet and returns non-zero */
return arp_find(header->dst_addr.c, skb)? 1 : 0;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 4e299218e..9ff5a4f11 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -931,14 +931,14 @@ static inline void happy_meal_clean_rings(struct happy_meal *hp)
for(i = 0; i < RX_RING_SIZE; i++) {
if(hp->rx_skbs[i] != NULL) {
- dev_kfree_skb(hp->rx_skbs[i], FREE_READ);
+ dev_kfree_skb(hp->rx_skbs[i]);
hp->rx_skbs[i] = NULL;
}
}
for(i = 0; i < TX_RING_SIZE; i++) {
if(hp->tx_skbs[i] != NULL) {
- dev_kfree_skb(hp->tx_skbs[i], FREE_WRITE);
+ dev_kfree_skb(hp->tx_skbs[i]);
hp->tx_skbs[i] = NULL;
}
}
@@ -1612,7 +1612,7 @@ static inline void happy_meal_tx(struct happy_meal *hp)
mmu_sync_dma(kva_to_hva(hp, skb->data),
skb->len, hp->happy_sbus_dev->my_bus);
#endif
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
hp->net_stats.tx_packets++;
elem = NEXT_TX(elem);
@@ -1644,7 +1644,7 @@ static inline void pci_happy_meal_tx(struct happy_meal *hp)
hp->tx_skbs[elem] = NULL;
hp->net_stats.tx_bytes+=skb->len;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
hp->net_stats.tx_packets++;
elem = NEXT_TX(elem);
@@ -2330,7 +2330,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
dev->trans_start = jiffies;
hp->etxregs->tx_pnding = ETX_TP_DMAWAKEUP;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
if(TX_BUFFS_AVAIL(hp))
dev->tbusy = 0;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 52a3cad23..093f7a181 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.68 1997/08/15 06:44:36 davem Exp $
+/* $Id: sunlance.c,v 1.69 1998/01/09 16:42:52 jj Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
@@ -53,12 +53,15 @@
*
* 1.10:
* 1/26/97: Modularize driver. (ecd@skynet.be)
+ *
+ * 1.11:
+ * 12/27/97: Added sun4d support. (jj@sunsite.mff.cuni.cz)
*/
#undef DEBUG_DRIVER
static char *version =
- "sunlance.c:v1.10 26/Jan/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+ "sunlance.c:v1.11 27/Dec/97 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
static char *lancestr = "LANCE";
static char *lancedma = "LANCE DMA";
@@ -679,14 +682,25 @@ static int lance_open (struct device *dev)
printk ("Lance: Can't get irq %d\n", dev->irq);
return -EAGAIN;
}
+ }
+#else
+ if (sparc_cpu_model == sun4d) {
+ struct devid_cookie dcookie;
- } else
-#endif
- if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
+ dcookie.real_dev_id = dev;
+ dcookie.bus_cookie = (void *)dev->base_addr;
+ if(request_irq(dev->irq, &lance_interrupt,
+ (SA_SHIRQ | SA_DCOOKIE),
+ lancestr, &dcookie)) {
+ printk ("Lance: Can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+ } else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
lancestr, (void *) dev)) {
printk ("Lance: Can't get irq %d\n", dev->irq);
return -EAGAIN;
}
+#endif
/* Stop the Lance */
ll->rap = LE_CSR0;
@@ -856,7 +870,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
/* Kick the lance: transmit now */
ll->rdp = LE_C0_INEA | LE_C0_TDMD;
dev->trans_start = jiffies;
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
if (TX_BUFFS_AVAIL)
dev->tbusy = 0;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index b17db5de0..b1b19a3c8 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -116,14 +116,14 @@ static inline void qe_clean_rings(struct sunqe *qep)
for(i = 0; i < RX_RING_SIZE; i++) {
if(qep->rx_skbs[i] != NULL) {
- dev_kfree_skb(qep->rx_skbs[i], FREE_READ);
+ dev_kfree_skb(qep->rx_skbs[i]);
qep->rx_skbs[i] = NULL;
}
}
for(i = 0; i < TX_RING_SIZE; i++) {
if(qep->tx_skbs[i] != NULL) {
- dev_kfree_skb(qep->tx_skbs[i], FREE_WRITE);
+ dev_kfree_skb(qep->tx_skbs[i]);
qep->tx_skbs[i] = NULL;
}
}
@@ -451,7 +451,7 @@ static inline void qe_tx(struct sunqe *qep)
mmu_sync_dma(((u32)((unsigned long)skb->data)),
skb->len, qep->qe_sbusdev->my_bus);
#endif
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
qep->net_stats.tx_packets++;
elem = NEXT_TX(elem);
@@ -804,7 +804,7 @@ static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
qep->net_stats.tx_bytes+=skb->len;
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
if(SUN4C_TX_BUFFS_AVAIL(qep))
dev->tbusy = 0;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 5aed7585a..cef3f54a4 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -663,7 +663,7 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
if ( ! priv->phyOnline ) {
TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name );
- dev_kfree_skb( skb, FREE_WRITE );
+ dev_kfree_skb( skb );
return 0;
}
@@ -710,7 +710,7 @@ int TLan_StartTx( struct sk_buff *skb, struct device *dev )
if ( priv->txTail >= TLAN_NUM_TX_LISTS )
priv->txTail = 0;
- dev_kfree_skb( skb, FREE_WRITE );
+ dev_kfree_skb( skb );
dev->trans_start = jiffies;
return 0;
@@ -2184,7 +2184,6 @@ static int TLan_PhyDp83840aCheck( struct device *dev )
{
TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
u16 gen_ctl;
- int i;
u32 io;
u16 phy;
u16 value;
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
index d92694ea6..f4484e225 100644
--- a/drivers/net/tulip.c
+++ b/drivers/net/tulip.c
@@ -1,7 +1,7 @@
-/* tulip.c: A DEC 21040 ethernet driver for linux. */
+/* tulip.c: A DEC 21040-family ethernet driver for linux. */
/*
- NOTICE: this version works with kernels 1.1.82 and later only!
- Written 1994,1995 by Donald Becker.
+ NOTICE: THIS IS THE ALPHA TEST VERSION!
+ Written 1994-1997 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -13,47 +13,69 @@
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.
-
- This has Baldur Norddahl's one liner fix for the AC/AE boards. If it
- stops working please change TINTR_ENABLE to 0xFFFFFFFF
+ Support and updates available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
*/
-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.02 12/15/96 mjacob@feral.com (2.0.27)\n";
+static const char *version = "tulip.c:v0.83 10/19/97 becker@cesdis.gsfc.nasa.gov\n";
/* A few user-configurable values. */
-/* Default to using 10baseT (i.e. AUI/10base2/100baseT port) port. */
-#define TULIP_10TP_PORT 0
-#define TULIP_100TP_PORT 1
-#define TULIP_AUI_PORT 1
-#define TULIP_BNC_PORT 2
-#define TULIP_MAX_PORT 3
-#define TULIP_AUTO_PORT -1
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[8] = {0, };
+static int options[8] = {0, };
+static int mtu[8] = {0, }; /* Jumbo MTU for interfaces. */
-#ifndef TULIP_PORT
-#define TULIP_PORT TULIP_10TP_PORT
+/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
+#ifdef REVERSE_PROBE_ORDER
+static int reverse_probe = 1;
+#else
+static int reverse_probe = 0;
+#endif
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 16
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static const rx_copybreak = 1518;
+#else
+static const rx_copybreak = 100;
+#endif
+
+/* The following example shows how to always use the 10base2 port. */
+#ifdef notdef
+#define TULIP_DEFAULT_MEDIA 1 /* 1 == 10base2 */
+#define TULIP_NO_MEDIA_SWITCH /* Don't switch from this port */
#endif
/* Define to force full-duplex operation on all Tulip interfaces. */
/* #define TULIP_FULL_DUPLEX 1 */
-/* Define to fix port. */
-/* #define TULIP_FIX_PORT 1 */
-
-/* Define to probe only first detected device */
-/*#define TULIP_MAX_CARDS 1*/
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT ((2000*HZ)/1000)
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/timer.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
@@ -61,9 +83,7 @@ static char *version =
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/bios32.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <asm/byteorder.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -72,35 +92,116 @@ static char *version =
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#include <linux/version.h> /* Evil, but neccessary */
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x) /* What to put in timer->expires. */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr) ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+
+#else /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#undef MOD_INC_USE_COUNT
+#define MOD_INC_USE_COUNT
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+#if (LINUX_VERSION_CODE >= 0x20100)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#ifdef SA_SHIRQ
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20123)
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+
+/* This my implementation of shared IRQs, now only used for 1.2.13. */
+#ifdef HAVE_SHARED_IRQ
+#define USE_SHARED_IRQ
+#include <linux/shared_irq.h>
+#endif
+
/* The total size is unusually large: The 21040 aligns each of its 16
longword-wide registers on a quadword boundary. */
#define TULIP_TOTAL_SIZE 0x80
+#ifdef HAVE_DEVLIST
+struct netdev_entry tulip_drv =
+{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef TULIP_DEBUG
+int tulip_debug = TULIP_DEBUG;
+#else
+int tulip_debug = 1;
+#endif
+
/*
Theory of Operation
I. Board Compatibility
-This device driver is designed for the DECchip 21040 "Tulip", Digital's
-single-chip ethernet controller for PCI, as used on the SMC EtherPower
-ethernet adapter. It also works with boards based the 21041 (new/experimental)
-and 21140 (10/100mbps).
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI. Supported members of the family
+are the 21040, 21041, 21140, 21140A and 21142. These chips are used on
+many PCI boards including the SMC EtherPower series.
II. Board-specific settings
PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line. While it's
-physically possible to shared PCI interrupt lines, the kernel doesn't
-support it.
+need to be set on the board. The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
III. Driver operation
IIIa. Ring buffers
+
The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
-The current driver uses a statically allocated Rx ring of descriptors and
-buffers, and a list of the Tx buffers.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers. When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff. When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames. For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information). For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data. A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
IIIC. Synchronization
The driver runs as two independent, single-threaded flows of control. One
@@ -124,659 +225,1464 @@ IV. Notes
Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840.html
+
+IVc. Errata
+
The DEC databook doesn't document which Rx filter settings accept broadcast
packets. Nor does it document how to configure the part to configure the
serial subsystem for normal (vs. loopback) operation or how to have it
autoswitch between internal 10baseT, SIA and AUI transceivers.
-The databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written. Hmmm, now how is that possible?
-*/
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written. Hmmm, now how is that possible? */
+
/* A few values that may be tweaked. */
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE 4
-#define RX_RING_SIZE 4
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-/* This is a mysterious value that can be written to CSR11 in the 21040
- to detect a full-duplex frame. No one knows what it should be, but if
- left at its default value some 10base2(!) packets trigger a
- full-duplex-request interrupt. */
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+ to support a pre-NWay full-duplex signaling mechanism using short frames.
+ No one knows what it should be, but if left at its default value some
+ 10base2(!) packets trigger a full-duplex-request interrupt. */
#define FULL_DUPLEX_MAGIC 0x6969
+#ifndef PCI_VENDOR_ID_DEC /* Now defined in linux/pci.h */
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_TULIP 0x0002 /* 21040. */
+#define PCI_DEVICE_ID_TULIP_FAST 0x0009 /* 21140. */
+#endif
+
+#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 /* 21041. */
+#endif
+#ifndef PCI_DEVICE_ID_DEC_TULIP_21142
+#define PCI_DEVICE_ID_DEC_TULIP_21142 0x0019
+#endif
+
+#ifndef PCI_VENDOR_ID_LITEON
+#define PCI_VENDOR_ID_LITEON 0x11AD
+#define PCI_DEVICE_ID_PNIC 0x0002
+#define PCI_DEVICE_ID_PNIC_X 0x0168
+#else
+/* Now PCI_VENDOR_ID_LITEON is defined, but device IDs have different names */
+#define PCI_DEVICE_ID_PNIC PCI_DEVICE_ID_LITEON_LNE100TX
+#define PCI_DEVICE_ID_PNIC_X 0x0168
+#endif
+
/* The rest of these values should never change. */
-#define PCI_DEVICE_ID_NONE 0xFFFF
-#define ETHNAMSIZ 8
-#define ROUND_UP(size, n) ((size + n - 1) & ~(n - 1))
+static void tulip_timer(unsigned long data);
+
+/* A table describing the chip types. */
+static struct tulip_chip_table {
+ int device_id;
+ char *chip_name;
+ int flags;
+ void (*media_timer)(unsigned long data);
+} tulip_tbl[] = {
+ { PCI_DEVICE_ID_DEC_TULIP, "Digital DS21040 Tulip", 0, tulip_timer },
+ { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DS21041 Tulip", 0, tulip_timer },
+ { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 0, tulip_timer },
+ { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 0, tulip_timer },
+ { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 0, tulip_timer },
+ {0, 0, 0, 0},
+};
+/* This matches the table above. */
+enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, LC82C168};
+
+static const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+/* A full-duplex map for above. */
+static const char media_fd[] =
+{0,0,0,0, 0xff,0xff,0,0, 0xff,0,0xff,0x01, 0,0,0xff,0 };
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
/* Offsets to the Command and Status Registers, "CSRs". All accesses
must be longword instructions and quadword aligned. */
enum tulip_offsets {
- /* 21040 21041 21140 */
- CSR0=0, /* BUS mode */
- CSR1=0x08, /* TX poll demand */
- CSR2=0x10, /* RX poll demand */
- CSR3=0x18, /* RX ring base addr */
- CSR4=0x20, /* TX ring base addr */
- CSR5=0x28, /* Status */
- CSR6=0x30, /* Command mode */
- CSR7=0x38, /* Interrupt Mask */
- CSR8=0x40, /* Missed frame counter */
- CSR9=0x48, /* Eth.addrROM SROM mii SROM mii */
- CSR10=0x50, /* Diagn. boot ROM - */
- CSR11=0x58, /* Full duplex G.P. timer G.P. timer */
- CSR12=0x60, /* SIA status G.P. */
- CSR13=0x68, /* SIA connectivity - */
- CSR14=0x70, /* SIA TX/RX - */
- CSR15=0x78 /* SIA general watchdog */
+ CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+ CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+ CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+ TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+ RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02,
+ TxIntr=0x01,
};
-/* description of CSR0 bus mode register */
-#define TBMOD_RESERVED 0xfff80000 /* I don't know */
-#define TBMOD_RESET 0x00000001
-#define TBMOD_BIGENDIAN 0x00000080
-/*
- Cache alignment bits 15:14 Burst length 13:8
- 0000 No alignment 0x00000000 unlimited 0800 8 longwords
- 4000 8 longwords 0100 1 longword 1000 16 longwords
- 8000 16 longwords 0200 2 longwords 2000 32 longwords
- C000 32 longwords 0400 4 longwords
-*/
-#define TBMOD_ALIGN0 0x00000000 /* no cache alignment */
-#define TBMOD_ALIGN8 0x00004000 /* 8 longwords */
-#define TBMOD_ALIGN16 0x00008000
-#define TBMOD_ALIGN32 (TBMOD_ALIGN8|TBMOD_ALIGN16)
-#define TBMOD_BURST0 0x00000000 /* unlimited=rx buffer size */
-#define TBMOD_BURST1 0x00000100 /* 1 longwords */
-#define TBMOD_BURST2 0x00000200
-#define TBMOD_BURST4 0x00000400
-#define TBMOD_BURST8 0x00000800
-#define TBMOD_BURST16 0x00001000
-#define TBMOD_BURST32 0x00002000
-
-/* description of CSR1 Tx poll demand register */
-/* description of CSR2 Rx poll demand register */
-#define TPOLL_START 0x00000001 /* ? */
-#define TPOLL_TRIGGER 0x00000000 /* ? */
-
-/* description of CSR5 status register from de4x5.h */
-#define TSTAT_BUSERROR 0x03800000
-#define TSTAT_SYSERROR 0x00002000
-#define TSTAT_TxSTAT 0x00700000
-#define TSTAT_RxSTAT 0x000e0000
-#define TSTAT_LKFAIL 0x00001000
-#define TSTAT_NORINTR 0x00010000 /* Normal interrupt */
-#define TSTAT_ABNINTR 0x00008000 /* Abnormal interrupt */
-#define TSTAT_RxMISSED 0x00000100 /* Rx frame missed */
-#define TSTAT_RxUNABL 0x00000080
-#define TSTAT_RxINTR 0x00000040
-#define TSTAT_LKPASS 0x00000010
-#define TSTAT_TEXPIRED 0x00000800 /* Timer Expired */
-#define TSTAT_TxTOUT 0x00000008
-#define TSTAT_TxUNABL 0x00000004
-#define TSTAT_TxINTR 0x00000001
-#define TSTAT_CLEARINTR 0x0001ffff /* clear all interrupt sources */
-
-/* description of CSR6 command mode register */
-#define TCMOD_SCRM 0x01000000 /* scrambler mode */
-#define TCMOD_PCS 0x00800000 /* PCS function */
-#define TCMOD_TxTHMODE 0x00400000 /* Tx threshold mode */
-#define TCMOD_SW100TP 0x00040000 /* 21140: 100MB */
-#define TCMOD_CAPTURE 0x00020000 /* capture effect */
-#define TCMOD_FULLDUPLEX 0x00000200
-#define TCMOD_TH128 0x00008000 /* 10 - 128 bytes threshold */
-#define TCMOD_TxSTART 0x00002000
-#define TCMOD_RxSTART 0x00000002
-#define TCMOD_ALLMCAST 0x00000080 /* pass all multicast */
-#define TCMOD_PROMISC 0x00000040 /* promisc */
-#define TCMOD_BOFFCOUNTER 0x00000020 /* backoff counter */
-#define TCMOD_INVFILTER 0x00000010 /* invert filtering */
-#define TCMOD_HONLYFILTER 0x00000004 /* hash only filtering */
-#define TCMOD_HPFILTER 0x00000001 /* hash/perfect Rx filtering */
-#define TCMOD_MODEMASK (TCMOD_ALLMCAST|TCMOD_PROMISC)
-#define TCMOD_FILTERMASK (TCMOD_HONLYFILTER|TCMOD_HPFILTER|TCMOD_INVFILTER)
-#define TCMOD_TRxSTART (TCMOD_TxSTART|TCMOD_RxSTART)
-#define TCMOD_BASE (TCMOD_CAPTURE|TCMOD_BOFFCOUNTER)
-#define TCMOD_10TP (TCMOD_TxTHMODE|TCMOD_BASE)
-#define TCMOD_100TP (TCMOD_SCRM|TCMOD_PCS|TCMOD_SW100TP|TCMOD_BASE)
-#define TCMOD_AUTO (TCMOD_SW100TP|TCMOD_TH128|TCMOD_10TP)
-
-/* description of CSR7 interrupt mask register */
-#define TINTR_ENABLE 0xFFFFBBFF
-#define TINTR_DISABLE 0x00000000
-
-/* description of CSR11 G.P. timer (21041/21140) register */
-#define TGEPT_COUNT 0x0001FFFF
-
-/* description of CSR12 SIA status(2104x)/GP(21140) register */
-#define TSIAS_CONERROR 0x00000002 /* connection error */
-#define TSIAS_LNKERROR 0x00000004 /* link error */
-#define TSIAS_ACTERROR 0x00000200 /* port Rx activity */
-#define TSIAS_RxACTIVE 0x00000100 /* port Rx activity */
-
-#define TGEPR_LK10NG 0x00000080 /* 10Mbps N.G. (R) */
-#define TGEPR_LK100NG 0x00000040 /* 100Mbps N.G. (R) */
-#define TGEPR_DETECT 0x00000020 /* detect signal (R) */
-#define TGEPR_HALFDUPLEX 0x00000008 /* half duplex (W) */
-#define TGEPR_PHYLOOPBACK 0x00000004 /* PHY loopback (W) */
-#define TGEPR_FORCEALED 0x00000002 /* force activity LED on (W) */
-#define TGEPR_FORCE100 0x00000001 /* force 100Mbps mode */
-
-/* description of CSR13 SIA connectivity register */
-#define TSIAC_OUTEN 0x0000e000 /* 21041: Output enable */
-#define TSIAC_SELED 0x00000f00 /* 21041: AUI or TP with LEDs */
-#define TSIAC_INEN 0x00001000 /* 21041: Input enable */
-#define TSIAC_NO10TP 0x00000008 /* 10baseT(0) or not(1) */
-#define TSIAC_CONFIG 0x00000004 /* Configuration */
-#define TSIAC_SWRESET 0x00000001 /* 21041: software reset */
-#define TSIAC_RESET 0x00000000 /* reset */
-#define TSIAC_C21041 (TSIAC_OUTEN|TSIAC_SELED|TSIAC_SWRESET)
-#define TSIAC_C21040 TSIAC_CONFIG
-
-/* description of CSR14 SIA TX/RX register */
-#define TSIAX_NO10TP 0x0000f73d
-#define TSIAX_10TP 0x0000ff3f
-
-/* description of CSR15 SIA general register */
-#define TSIAG_SWBNCAUI 0x00000008 /* BNC(0) or AUI(1) */
-#define TSIAG_BNC 0x00000006
-#define TSIAG_AUI (TSIAG_BNC|TSIAG_SWBNCAUI)
-#define TSIAG_10TP 0x00000000
-
-/* description of rx_ring.status */
-#define TRING_OWN 0x80000000 /* Owned by chip */
-#define TRING_CLEAR 0x00000000 /* clear */
-#define TRING_ERROR 0x00008000 /* error summary */
-#define TRING_ETxTO 0x00004000 /* Tx time out */
-#define TRING_ELCOLL 0x00000200 /* late collision */
-#define TRING_EFCOLL 0x00000100 /* fatal collision */
-#define TRING_ELCARR 0x00000800 /* carrier lost */
-#define TRING_ENCARR 0x00000400 /* no carrier */
-#define TRING_ENOHB 0x00000080 /* heartbeat fail */
-#define TRING_ELINK 0x00000004 /* link fail */
-#define TRING_EUFLOW 0x00000002 /* underflow */
-
-#define TRING_ELEN 0x00004000 /* length error */
-#define TRING_FDESC 0x00000200 /* first descriptor */
-#define TRING_LDESC 0x00000100 /* last descriptor */
-#define TRING_ERUNT 0x00000800 /* runt frame */
-#define TRING_ELONG 0x00000080 /* frame too long */
-#define TRING_EWATCHDOG 0x00000010 /* receive watchdog */
-#define TRING_EDRBIT 0x00000004 /* dribble bit */
-#define TRING_ECRC 0x00000002 /* CRC error */
-#define TRING_EOVERFLOW 0x00000001 /* overflow */
-
-#define TRING_RxDESCMASK (TRING_FDESC|TRING_LDESC)
-#define TRING_RxLENGTH (TRING_ERUNT|TRING_ELONG|TRING_EWATCHDOG)
-#define TRING_RxFRAME (TRING_EDRBIT)
-#define TRING_RxCRC (TRING_ECRC)
-#define TRING_RxFIFO (TRING_EOVERFLOW)
-#define TRING_TxABORT (TRING_ETxTO|TRING_EFCOLL|TRING_ELINK)
-#define TRING_TxCARR (TRING_ELCARR|TRING_ENCARR)
-#define TRING_TxWINDOW (TRING_ELCOLL)
-#define TRING_TxFIFO (TRING_EUFLOW)
-#define TRING_TxHEARTBEAT (TRING_ENOHB)
/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
s32 status;
s32 length;
- u32 buffer1, buffer2; /* We use only buffer 1. */
+ u32 buffer1, buffer2;
};
struct tulip_tx_desc {
s32 status;
s32 length;
- u32 buffer1, buffer2; /* We use only buffer 1. */
+ u32 buffer1, buffer2; /* We use only buffer 1. */
+};
+
+struct medialeaf {
+ u8 type;
+ u8 media;
+ unsigned char *leafdata;
+};
+
+struct mediatable {
+ u16 defaultmedia;
+ u8 leafcount, csr12dir; /* General purpose pin directions. */
+ unsigned has_mii:1;
+ struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+ struct mediainfo *next;
+ int info_type;
+ int index;
+ struct non_mii { char media; unsigned char csr12val; char bitnum, flags;} non_mii;
+ unsigned char *info;
};
struct tulip_private {
+ char devname[8]; /* Used only for kernel debugging. */
+ const char *product_name;
+ struct device *next_module;
struct tulip_rx_desc rx_ring[RX_RING_SIZE];
struct tulip_tx_desc tx_ring[TX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
- char rx_buffs[RX_RING_SIZE][PKT_BUF_SZ];
- /* temporary Rx buffers. */
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ char *rx_buffs; /* Address of temporary Rx buffers. */
+ u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */
+ int chip_id;
+ int revision;
+#if LINUX_VERSION_CODE > 0x20139
struct net_device_stats stats;
- int setup_frame[48]; /* Pseudo-Tx frame to init address table. */
- void (*port_select)(struct device *dev);
- int (*port_fail)(struct device *dev);
- struct device *next_module;
- char *signature;
+#else
+ struct enet_statistics stats;
+#endif
+ struct timer_list timer; /* Media selection timer. */
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ int fc_bit;
+#endif
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int port_fix:1; /* Fix if_port to specified port. */
+ unsigned int full_duplex_lock:1;
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[128]; /* Serial EEPROM contents. */
+ signed char phys[4]; /* MII device addresses. */
+ struct mediatable *mtable;
+ int cur_index; /* Current media index. */
+ unsigned char pci_bus, pci_device_fn;
+ int pad0, pad1; /* Used for 8-byte alignment */
};
-struct eeprom {
- union {
- struct { /* broken EEPROM structure */
- u_char addr[ETH_ALEN];
- } ng;
- struct { /* DEC EtherWorks
- and other cards which have correct eeprom structure */
- u_char dum1[20];
- u_char addr[ETH_ALEN];
- } ok;
- } hw;
-#define ng_addr hw.ng.addr
-#define ok_addr hw.ok.addr
-#define EE_SIGNLEN 14 /* should be 102 ? */
- u_char sign[EE_SIGNLEN];
-};
-
-static int read_eeprom(unsigned long ioaddr, struct eeprom *eepp);
+static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int options);
+static void parse_eeprom(struct device *dev);
+static int read_eeprom(int ioaddr, int location);
+static int mdio_read(int ioaddr, int phy_id, int location);
+static void select_media(struct device *dev, int startup);
static int tulip_open(struct device *dev);
+static void tulip_timer(unsigned long data);
+static void tulip_tx_timeout(struct device *dev);
static void tulip_init_ring(struct device *dev);
static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
static int tulip_rx(struct device *dev);
-static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
static int tulip_close(struct device *dev);
-static struct net_device_stats *tulip_get_stats(struct device *dev);
+static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef NEW_MULTICAST
static void set_multicast_list(struct device *dev);
+#else
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+#include <linux/if_arp.h>
+#include <net/ip.h>
-#define generic21140_fail NULL
-static void generic21040_select(struct device *dev);
-static void generic21140_select(struct device *dev);
-static void generic21041_select(struct device *dev);
-static void auto21140_select(struct device *dev);
-static void cogent21140_select(struct device *dev);
-static int generic21040_fail(struct device *dev);
-static int generic21041_fail(struct device *dev);
+static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst);
+#endif
+
+
#ifdef MODULE
/* A list of all installed Tulip devices, for removing the driver module. */
static struct device *root_tulip_dev = NULL;
#endif
-static struct {
- void (*port_select)(struct device *dev);
- int (*port_fail)(struct device *dev);
- unsigned int vendor_id, device_id;
- char *signature;
- unsigned int array:1;
-} cardVendor[] = {
- {generic21140_select, generic21140_fail,
- 0x0000c000, PCI_DEVICE_ID_DEC_TULIP_FAST, "smc9332", 0},
- {generic21041_select, generic21041_fail,
- 0x0000c000, PCI_DEVICE_ID_DEC_TULIP_PLUS, "smc8432", 0},
- {generic21040_select, generic21040_fail,
- 0x0000c000, PCI_DEVICE_ID_DEC_TULIP, "old smc8432", 0},
- {auto21140_select, generic21140_fail,
- 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,
- 0x0000f800, PCI_DEVICE_ID_DEC_TULIP_PLUS, "DE450", 0},
- {generic21040_select, generic21040_fail,
- 0x0000f800, PCI_DEVICE_ID_DEC_TULIP, "DE43x", 0},
- {generic21040_select, generic21040_fail,
- 0x0040c700, PCI_DEVICE_ID_DEC_TULIP, "EN9400", 0},
- {generic21040_select, generic21040_fail,
- 0x00c09500, PCI_DEVICE_ID_DEC_TULIP, "ZNYX312", 1},
- {generic21040_select, generic21040_fail,
- 0x08002b00, PCI_DEVICE_ID_DEC_TULIP, "QSILVER's", 0},
- {generic21040_select, generic21040_fail,
- 0, PCI_DEVICE_ID_DEC_TULIP, "21040", 0},
- {generic21140_select, generic21140_fail,
- 0, PCI_DEVICE_ID_DEC_TULIP_FAST, "21140", 0},
- {generic21041_select, generic21041_fail,
- 0, PCI_DEVICE_ID_DEC_TULIP_PLUS, "21041", 0},
- {NULL, NULL, 0, 0, "Unknown", 0}
-};
+/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
+ but now receives directly into full-sized skbuffs that are allocated
+ at open() time.
+ This allows the probe routine to use the old driver initialization
+ interface. */
-
-/* Serial EEPROM section.
- A "bit" grungy, but we work our way through bit-by-bit :->. */
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
-#define EE_CS 0x01 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x01
-#define EE_WRITE_1 0x05
-#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
-#define EE_ENB (0x4800 | EE_CS)
+int tulip_probe(struct device *dev)
+{
+ int cards_found = 0;
+ static int pci_index = 0; /* Static, for multiple probe calls. */
+
+ /* Ideally we would detect all network cards in slot order. That would
+ be best done a central PCI probe dispatch, which wouldn't work
+ well with the current structure. So instead we detect just the
+ Tulip cards in slot order. */
+
+ if (pcibios_present()) {
+ unsigned char pci_bus, pci_device_fn;
+
+ for (;pci_index < 0xff; pci_index++) {
+ unsigned char pci_irq_line, pci_latency;
+ unsigned short pci_command, vendor, device;
+ unsigned int pci_ioaddr, chip_idx = 0;
+
+ if (pcibios_find_class
+ (PCI_CLASS_NETWORK_ETHERNET << 8,
+ reverse_probe ? 0xfe - pci_index : pci_index,
+ &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+ if (reverse_probe)
+ continue;
+ else
+ break;
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ 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 != PCI_VENDOR_ID_DEC
+ && vendor != PCI_VENDOR_ID_LITEON)
+ continue;
+ if (vendor == PCI_VENDOR_ID_LITEON)
+ device = PCI_DEVICE_ID_PNIC_X;
+
+ for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
+ if (device == tulip_tbl[chip_idx].device_id)
+ break;
+ if (tulip_tbl[chip_idx].chip_name == 0) {
+ printk(KERN_INFO "Unknown Digital PCI ethernet chip type"
+ " %4.4x"" detected: not configured.\n", device);
+ continue;
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n",
+ pci_ioaddr, pci_irq_line);
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5 << 6)
-#define EE_READ_CMD (6 << 6)
-#define EE_ERASE_CMD (7 << 6)
+ if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE))
+ continue;
#ifdef MODULE
-static int if_port=TULIP_AUTO_PORT;
-#ifdef TULIP_FULL_DUPLEX
-static int full_duplex=1;
+ dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
+ cards_found);
#else
-static int full_duplex=0;
-#endif
+ dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1);
#endif
-#define tio_write(val, port) outl(val, ioaddr + port)
-#define tio_read(port) inl(ioaddr + port)
+ if (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)) {
+ printk(KERN_INFO " 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(KERN_INFO " PCI latency timer (CFLT) is unreasonably"
+ " low at %d. Setting to 64 clocks.\n", pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 64);
+ } else if (tulip_debug > 1)
+ printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n",
+ pci_latency);
+ /* Bring the 21143 out power-down mode. */
+ if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ 0x40, 0x40000000);
+ dev = 0;
+ cards_found++;
+ }
+ }
+ }
-static void inline
-tio_sia_write(unsigned long ioaddr, u32 val13, u32 val14, u32 val15)
-{
- tio_write(0,CSR13);
- tio_write(val15,CSR15);
- tio_write(val14,CSR14);
- tio_write(val13,CSR13);
+ return cards_found ? 0 : -ENODEV;
}
-/*
- card_type returns 1 if the card is 'etherarray'
-*/
-
-__initfunc(static int
-card_type(struct tulip_private *tp, int device_id, int vendor_id))
+static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+ int chip_id, int board_idx)
{
- int n;
-
- for (n = 0; cardVendor[n].device_id; n ++)
- if (cardVendor[n].device_id == device_id
- && (cardVendor[n].vendor_id == vendor_id
- || cardVendor[n].vendor_id == 0)) break;
- tp->port_select = cardVendor[n].port_select;
- tp->port_fail = cardVendor[n].port_fail;
- tp->signature = cardVendor[n].signature;
- return(cardVendor[n].array ? 1: 0);
-}
+ static int did_version = 0; /* Already printed version info. */
+ struct tulip_private *tp;
+ /* See note below on the multiport cards. */
+ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+ static int last_irq = 0;
+ int i;
+ unsigned short sum;
-__initfunc(static int
-read_eeprom(unsigned long ioaddr, struct eeprom *eepp))
-{
- int i, n;
- unsigned short val = 0;
- int read_cmd = EE_READ_CMD;
- u_char *p=(u_char *)eepp;
-
- for (n = 0; n < sizeof(struct eeprom) / 2; n ++, read_cmd ++) {
- tio_write(EE_ENB & ~EE_CS, CSR9);
- tio_write(EE_ENB, CSR9);
-
- /* Shift the read command bits out. */
- for (i = 10; i >= 0; i--) {
- short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- tio_write(EE_ENB | dataval, CSR9);
- udelay(100);
- tio_write(EE_ENB | dataval | EE_SHIFT_CLK, CSR9);
- udelay(150);
- tio_write(EE_ENB | dataval, CSR9);
- udelay(250);
+ if (tulip_debug > 0 && did_version++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dev = init_etherdev(dev, 0);
+
+ printk(KERN_INFO "%s: %s at %#3x,",
+ dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
+
+ /* Stop the chip's Tx and Rx processes. */
+ outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+ /* Clear the missed-packet counter. */
+ (volatile)inl(ioaddr + CSR8);
+
+ if (chip_id == DC21041) {
+ if (inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_id = DC21040;
+ } else {
+ printk(" 21041 mode,");
}
- tio_write(EE_ENB, CSR9);
-
- for (i = 16; i > 0; i--) {
- tio_write(EE_ENB | EE_SHIFT_CLK, CSR9);
- udelay(100);
- val = (val << 1)
- | ((tio_read(CSR9) & EE_DATA_READ) ? 1 : 0);
- tio_write(EE_ENB, CSR9);
- udelay(100);
+ }
+
+ /* The station address ROM is read byte serially. The register must
+ be polled, waiting for the value to be read bit serially from the
+ EEPROM.
+ */
+ sum = 0;
+ if (chip_id == DC21040) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 6; i++) {
+ int value, boguscnt = 100000;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ dev->dev_addr[i] = value;
+ sum += value & 0xff;
}
+ } else if (chip_id == LC82C168) {
+ for (i = 0; i < 3; i++) {
+ int value, boguscnt = 100000;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ ((u16*)dev->dev_addr)[i] = value;
+ sum += value & 0xffff;
+ }
+ } else { /* Must be a new chip, with a serial EEPROM interface. */
+ /* We read the whole EEPROM, and sort it out later. DEC has a
+ specification _Digital Semiconductor 21X4 Serial ROM Format_
+ but early vendor boards just put the address in the first six
+ EEPROM locations. */
+ unsigned char ee_data[128];
+ int sa_offset = 0;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
+
+ /* Detect the simple EEPROM format by the duplicated station addr. */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ sa_offset = 20;
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += ee_data[i + sa_offset];
+ }
+ }
+ /* Lite-On boards have the address byte-swapped. */
+ if (dev->dev_addr[0] == 0xA0 && dev->dev_addr[1] == 0x00)
+ for (i = 0; i < 6; i+=2) {
+ char tmp = dev->dev_addr[i];
+ dev->dev_addr[i] = dev->dev_addr[i+1];
+ dev->dev_addr[i+1] = tmp;
+ }
+ /* On the Zynx 315 Etherarray and other multiport boards only the
+ first Tulip has an EEPROM.
+ The addresses of the subsequent ports are derived from the first.
+ Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+ that here as well. */
+ if (sum == 0 || sum == 6*0xff) {
+ printk(" EEPROM not present,");
+ for (i = 0; i < 5; i++)
+ dev->dev_addr[i] = last_phys_addr[i];
+ dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386) /* This BIOS bug doesn't exist on Alphas. */
+ irq = last_irq;
+#endif
+ }
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
- /* Terminate the EEPROM access. */
- tio_write(EE_ENB & ~EE_CS, CSR9);
- *p ++ = le16_to_cpu(val);
- *p ++ = le16_to_cpu(val) >> 8;
- }
- /* broken eeprom ? */
- p = (u_char *)eepp;
- for (i = 0; i < 8; i ++)
- if (p[i] != p[15 - i] || p[i] != p[16 + i]) return(0);
- return(-1); /* broken */
-}
+ /* We do a request_region() only to register /proc/ioports info. */
+ request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
-/* Is this required ? */
-static int
-generic21040_fail(struct device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
- return(tio_read(CSR12) & TSIAS_CONERROR);
-}
+ /* Make certain the data structures are quadword aligned. */
+ tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
+ memset(tp, 0, sizeof(*tp));
+ dev->priv = tp;
-static int
-generic21041_fail(struct device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
- u32 csr12 = tio_read(CSR12);
+#ifdef MODULE
+ tp->next_module = root_tulip_dev;
+ root_tulip_dev = dev;
+#endif
- return((!(csr12 & TSIAS_CONERROR)
- || !(csr12 & TSIAS_LNKERROR)) ? 0: 1);
-}
+ tp->chip_id = chip_id;
-static void
-generic21040_select(struct device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
- const char *media;
+#ifdef TULIP_FULL_DUPLEX
+ tp->full_duplex = 1;
+ tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+ tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+ tp->medialock = 1;
+#endif
- dev->if_port &= 3;
- switch (dev->if_port)
- {
- case TULIP_10TP_PORT:
- media = "10baseT";
+ /* The lower four bits are the media type. */
+ if (board_idx >= 0) {
+ tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0;
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
+ tp->default_port = options[board_idx] & 15;
+ if (tp->default_port)
+ tp->medialock = 1;
+ if (mtu[board_idx] > 0)
+ dev->mtu = mtu[board_idx];
+ }
+
+ /* This is logically part of probe1(), but too complex to write inline. */
+ if (chip_id != DC21040 && chip_id != LC82C168)
+ parse_eeprom(dev);
+
+ if (tp->mtable && tp->mtable->has_mii) {
+ int phy, phy_idx;
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later,
+ but takes much time. */
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 0);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ tp->phys[phy_idx++] = phy;
+ printk(KERN_INFO "%s: MII transceiver found at MDIO address %d.\n",
+ dev->name, phy);
+ }
+ }
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ tp->phys[0] = 1;
+ }
+ }
+
+ /* The Tulip-specific entries in the device structure. */
+ dev->open = &tulip_open;
+ dev->hard_start_xmit = &tulip_start_xmit;
+ dev->stop = &tulip_close;
+ dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+ dev->accept_fastpath = tulip_accept_fastpath;
+#endif
+
+ /* Reset the xcvr interface and turn on heartbeat. */
+ switch (chip_id) {
+ case DC21041:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+ outl(inl(ioaddr + CSR6) | 0x200, ioaddr + CSR6);
+ outl(0x0000EF05, ioaddr + CSR13);
break;
- case TULIP_AUI_PORT:
- media = "AUI";
+ case DC21140: case DC21142:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
break;
- case TULIP_BNC_PORT:
- media = "BNC";
+ case DC21040:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0x00000004, ioaddr + CSR13);
break;
- default:
- media = "unknown type";
+ case LC82C168:
+ outl(0x33, ioaddr + CSR12);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
break;
}
- printk("%s: enabling %s port.\n", dev->name, media);
- /* Set the full duplex match frame. */
- tio_write(FULL_DUPLEX_MAGIC, CSR11);
- tio_write(TSIAC_RESET, CSR13);
- /* Reset the serial interface */
- tio_write((dev->if_port ? TSIAC_NO10TP: 0) | TSIAC_C21040, CSR13);
-}
-#if 0
-static void
-generic_timer(struct device *dev, u32 count)
+ return dev;
+}
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+ Search www.digital.com for "21X4 SROM" to get details.
+ This code is very complex, and will require changes to support
+ additional cards, so I'll be verbose about what is going on.
+ */
+
+/* Known cards that have old-style EEPROMs. */
+static struct fixups {
+ char *name;
+ unsigned char addr0, addr1, addr2;
+ u16 newtable[32]; /* Max length below. */
+} eeprom_fixups[] = {
+ {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0903, 0x006D, /* 100baseTx */ }},
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x013f,
+ 0x0103, 0x006D, /* 100baseTx */ }},
+ {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
+ {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ }},
+ {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+ "21142 non-MII PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+#define EEPROM_SIZE 128
+static void parse_eeprom(struct device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ /* The last media info list parsed, for multiport boards. */
+ static struct mediatable *last_mediatable = NULL;
+ static unsigned char *last_ee_data = NULL;
+ static controller_index = 0;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned char *ee_data = tp->eeprom;
+ int i;
- tio_write(count, CSR11);
- while (tio_read(CSR11) & TGEPT_COUNT);
-}
-#endif
+ tp->mtable = 0;
+ for (i = 0; i < EEPROM_SIZE/2; i++)
+ ((u16 *)ee_data)[i] = read_eeprom(ioaddr, i);
-static void
-generic21041_select(struct device *dev)
-{
- unsigned long ioaddr = dev->base_addr;
- u32 tsiac = TSIAC_C21041;
- u32 tsiax = TSIAX_10TP;
- u32 tsiag = TSIAG_10TP;
-
- switch(dev->if_port) {
- case TULIP_AUI_PORT:
- tsiac |= TSIAC_NO10TP;
- tsiax = TSIAX_NO10TP;
- tsiag = TSIAG_AUI;
- break;
- case TULIP_BNC_PORT:
- tsiac |= TSIAC_NO10TP;
- tsiax = TSIAX_NO10TP;
- tsiag = TSIAG_BNC;
- break;
- default:
- dev->if_port = TULIP_10TP_PORT;
- break;
+ /* Detect an old-style (SA only) EEPROM layout:
+ memcmp(eedata, eedata+16, 8). */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ break;
+ if (i >= 8) {
+ if (ee_data[0] == 0xff) {
+ if (last_mediatable) {
+ controller_index++;
+ printk(KERN_INFO "%s: Controller %d of multiport board.\n",
+ dev->name, controller_index);
+ tp->mtable = last_mediatable;
+ ee_data = last_ee_data;
+ goto subsequent_board;
+ } else
+ printk(KERN_INFO "%s: Missing EEPROM, this interface may "
+ "not work correctly!\n",
+ dev->name);
+ return;
+ }
+ /* Do a fix-up based on the vendor half of the station address prefix. */
+ for (i = 0; eeprom_fixups[i].name; i++) {
+ if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+ && dev->dev_addr[1] == eeprom_fixups[i].addr1
+ && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+ if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
+ i++; /* An Accton EN1207, not an outlaw Maxtech. */
+ memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+ sizeof(eeprom_fixups[i].newtable));
+ printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
+ " substitute media control info.\n",
+ dev->name, eeprom_fixups[i].name);
+ break;
+ }
+ }
+ if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+ printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n",
+ dev->name);
+ return;
+ }
+ }
+ if (tulip_debug > 1) {
+ printk(KERN_DEBUG "read_eeprom:");
+ for (i = 0; i < 64; i++) {
+ printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ",
+ read_eeprom(ioaddr, i));
+ }
+ printk("\n");
+ }
+
+ controller_index = 0;
+ if (ee_data[19] > 1) { /* Multiport board. */
+ last_ee_data = ee_data;
+ }
+subsequent_board:
+
+ if (tp->chip_id == DC21041) {
+ unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+ short media = *(u16 *)p;
+ int count = p[2];
+
+ printk(KERN_INFO "%s:21041 Media information at %d, default media "
+ "%4.4x (%s).\n", dev->name, ee_data[27], media,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ unsigned char media_code = p[3 + i*7];
+ u16 *csrvals = (u16 *)&p[3 + i*7 + 1];
+ printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
+ " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+ dev->name, media_code & 15, medianame[media_code & 15],
+ csrvals[0], csrvals[1], csrvals[2]);
+ }
+ } else {
+ unsigned char *p = (void *)ee_data + ee_data[27];
+ unsigned char csr12dir = 0;
+ int count;
+ struct mediatable *mtable;
+ u16 media = *((u16 *)p)++;
+
+ if (tp->chip_id == DC21140)
+ csr12dir = *p++;
+ count = *p++;
+ mtable = (struct mediatable *)
+ kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+ GFP_KERNEL);
+ if (mtable == NULL)
+ return; /* Horrible, impossible failure. */
+ last_mediatable = tp->mtable = mtable;
+ mtable->defaultmedia = media;
+ mtable->leafcount = count;
+ mtable->csr12dir = csr12dir;
+ mtable->has_mii = 0;
+
+ printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ struct medialeaf *leaf = &mtable->mleaf[i];
+
+ if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+ leaf->type = 0;
+ leaf->media = p[0] & 0x3f;
+ leaf->leafdata = p;
+ p += 4;
+ } else {
+ leaf->type = p[1];
+ if (p[1] & 1) {
+ mtable->has_mii = 1;
+ leaf->media = 11;
+ } else
+ leaf->media = p[2] & 0x0f;
+ leaf->leafdata = p + 2;
+ p += (p[0] & 0x3f) + 1;
+ }
+ if (tulip_debug > 1 && leaf->media == 11) {
+ unsigned char *bp = leaf->leafdata;
+ printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
+ "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+ dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+ bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+ }
+ printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
+ "by a %s (%d) block.\n",
+ dev->name, i, medianame[leaf->media], leaf->media,
+ block_name[leaf->type], leaf->type);
+ }
}
- tio_sia_write(ioaddr, tsiac, tsiax, tsiag);
- if (dev->start)
- printk("%s: enabling %s port.\n", dev->name,
- (dev->if_port == TULIP_AUI_PORT) ? "AUI":
- (dev->if_port == TULIP_BNC_PORT) ? "BNC": "10TP");
}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
-static void
-auto21140_select(struct device *dev)
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ The 1.2 code is a "nasty" timing loop, but PC compatible machines are
+ *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */
+#ifdef _LINUX_DELAY_H
+#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000)
+#else
+#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5 << 6)
+#define EE_READ_CMD (6 << 6)
+#define EE_ERASE_CMD (7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
{
int i;
- unsigned long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ unsigned short retval = 0;
+ int ee_addr = ioaddr + CSR9;
+ int read_cmd = location | EE_READ_CMD;
+
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ outl(EE_ENB, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 10; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outl(EE_ENB | dataval, ee_addr);
+ eeprom_delay(100);
+ outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay(150);
+ outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */
+ eeprom_delay(250);
+ }
+ outl(EE_ENB, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay(100);
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outl(EE_ENB, ee_addr);
+ eeprom_delay(100);
+ }
- /* kick port */
- tio_write(TPOLL_TRIGGER, CSR1);
- tio_write(TINTR_ENABLE, CSR7);
- tio_write(TCMOD_AUTO|TCMOD_TRxSTART, CSR6);
- dev->if_port = !(tio_read(CSR12) & TGEPR_FORCEALED);
- printk("%s: probed %s port.\n",
- dev->name, dev->if_port ? "100TX" : "10TP");
- tio_write((dev->if_port ? TGEPR_FORCE100: 0)
- | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12);
- tio_write(TINTR_DISABLE, CSR7);
- i = tio_read(CSR8) & 0xffff;
- tio_write(TCMOD_AUTO, CSR6);
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ return retval;
}
-static void
-cogent21140_select(struct device *dev)
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. It is just different enough from the EEPROM protocol
+ to not share code. The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+#ifdef _LINUX_DELAY_H
+#define mdio_delay() udelay(1)
+#else
+#define mdio_delay() __SLOW_DOWN_IO
+#endif
+
+static int mdio_read(int ioaddr, int phy_id, int location)
{
- unsigned long ioaddr = dev->base_addr, csr6;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- dev->if_port &= 1;
- csr6 = tio_read(CSR6) &
- ~(TCMOD_10TP|TCMOD_100TP|TCMOD_TRxSTART|TCMOD_SCRM);
- /* Stop the transmit process. */
- tio_write(csr6 | TCMOD_RxSTART, CSR6);
- printk("%s: enabling %s port.\n",
- dev->name, dev->if_port ? "100baseTx" : "10baseT");
- /* Turn on the output drivers */
- tio_write(0x0000013F, CSR12);
- tio_write((dev->if_port ? TGEPR_FORCE100: 0)
- | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12);
- tio_write((dev->if_port ? TCMOD_100TP: TCMOD_10TP)
- | TCMOD_TRxSTART | TCMOD_TH128 | csr6, CSR6);
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ unsigned short retval = 0;
+ int mdio_addr = ioaddr + CSR9;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the read command bits out. */
+ for (i = 17; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+ outl(dataval, mdio_addr);
+ mdio_delay();
+ outl(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ outl(dataval, mdio_addr);
+ mdio_delay();
+ }
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN, mdio_addr);
+
+ for (i = 16; i > 0; i--) {
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 16; i > 0; i--) {
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ }
+ return retval;
}
-static void
-generic21140_select(struct device *dev)
-{
- unsigned long ioaddr = dev->base_addr, csr6;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+/* Enable receiver */
- dev->if_port &= 1;
- csr6 = tio_read(CSR6) &
- ~(TCMOD_10TP|TCMOD_100TP|TCMOD_TRxSTART|TCMOD_SCRM);
+void tulip_xon(struct device *dev)
+{
+ struct tulip_private *lp = (struct tulip_private *)dev->priv;
- /* Stop the transmit process. */
- tio_write(csr6 | TCMOD_RxSTART, CSR6);
+ clear_bit(lp->fc_bit, &netdev_fc_xoff);
if (dev->start)
- printk("%s: enabling %s port.\n",
- dev->name, dev->if_port ? "100TX" : "10TP");
- tio_write((dev->if_port ? TCMOD_100TP: TCMOD_10TP)
- | TCMOD_TRxSTART | TCMOD_TH128 | csr6, CSR6);
- tio_write((dev->if_port ? TGEPR_FORCE100: 0)
- | (tp->full_duplex ? 0:TGEPR_HALFDUPLEX), CSR12);
+ outl(lp->csr6 | 0x2002, dev->base_addr + CSR6);
}
+#endif
+
static int
tulip_open(struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- unsigned long ioaddr = dev->base_addr;
- int i;
+ int ioaddr = dev->base_addr;
+ int i = 0;
+
+ /* On some chip revs we must set the MII/SYM port before the reset!? */
+ if (tp->mtable && tp->mtable->has_mii)
+ outl(0x00040000, ioaddr + CSR6);
- /* Reset the chip, holding bit 0 set at least 10 PCI cycles. */
- tio_write(tio_read(CSR0)|TBMOD_RESET, CSR0);
- udelay(1000);
- /* Deassert reset. Set 8 longword cache alignment, 8 longword burst.
- -> Set 32 longword cache alignment, unlimited longword burst ?
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ outl(0x00000001, ioaddr + CSR0);
+#ifdef _LINUX_DELAY_H
+ udelay(2);
+#else
+ SLOW_DOWN_IO;
+#endif
+ /* Deassert reset.
+ 486: Set 8 longword cache alignment, 8 longword burst.
+ 586: Set 16 longword cache alignment, no burst limit.
+ Cache alignment bits 15:14 Burst length 13:8
+ 0000 No alignment 0x00000000 unlimited 0800 8 longwords
+ 4000 8 longwords 0100 1 longword 1000 16 longwords
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
- tio_write(tio_read(CSR0)|TBMOD_ALIGN32|TBMOD_BURST0, CSR0);
+#if defined(__alpha__)
+ /* ToDo: Alpha setting could be better. */
+ outl(0x00200000 | 0xE000, ioaddr + CSR0);
+#elif defined(__powerpc__)
+ outl(0x00200080 | 0x8000, ioaddr + CSR0);
+#elif defined(__i386)
+#if defined(MODULE)
+ /* When a module we don't have 'x86' to check. */
+ outl(0x00200000 | 0x4800, ioaddr + CSR0);
+#else
+#ifndef ORIGINAL_TEXT
+#define x86 (boot_cpu_data.x86)
+#endif
+ outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
+ if (x86 <= 4)
+ printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
+ "alignment to %x.\n", dev->name,
+ 0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000));
+#endif
+#else
+ outl(0x00200000 | 0x4800, ioaddr + CSR0);
+#warning Processor architecture undefined!
+#endif
- if (request_irq(dev->irq, (void *)&tulip_interrupt, SA_SHIRQ,
- tp->signature, dev))
+#ifdef SA_SHIRQ
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ,
+ tulip_tbl[tp->chip_id].chip_name, dev)) {
+ return -EAGAIN;
+ }
+#else
+ if (irq2dev_map[dev->irq] != NULL
+ || (irq2dev_map[dev->irq] = dev) == NULL
+ || dev->irq == 0
+ || request_irq(dev->irq, &tulip_interrupt, 0,
+ tulip_tbl[tp->chip_id].chip_name)) {
return -EAGAIN;
+ }
+#endif
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
+
+ MOD_INC_USE_COUNT;
tulip_init_ring(dev);
+ /* This is set_rx_mode(), but without starting the transmitter. */
/* Fill the whole address filter table with our physical address. */
- {
- unsigned short *eaddrs = (unsigned short *)dev->dev_addr;
- int *setup_frm = tp->setup_frame, i;
+ {
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u32 *setup_frm = tp->setup_frame, i;
/* You must add the broadcast address when doing perfect filtering! */
- *setup_frm++ = cpu_to_le32(0xffff);
- *setup_frm++ = cpu_to_le32(0xffff);
- *setup_frm++ = cpu_to_le32(0xffff);
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
/* Fill the rest of the accept table with our physical address. */
for (i = 1; i < 16; i++) {
- *setup_frm++ = cpu_to_le32(eaddrs[0]);
- *setup_frm++ = cpu_to_le32(eaddrs[1]);
- *setup_frm++ = cpu_to_le32(eaddrs[2]);
+ *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2];
}
/* Put the setup frame on the Tx list. */
- tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
- tp->tx_ring[0].buffer1 = cpu_to_le32(virt_to_bus(tp->setup_frame));
- tp->tx_ring[0].buffer2 = cpu_to_le32(0);
- tp->tx_ring[0].status = cpu_to_le32(TRING_OWN);
- barrier();
- tp->cur_tx++, tp->dirty_tx++;
+ tp->tx_ring[0].length = 0x08000000 | 192;
+ tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[0].status = 0x80000000;
+
+ tp->cur_tx++;
}
- tio_write(virt_to_bus(tp->rx_ring), CSR3);
- tio_write(virt_to_bus(tp->tx_ring), CSR4);
+ outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+ outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+ if (dev->if_port == 0)
+ dev->if_port = tp->default_port;
+ if (tp->chip_id == DC21041 && dev->if_port > 4)
+ /* Invalid: Select initial TP, autosense, autonegotiate. */
+ dev->if_port = 4;
+
+ /* Allow selecting a default media. */
+ if (tp->mtable == NULL)
+ goto media_picked;
+ if (dev->if_port)
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media ==
+ (dev->if_port == 12 ? 0 : dev->if_port)) {
+ printk(KERN_INFO "%s: Using user-specified media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ goto media_picked;
+ }
+ if ((tp->mtable->defaultmedia & 0x0800) == 0)
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
+ printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+ dev->name, medianame[tp->mtable->mleaf[i].media]);
+ goto media_picked;
+ }
+ for (i = tp->mtable->leafcount - 1;
+ (media_fd[tp->mtable->mleaf[i].media] & 2) && i > 0; i--)
+ ;
+media_picked:
+
+ tp->cur_index = i;
+ tp->csr6 = 0;
+ select_media(dev, 1);
+
+ /* Start the chip's Tx to process setup frame. */
+ outl(tp->csr6, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2000, ioaddr + CSR6);
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
- /*
- * 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 (((s32)le32_to_cpu(tp->tx_ring[0].status)) >= 0) {
+
+
+ /* Enable interrupts by setting the interrupt mask. */
+ outl(0x0001ebef, ioaddr + CSR7);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ outl(0, ioaddr + CSR2); /* Rx poll demand */
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n",
+ dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+ inl(ioaddr + CSR13));
+ }
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer(&tp->timer);
+ tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = &tulip_timer; /* timer handler */
+ add_timer(&tp->timer);
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ tp->fc_bit = netdev_register_fc(dev, tulip_xon);
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+ dev->tx_semaphore = 1;
+#endif
+ return 0;
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct device *dev, int startup)
+{
+ int ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ struct mediatable *mtable = tp->mtable;
+ u32 new_csr6;
+ int check_mii =0, i;
+
+ if (mtable) {
+ struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+ unsigned char *p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: /* 21140 non-MII xcvr. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control"
+ " setting %2.2x.\n",
+ dev->name, p[1]);
+ dev->if_port = p[0];
+ if (startup)
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ outl(p[1], ioaddr + CSR12);
+ new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+ break;
+ case 1:
+ if (startup) {
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ dev->if_port = 11;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Doing a reset sequence of length %d.\n",
+ dev->name, p[2 + p[1]]);
+ for (i = 0; i < p[2 + p[1]]; i++)
+ outl(p[3 + p[1] + i], ioaddr + CSR12);
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s Doing a transceiver setup sequence of length %d.\n",
+ dev->name, p[1]);
+ for (i = 0; i < p[1]; i++)
+ outl(p[2 + i], ioaddr + CSR12);
+ }
+ check_mii = 1;
+ new_csr6 = 0x020C0000;
break;
+ case 2: case 4: {
+ u16 *setup = (u16*)&p[1];
+ dev->if_port = p[0] & 15;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
+ dev->name, medianame[dev->if_port], setup[0], setup[1]);
+ if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
+ outl(0, ioaddr + CSR13);
+ outl(setup[1], ioaddr + CSR14);
+ outl(setup[2], ioaddr + CSR15);
+ outl(setup[0], ioaddr + CSR13);
+ setup += 3;
+ } else {
+ outl(0, ioaddr + CSR13);
+ outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ }
+ outl(setup[0]<<16, ioaddr + CSR15); /* Direction */
+ outl(setup[1]<<16, ioaddr + CSR15); /* Data */
+ if (mleaf->type == 4)
+ new_csr6 = 0x02000000 | ((setup[2] & 0x71) << 18);
+ else
+ new_csr6 = 0x82420000;
+ break;
+ }
+ case 3: {
+ int init_length = p[1];
+ u16 * init_sequence = (u16*)(p + 2);
+ int reset_length = p[2 + init_length*2];
+ u16 * reset_sequence = (u16*)&p[3 + init_length*2];
+
+ dev->if_port = 11;
+ if (startup) {
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Doing a 21142 reset sequence of length %d.\n",
+ dev->name, reset_length);
+ for (i = 0; i < reset_length; i++)
+ outl(reset_sequence[i] << 16, ioaddr + CSR15);
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n",
+ dev->name, init_length);
+ for (i = 0; i < init_length; i++)
+ outl(init_sequence[i] << 16, ioaddr + CSR15);
+ check_mii = 1;
+ new_csr6 = 0x020C0000;
+ break;
+ }
+ default:
+ new_csr6 = 0x020C0000;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12) & 0xff);
+ } else if (tp->chip_id == DC21140) {
+ /* Set media type to MII @ 100mbps: 0x020C0000 */
+ new_csr6 = 0x020C0000;
+ dev->if_port = 11;
+ if (tulip_debug > 1) {
+ printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n",
+ dev->name, inl(ioaddr + CSR12) & 0xff);
+ }
+ } else if (tp->chip_id == DC21041) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+ dev->name, medianame[dev->if_port & 15],
+ inl(ioaddr + CSR12) & 0xffff);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ new_csr6 = 0x80020000;
+ } else if (tp->chip_id == LC82C168) {
+ if (startup)
+ dev->if_port = 3;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: LiteOn PHY status is %3.3x, CSR12 %4.4x,"
+ " media %s.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
+ medianame[dev->if_port]);
+ if (dev->if_port == 3 || dev->if_port == 5) {
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ if (startup)
+ outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
+ else
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
}
- udelay(1000);
+ } else { /* 21040 */
+ /* Turn on the xcvr interface. */
+ int csr12 = inl(ioaddr + CSR12);
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+ dev->name, dev->if_port ? "AUI" : "10baseT", csr12);
+ new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000);
+ /* Set the full duplux match frame. */
+ outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
}
- 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);
+
+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+ return;
+}
+
+static void tulip_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u32 csr12 = inl(ioaddr + CSR12);
+ int next_tick = 0;
+
+ if (tulip_debug > 3) {
+ printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
+ "SIA %8.8x %8.8x %8.8x %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
+ csr12, inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
}
- /*
- * 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);
- /* Enable interrupts by setting the interrupt mask. */
- tio_write(TINTR_ENABLE, CSR7);
+ switch (tp->chip_id) {
+ case DC21040:
+ if (csr12 & 0x0002) { /* Network error */
+ printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n",
+ dev->name, dev->if_port ? "10baseT" : "AUI");
+ dev->if_port ^= 1;
+ outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ dev->trans_start = jiffies;
+ }
+ break;
+ case DC21041:
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
+ dev->name, csr12);
+ switch (dev->if_port) {
+ case 0: case 3: case 4:
+ if (csr12 & 0x0004) { /*LnkFail */
+ /* 10baseT is dead. Check for activity on alternate port. */
+ tp->mediasense = 1;
+ if (csr12 & 0x0200)
+ dev->if_port = 2;
+ else
+ dev->if_port = 1;
+ printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+ dev->name, medianame[dev->if_port]);
+ outl(0, ioaddr + CSR13); /* Reset */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ next_tick = 10*HZ; /* 2.4 sec. */
+ } else
+ next_tick = 30*HZ;
+ break;
+ case 1: /* 10base2 */
+ case 2: /* AUI */
+ if (csr12 & 0x0100) {
+ next_tick = (30*HZ); /* 30 sec. */
+ tp->mediasense = 0;
+ } else if ((csr12 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name);
+ dev->if_port = 0;
+ select_media(dev, 0);
+ next_tick = (24*HZ)/10; /* 2.4 sec. */
+ } else if (tp->mediasense || (csr12 & 0x0002)) {
+ dev->if_port = 3 - dev->if_port; /* Swap ports. */
+ select_media(dev, 0);
+ next_tick = 20*HZ;
+ } else {
+ next_tick = 20*HZ;
+ }
+ break;
+ }
+ break;
+ case LC82C168: {
+ int phy_reg = inl(ioaddr + 0xB8);
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, inl(ioaddr + CSR5));
+ if (phy_reg & 0x04000000) { /* Remote link fault */
+ outl(0x0201F078, ioaddr + 0xB8);
+ next_tick = (24*HZ)/10;
+ } else
+ next_tick = 10*HZ;
+ if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+ "CSR5 %8.8x, PHY %3.3x.\n",
+ dev->name, medianame[dev->if_port], csr12,
+ inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ if (dev->if_port == 0) {
+ dev->if_port = 3;
+ } else
+ dev->if_port = 0;
+ next_tick = (24*HZ)/10;
+ select_media(dev, 0);
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ dev->trans_start = jiffies;
+ }
+ break;
+ }
+ case DC21140: case DC21142: {
+ struct medialeaf *mleaf;
+ unsigned char *p;
+ if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
+ /* Assume this is like a SMC card, and check its link beat bit. */
+ if ((dev->if_port == 0 && (csr12 & 0x0080)) ||
+ (dev->if_port == 1 && (csr12 & 0x0040) == 0)) {
+ dev->if_port ^= 1;
+ /* Stop the transmit process. */
+ tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000);
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to"
+ " %s media.\n", dev->name,
+ csr12 & 0xff,
+ dev->if_port ? "100baseTx" : "10baseT");
+ outl(tp->csr6 | 0xA002, ioaddr + CSR6);
+ dev->trans_start = jiffies;
+ next_tick = (24*HZ)/10;
+ } else {
+ next_tick = 10*HZ;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link"
+ " beat detected as %s.\n", dev->name,
+ csr12 & 0xff,
+ dev->if_port ? "100baseTx" : "10baseT");
+ }
+ break;
+ }
+ mleaf = &tp->mtable->mleaf[tp->cur_index];
+ p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: case 4: {
+ /* Type 0 non-MII or #4 SYM transceiver. Check the link beat bit. */
+ s8 bitnum = p[mleaf->type == 4 ? 5 : 2];
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is"
+ " %d, expecting %d.\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
+ /* Check that the specified bit has the proper value. */
+ if ((bitnum < 0) !=
+ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ medianame[mleaf->media]);
+ break;
+ }
+ if (tp->medialock)
+ break;
+ select_next_media:
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+ if (media_fd[dev->if_port])
+ goto select_next_media; /* Skip FD entries. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No link beat on media %s,"
+ " trying transceiver type %s.\n",
+ dev->name, medianame[mleaf->media & 15],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
+ select_media(dev, 0);
+ /* Restart the transmit process. */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ next_tick = (24*HZ)/10;
+ break;
+ }
+ case 1: case 3: /* 21140, 21142 MII */
+ {
+ int mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
+ int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+ printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, "
+ "MII status %4.4x, Link partner report %4.4x.\n",
+ dev->name, csr12, mii_reg1, mii_reg5);
+#ifdef notdef
+ if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0)
+ goto select_next_media;
+#else
+ if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0)
+ printk(KERN_INFO "%s: No link beat on the MII interface, "
+ "status then %4.4x now %4.4x.\n",
+ dev->name, mii_reg1,
+ mdio_read(ioaddr, tp->phys[0], 1));
+#endif
+ if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
+ ; /* No MII device or no link partner report */
+ else if (tp->full_duplex_lock)
+ ;
+ else if ((mii_reg5 & 0x0100) != 0
+ || (mii_reg5 & 0x00C0) == 0x0040) {
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex == 0) {
+ tp->full_duplex = 1;
+ tp->csr6 |= 0x0200;
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ }
+ if (tulip_debug > 0) /* Gurppp, should be >1 */
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+ " Xcvr #%d parter capability of %4.4x.\n",
+ dev->name, full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ }
+ }
+ break;
+ case 2: /* 21142 serial block has no link beat. */
+ default:
+ break;
+ }
+ }
+ break;
+ default: /* Invalid chip type. */
+ break;
+ }
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
- MOD_INC_USE_COUNT;
- return 0;
+static void tulip_tx_timeout(struct device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (tp->mtable && tp->mtable->has_mii) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if (inl(ioaddr + CSR12) & 0x0002) {
+ printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
+ dev->name, dev->if_port ? "10baseT" : "AUI");
+ dev->if_port ^= 1;
+ outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ }
+ dev->trans_start = jiffies;
+ return;
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142) {
+ /* Stop the transmit process. */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ dev->if_port ^= 1;
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
+ dev->name, dev->if_port ? "100baseTx" : "10baseT");
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ tp->stats.tx_errors++;
+ dev->trans_start = jiffies;
+ return;
+ } else if (tp->chip_id == DC21041) {
+ u32 csr12 = inl(ioaddr + CSR12);
+
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x,"
+ " CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ select_media(dev, 0);
+ tp->stats.tx_errors++;
+ dev->trans_start = jiffies;
+ return;
+ } else
+ printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
+ " resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+#ifdef way_too_many_messages
+ printk(" Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+#endif
+
+ /* Perhaps we should reinitialize the hardware here. */
+ dev->if_port = 0;
+ /* Stop and restart the chip's Tx processes . */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+
+ dev->trans_start = jiffies;
+ tp->stats.tx_errors++;
+ return;
}
+
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void
tulip_init_ring(struct device *dev)
@@ -789,76 +1695,81 @@ tulip_init_ring(struct device *dev)
tp->dirty_rx = tp->dirty_tx = 0;
for (i = 0; i < RX_RING_SIZE; i++) {
- tp->rx_ring[i].status = cpu_to_le32(TRING_OWN);
- tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
- tp->rx_ring[i].buffer1 = cpu_to_le32(virt_to_bus(tp->rx_buffs[i]));
- tp->rx_ring[i].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[i+1]));
+ tp->rx_ring[i].status = 0x80000000; /* Owned by Tulip chip */
+ tp->rx_ring[i].length = PKT_BUF_SZ;
+ {
+ /* Note the receive buffer must be longword aligned.
+ dev_alloc_skb() provides 16 byte alignment. But do *not*
+ use skb_reserve() to align the IP header! */
+ struct sk_buff *skb;
+ skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ tp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break; /* Bad news! */
+ skb->dev = dev; /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+ tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+#else
+ tp->rx_ring[i].buffer1 = virt_to_bus(skb->data);
+#endif
+ }
+ tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
}
- /* Mark the last entry as wrapping the ring. */
- tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | 0x02000000);
- tp->rx_ring[i-1].buffer2 = cpu_to_le32(virt_to_bus(&tp->rx_ring[0]));
+ /* Mark the last entry as wrapping the ring. */
+ tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
+ tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
/* The Tx buffer descriptor is filled in as needed, but we
do need to clear the ownership bit. */
for (i = 0; i < TX_RING_SIZE; i++) {
- tp->tx_ring[i].status = cpu_to_le32(0x00000000);
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
}
+ tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
}
static int
tulip_start_xmit(struct sk_buff *skb, struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- unsigned long ioaddr = dev->base_addr;
- int entry, len;
- unsigned long daddr;
+ int entry;
+ u32 flag;
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy || (tp->port_fail && tp->port_fail(dev))) {
- int tickssofar = jiffies - dev->trans_start;
- int i;
- if (tickssofar < 40) return(1);
- if (tp->port_select) {
- if (!tp->port_fix) dev->if_port ++;
- tp->port_select(dev);
- dev->trans_start = jiffies;
- return(0);
- }
- printk("%s: transmit timed out, status %8.8x,"
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, tio_read(CSR5), tio_read(CSR12),
- tio_read(CSR13), tio_read(CSR14), tio_read(CSR15));
-#if !defined(__alpha__) && !defined(__sparc_v9__)
- printk(" Rx ring %8.8x: ", (int)tp->rx_ring);
-#endif
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)le32_to_cpu(tp->rx_ring[i].status));
-#if !defined(__alpha__) && !defined(__sparc_v9__)
- printk("\n Tx ring %8.8x: ", (int)tp->tx_ring);
-#endif
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)le32_to_cpu(tp->tx_ring[i].status));
- printk("\n");
-
- tp->stats.tx_errors++;
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- tio_write(TSIAC_CONFIG, CSR13);
- /* Start the chip's Tx and Rx processes . */
- tio_write(TCMOD_10TP | TCMOD_TRxSTART, CSR6);
- /* Trigger an immediate transmit demand. */
- tio_write(TPOLL_TRIGGER, CSR1);
-
- dev->tbusy=0;
- dev->trans_start = jiffies;
- return(0);
+#ifdef ORIGINAL_TEXT
+#ifndef final_version
+ if (skb == NULL || skb->len <= 0) {
+ printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
+ dev->name);
+ dev_tint(dev);
+ return 0;
}
+#endif
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+ cli();
+ if (xchg(&dev->tx_semaphore,0) == 0) {
+ sti();
+ /* With new queueing algorithm returning 1 when dev->tbusy == 0
+ should not result in lockups, but I am still not sure. --ANK
+ */
+ if (net_ratelimit())
+ printk(KERN_CRIT "Please check: are you still alive?\n");
+ return 1;
+ }
+#endif
/* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- If this ever occurs the queue layer is doing something evil! */
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
+#ifdef CONFIG_NET_FASTROUTE
+ sti();
+#endif
+ if (jiffies - dev->trans_start >= TX_TIMEOUT)
+ tulip_tx_timeout(dev);
+#ifdef CONFIG_NET_FASTROUTE
+ dev->tx_semaphore = 1;
+#endif
return 1;
}
@@ -868,89 +1779,109 @@ tulip_start_xmit(struct sk_buff *skb, struct device *dev)
/* Calculate the next Tx descriptor entry. */
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);
-#ifdef NO_ANK_FIX
- len = 192;
-#else
- skb = NULL;
-#endif
+ tp->tx_skbuff[entry] = skb;
+ tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+
+ if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+ flag = 0x60000000; /* No interrupt */
+ dev->tbusy = 0;
+ } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+ flag = 0xe0000000; /* Tx-done intr. */
+ dev->tbusy = 0;
+ } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+ flag = 0x60000000; /* No Tx-done intr. */
+ dev->tbusy = 0;
} else {
- daddr = virt_to_bus(skb->data);
- len = skb->len;
- tp->stats.tx_bytes+=len;
+ /* Leave room for set_rx_mode() to fill entries. */
+ flag = 0xe0000000; /* Tx-done intr. */
+ tp->tx_full = 1;
}
- tp->tx_skbuff[entry] = skb;
- tp->tx_ring[entry].length = cpu_to_le32(len |
- (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000));
- tp->tx_ring[entry].buffer1 = cpu_to_le32(daddr);
- tp->tx_ring[entry].buffer2 = cpu_to_le32(0);
- tp->tx_ring[entry].status = cpu_to_le32(TRING_OWN); /* Pass ownership to the chip. */
- barrier();
+ if (entry == TX_RING_SIZE-1)
+ flag |= 0xe2000000;
+ tp->stats.tx_bytes += skb->len;
+ tp->tx_ring[entry].length = skb->len | flag;
+ tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
tp->cur_tx++;
-
/* Trigger an immediate transmit demand. */
- tio_write(TPOLL_TRIGGER, CSR1);
+ outl(0, dev->base_addr + CSR1);
dev->trans_start = jiffies;
+#ifdef CONFIG_NET_FASTROUTE
+ dev->tx_semaphore = 1;
+ sti();
+#endif
- return(0);
+ return 0;
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs)
{
- struct device *dev = (struct device *)dev_id;
+#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
+ struct device *dev = (struct device *)dev_instance;
+#else
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+
struct tulip_private *lp;
- int csr5, boguscnt=10;
- unsigned long ioaddr;
+ int csr5, ioaddr, boguscnt = 12;
if (dev == NULL) {
- printk ("tulip_interrupt(): irq %d for unknown device.\n", irq);
+ printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
+ irq);
return;
}
ioaddr = dev->base_addr;
lp = (struct tulip_private *)dev->priv;
if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
do {
- csr5 = tio_read(CSR5);
+ csr5 = inl(ioaddr + CSR5);
/* Acknowledge all of the current interrupt sources ASAP. */
- tio_write(csr5 & TSTAT_CLEARINTR, CSR5);
- /* check interrupt ? */
- if ((csr5 & (TSTAT_NORINTR|TSTAT_ABNINTR)) == 0) break;
+ outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
+ dev->name, csr5, inl(dev->base_addr + CSR5));
+
+ if ((csr5 & 0x00018000) == 0)
+ break;
- if (csr5 & TSTAT_RxINTR) /* Rx interrupt */
+ if (csr5 & RxIntr)
tulip_rx(dev);
- if (csr5 & TSTAT_TxINTR) { /* Tx-done interrupt */
- int dirty_tx = lp->dirty_tx;
+ if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+ int dirty_tx;
- while (dirty_tx < lp->cur_tx) {
+ for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
int entry = dirty_tx % TX_RING_SIZE;
- int status = le32_to_cpu(lp->tx_ring[entry].status);
+ int status = lp->tx_ring[entry].status;
if (status < 0)
break; /* It still hasn't been Txed */
+ /* Check for Rx filter setup frames. */
+ if (lp->tx_skbuff[entry] == NULL)
+ continue;
- if (status & TRING_ERROR) {
+ if (status & 0x8000) {
/* There was an major error, log it. */
+#ifndef final_version
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, status);
+#endif
lp->stats.tx_errors++;
- if (status & TRING_TxABORT) lp->stats.tx_aborted_errors++;
- if (status & TRING_TxCARR) lp->stats.tx_carrier_errors++;
- if (status & TRING_TxWINDOW) lp->stats.tx_window_errors++;
- if (status & TRING_TxFIFO) lp->stats.tx_fifo_errors++;
- if ((status & TRING_TxHEARTBEAT) && !lp->full_duplex)
+ if (status & 0x4104) lp->stats.tx_aborted_errors++;
+ if (status & 0x0C00) lp->stats.tx_carrier_errors++;
+ if (status & 0x0200) lp->stats.tx_window_errors++;
+ if (status & 0x0002) lp->stats.tx_fifo_errors++;
+ if ((status & 0x0080) && lp->full_duplex == 0)
lp->stats.tx_heartbeat_errors++;
#ifdef ETHER_STATS
if (status & 0x0100) lp->stats.collisions16++;
@@ -964,15 +1895,14 @@ static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/* Free the original skb. */
- if (lp->tx_skbuff[entry] != NULL)
- dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
- dirty_tx++;
+ dev_kfree_skb(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = 0;
}
#ifndef final_version
- if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
- printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dirty_tx, lp->cur_tx, lp->tx_full);
+ if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
dirty_tx += TX_RING_SIZE;
}
#endif
@@ -989,34 +1919,52 @@ static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/* Log errors. */
- if (csr5 & TSTAT_ABNINTR) { /* Abnormal error summary bit. */
- if (csr5 & TSTAT_TxTOUT) lp->stats.tx_errors++; /* Tx babble. */
- if (csr5 & TSTAT_RxMISSED) { /* Missed a Rx frame. */
+ if (csr5 & 0x8000) { /* Abnormal error summary bit. */
+ if (csr5 & TxJabber) lp->stats.tx_errors++;
+ if (csr5 & TxFIFOUnderflow) {
+ lp->csr6 |= 0x00200000; /* Reconfigure to store-n-forward. */
+ /* Restart the transmit process. */
+ outl(lp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(lp->csr6 | 0x2002, ioaddr + CSR6);
+ }
+ if (csr5 & RxDied) { /* Missed a Rx frame. */
lp->stats.rx_errors++;
- lp->stats.rx_missed_errors += tio_read(CSR8) & 0xffff;
+ lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
}
- if (csr5 & TSTAT_TEXPIRED) {
- printk("%s: Something Wicked happened! %8.8x.\n",
+ if (csr5 & TimerInt) {
+ printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
dev->name, csr5);
/* Hmmmmm, it's not clear what to do here. */
}
+ /* Clear all error sources, included undocumented ones! */
+ outl(0x000f7ba, ioaddr + CSR5);
}
if (--boguscnt < 0) {
- printk("%s: Too much work at interrupt, csr5=0x%8.8x.\n",
+ printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n",
dev->name, csr5);
/* Clear all interrupt sources. */
- tio_write(TSTAT_CLEARINTR, CSR5);
+ outl(0x0001ffff, ioaddr + CSR5);
break;
}
} while (1);
- /* Special code for testing *only*. */
+ if (tulip_debug > 3)
+ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+ /* Code that should never be run! Perhaps remove after testing.. */
{
static int stopit = 10;
if (dev->start == 0 && --stopit < 0) {
- printk("%s: Emergency stop, looping startup interrupt.\n",
- dev->name);
+ printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n"
+ KERN_ERR "%s: Disabling interrupt handler %d to avoid "
+ "locking up the machine.\n",
+ dev->name, dev->name, dev->irq);
+#ifdef SA_SHIRQ
free_irq(irq, dev);
+#else
+ free_irq(irq);
+#endif
}
}
@@ -1024,433 +1972,522 @@ static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
+#ifdef CONFIG_NET_FASTROUTE
+/* DMAing cards are the most easy in this respect,
+ they are able to make fast route to any device.
+
+ Now we allow to make it only to another ethernet card.
+ */
+static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst)
+{
+ struct device *odev = dst->dev;
+
+ if (dst->ops->protocol != __constant_htons(ETH_P_IP))
+ return -1;
+ if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL)
+ return -1;
+
+ return 0;
+}
+
+/*
+ Return values:
+
+ 0 - packet has gone by fast path.
+ 1 - fast path is OK, but device deferred xmit. (semifast path)
+
+ 2 - fast path is hit, but packet is a bit strange. (NI)
+ 3 - oom
+
+ 4 - fast path miss.
+ */
+
+static int tulip_fast_forward(struct device *dev, int entry, int len)
+{
+ struct tulip_private *lp = (struct tulip_private *)dev->priv;
+ struct sk_buff *skb = lp->rx_skbuff[entry];
+ struct ethhdr *eth = (void*)skb->data;
+
+ if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+ struct rtable *rt;
+ struct iphdr *iph;
+ unsigned h;
+
+ iph = (struct iphdr*)(skb->data + ETH_HLEN);
+ h = (*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK;
+ rt = (struct rtable*)(dev->fastpath[h]);
+ if (rt &&
+ ((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] &&
+ ((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] &&
+ ((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] &&
+ ((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] &&
+ rt->u.dst.obsolete == 0) {
+ struct device *odev = rt->u.dst.dev;
+
+ dev_fastroute_stat.hits++;
+
+ if (*(u8*)iph != 0x45 ||
+ (eth->h_dest[0]&1) ||
+ !neigh_is_valid(rt->u.dst.neighbour) ||
+ iph->ttl <= 1)
+ goto alas2;
+
+ ip_decrease_ttl(iph);
+
+ if (1) {
+ struct sk_buff *skb2 = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ if (skb2 == NULL)
+ goto oom;
+ lp->rx_ring[entry].buffer1 = virt_to_bus(skb2->tail);
+ skb2->dev = dev;
+ lp->rx_skbuff[entry] = skb2;
+ }
+
+ skb_put(skb, len);
+
+ ip_statistics.IpInReceives++;
+ ip_statistics.IpForwDatagrams++;
+
+ /* Could use hh cache */
+ memcpy(eth->h_source, odev->dev_addr, 6);
+ memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
+ skb->dev = odev;
+
+#ifdef FAST_SKB_RECYCLE /* DO NOT DEFINE IT! READ COMMENT */
+ /* We could use fast buffer recycling here if odev
+ is not DMAing.
+
+ The only problem is that we must allocate skb2
+ BEFORE we lose skb, otherwise we would make hole in
+ tulip rx array. Hence, to implement FAST_SKB_RECYCLE
+ we need always keep at least one skb in a safe place.
+ */
+ atomic_inc(&skb->users);
+#endif
+
+ if (odev->tx_semaphore &&
+ odev->tbusy == 0 &&
+ odev->interrupt == 0 &&
+ odev->hard_start_xmit(skb, odev) == 0) {
+#ifdef FAST_SKB_RECYCLE
+ if (atomic_read(&skb->users) == 1) {
+ skb->tail = skb->data;
+ skb->len = 0;
+ }
+#endif
+ dev_fastroute_stat.succeed++;
+ return 0;
+ }
+#ifdef FAST_SKB_RECYCLE
+ atomic_dec(&skb->users);
+#endif
+
+ /* Otherwise... */
+ skb->pkt_type = PACKET_FASTROUTE;
+ skb->nh.raw = skb->data + ETH_HLEN;
+ skb->protocol = __constant_htons(ETH_P_IP);
+ dev_fastroute_stat.deferred++;
+ return 1;
+ }
+ }
+ return 4;
+
+oom:
+ return 3;
+
+alas2:
+#ifdef not_yet
+ skb->dst = dst_clone(&rt->u.dst);
+ return 2;
+#else
+ return 4;
+#endif
+}
+#endif
+
static int
tulip_rx(struct device *dev)
{
struct tulip_private *lp = (struct tulip_private *)dev->priv;
int entry = lp->cur_rx % RX_RING_SIZE;
- int i;
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ lp->rx_ring[entry].status);
/* If we own the next entry, it's a new packet. Send it up. */
- while (((s32)le32_to_cpu(lp->rx_ring[entry].status)) >= 0) {
- int status = le32_to_cpu(lp->rx_ring[entry].status);
-
- if ((status & TRING_RxDESCMASK) != TRING_RxDESCMASK) {
- printk("%s: Ethernet frame spanned multiple buffers,"
- "status %8.8x!\n", dev->name, status);
- } else if (status & TRING_ERROR) {
+ while (lp->rx_ring[entry].status >= 0) {
+ int status = lp->rx_ring[entry].status;
+
+ if ((status & 0x0300) != 0x0300) {
+ if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+ "multiple buffers, status %8.8x!\n", dev->name, status);
+ lp->stats.rx_length_errors++;
+ }
+ } else if (status & 0x8000) {
/* There was a fatal error. */
lp->stats.rx_errors++; /* end of a packet.*/
- if (status & TRING_RxLENGTH) lp->stats.rx_length_errors++;
- if (status & TRING_RxFRAME) lp->stats.rx_frame_errors++;
- if (status & TRING_RxCRC) lp->stats.rx_crc_errors++;
- if (status & TRING_RxFIFO) lp->stats.rx_fifo_errors++;
+ if (status & 0x0890) lp->stats.rx_length_errors++;
+ if (status & 0x0004) lp->stats.rx_frame_errors++;
+ if (status & 0x0002) lp->stats.rx_crc_errors++;
+ if (status & 0x0001) lp->stats.rx_fifo_errors++;
} else {
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
- short pkt_len = (le32_to_cpu(lp->rx_ring[entry].status) >> 16) - 4;
+ short pkt_len = (lp->rx_ring[entry].status >> 16) - 4;
struct sk_buff *skb;
+ int rx_in_place = 0;
- skb = dev_alloc_skb(pkt_len + 2);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (netdev_dropping)
+ goto throttle;
+#endif
+
+ skb = lp->rx_skbuff[entry];
+
+#ifdef CONFIG_NET_FASTROUTE
+ switch (tulip_fast_forward(dev, entry, pkt_len)) {
+ case 0:
+ goto gone;
+ case 1:
+ goto semi_gone;
+ case 2:
+ break;
+ case 3:
+ skb = NULL;
+ goto memory_squeeze;
+ }
+#endif
+ /* Check if the packet is long enough to just accept without
+ copying to a properly sized skbuff. */
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+ char *temp;
+
+ /* Get a fresh skbuff to replace the filled one. */
+ newskb = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ if (newskb == NULL) {
+ skb = NULL; /* No memory, drop the packet. */
+ goto memory_squeeze;
+ }
+ /* Pass up the skb already on the Rx ring. */
+ temp = skb_put(skb, pkt_len);
+ if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal consistency error -- the "
+ "skbuff addresses do not match"
+ " in tulip_rx: %p vs. %p / %p.\n", dev->name,
+ bus_to_virt(lp->rx_ring[entry].buffer1),
+ skb->head, temp);
+ rx_in_place = 1;
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ /* Longword alignment required: do not skb_reserve(2)! */
+ lp->rx_ring[entry].buffer1 = virt_to_bus(newskb->tail);
+ } else
+ skb = DEV_ALLOC_SKB(pkt_len + 2);
+memory_squeeze:
if (skb == NULL) {
- printk("%s: Memory squeeze, deferring packet.\n",
+ int i;
+ printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n",
dev->name);
/* Check that at least two ring entries are free.
If not, free one and mark stats->rx_dropped++. */
- for (i=0; i < RX_RING_SIZE; i++)
- if (((s32)le32_to_cpu(lp->rx_ring[(entry+i) % RX_RING_SIZE].status)) < 0)
+ for (i = 0; i < RX_RING_SIZE; i++)
+ if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
break;
if (i > RX_RING_SIZE -2) {
lp->stats.rx_dropped++;
- lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN);
+ lp->rx_ring[entry].status = 0x80000000;
lp->cur_rx++;
}
break;
}
skb->dev = dev;
- skb_reserve(skb, 2);
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len);
- /* Needed for 1.3.x */
- skb->protocol = eth_type_trans(skb,dev);
+ if (! rx_in_place) {
+ skb_reserve(skb, 2); /* 16 byte align the data fields */
+#if LINUX_VERSION_CODE < 0x20200 || defined(__alpha__)
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len);
+#else
+#ifdef ORIGINAL_TEXT
+#warning Code untested
+#else
+#error Code is wrong, and it has nothing to do with 2.2 :-)
+#endif
+ eth_copy_and_sum(skb, bus_to_virt(lp->rx_ring[entry].buffer1),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
+#endif
+ }
+#if LINUX_VERSION_CODE > 0x10300
+ skb->protocol = eth_type_trans(skb, dev);
+#else
+ skb->len = pkt_len;
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+semi_gone:
+#endif
netif_rx(skb);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (netdev_dropping) {
+throttle:
+ if (lp->fc_bit) {
+ outl(lp->csr6 | 0x2000, dev->base_addr + CSR6);
+ set_bit(lp->fc_bit, &netdev_fc_xoff);
+ }
+ }
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+gone:
+#endif
lp->stats.rx_packets++;
- lp->stats.rx_bytes+=skb->len;
+#ifndef ORIGINAL_TEXT
+ lp->stats.rx_bytes += pkt_len;
+#endif
}
- lp->rx_ring[entry].status = cpu_to_le32(TRING_OWN);
+ lp->rx_ring[entry].status = 0x80000000;
entry = (++lp->cur_rx) % RX_RING_SIZE;
}
- return(0);
+
+ return 0;
}
static int
tulip_close(struct device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ int ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+#ifdef CONFIG_NET_FASTROUTE
+ dev->tx_semaphore = 0;
+#endif
dev->start = 0;
dev->tbusy = 1;
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (tp->fc_bit) {
+ int bit = tp->fc_bit;
+ tp->fc_bit = 0;
+ netdev_unregister_fc(bit);
+ }
+#endif
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
/* Disable interrupts by clearing the interrupt mask. */
- tio_write(TINTR_DISABLE, CSR7);
+ outl(0x00000000, ioaddr + CSR7);
/* Stop the chip's Tx and Rx processes. */
- tio_write(tio_read(CSR6) & ~(TCMOD_TRxSTART), CSR6);
- /* Leave the card in 10baseT state. */
- tio_write(TSIAC_CONFIG, CSR13);
+ outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+ /* 21040 -- Leave the card in 10baseT state. */
+ if (tp->chip_id == DC21040)
+ outl(0x00000004, ioaddr + CSR13);
- tp->stats.rx_missed_errors += tio_read(CSR8) & 0xffff;
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
- tio_write(0, CSR13);
-/* tio_write(0, CSR8); wake up chip ? */
+ del_timer(&tp->timer);
+#ifdef SA_SHIRQ
free_irq(dev->irq, dev);
+#else
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+#endif
- MOD_DEC_USE_COUNT;
- return(0);
-}
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = tp->rx_skbuff[i];
+ tp->rx_skbuff[i] = 0;
+ tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
+ tp->rx_ring[i].length = 0;
+ tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+ if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+ skb->free = 1;
+#endif
+ dev_kfree_skb(skb);
+ }
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (tp->tx_skbuff[i])
+ dev_kfree_skb(tp->tx_skbuff[i]);
+ tp->tx_skbuff[i] = 0;
+ }
-static int
-tulip_config(struct device *dev, struct ifmap *map)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- if (map->port == 0xff) return(-EINVAL);
- dev->if_port = map->port;
- tp->port_fix = 1;
- if (tp->port_select) tp->port_select(dev);
- return(0);
+ MOD_DEC_USE_COUNT;
+
+ return 0;
}
-static struct net_device_stats *tulip_get_stats(struct device *dev)
+static struct enet_statistics *
+tulip_get_stats(struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- /* unsigned long ioaddr = dev->base_addr;*/
+ int ioaddr = dev->base_addr;
+
+ if (dev->start)
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
- return(&tp->stats);
+ return &tp->stats;
}
-/*
- * Set or clear the multicast filter for this adaptor.
- */
+/* Set or clear the multicast filter for this adaptor.
+ Note that we only use exclusion around actually queueing the
+ new frame, not around filling tp->setup_frame. This is non-deterministic
+ when re-entered but still correct. */
-static void set_multicast_list(struct device *dev)
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
{
- unsigned long ioaddr = dev->base_addr;
- int csr6 = tio_read(CSR6) & ~(TCMOD_MODEMASK|TCMOD_FILTERMASK);
-
- if (dev->flags&IFF_PROMISC)
- { /* Set promiscuous. why ALLMULTI ? */
- tio_write(csr6 | TCMOD_PROMISC | TCMOD_ALLMCAST, CSR6);
- /* Log any net taps. */
- printk("%s: Promiscuous mode enabled.\n", dev->name);
- }
- else if (dev->mc_count > 14 || (dev->flags&IFF_ALLMULTI))
- {
- /* Too many to filter perfectly -- accept all multicasts. */
- tio_write(csr6 | TCMOD_ALLMCAST, CSR6);
- }
- else
- {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- struct dev_mc_list *dmi=dev->mc_list;
- int *setup_frm = tp->setup_frame;
- unsigned short *eaddrs;
- int i;
-
- /* We have < 15 addresses that we can use the wonderful
- 16 address perfect filtering of the Tulip. Note that only
- the low shortword of setup_frame[] is valid. */
- tio_write(csr6 | 0x0000, CSR6);
- for (i = 0; i < dev->mc_count; i ++) {
- eaddrs=(unsigned short *)dmi->dmi_addr;
- dmi=dmi->next;
- *setup_frm++ = cpu_to_le32(*eaddrs++);
- *setup_frm++ = cpu_to_le32(*eaddrs++);
- *setup_frm++ = cpu_to_le32(*eaddrs++);
+ unsigned int crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
}
- /* Fill the rest of the table with our physical address. */
- eaddrs = (unsigned short *)dev->dev_addr;
- /* Always accept broadcast packets */
- *setup_frm++ = cpu_to_le32(0xffff);
- *setup_frm++ = cpu_to_le32(0xffff);
- *setup_frm++ = cpu_to_le32(0xffff);
- do {
- *setup_frm++ = cpu_to_le32(eaddrs[0]);
- *setup_frm++ = cpu_to_le32(eaddrs[1]);
- *setup_frm++ = cpu_to_le32(eaddrs[2]);
- } while (++i < 15);
-
- /* Now add this frame to the Tx list. */
- tulip_start_xmit((struct sk_buff *) -1, dev);
}
+ return crc;
}
-__initfunc(int
-tulip_hwinit(struct device *dev, unsigned long ioaddr,
- int irq, int device_id))
-{
- /* See note below on the Znyx 315 etherarray. */
- static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
- static int last_irq;
- char detect_mesg[80], *mesgp=detect_mesg;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
- unsigned short sum, bitsum;
-
- if (check_region(ioaddr, TULIP_TOTAL_SIZE) != 0) {
- printk("tulip_hwinit: region already allocated at %#3lx.\n",
- ioaddr);
- return(-1);
- }
-
- mesgp += sprintf(mesgp, "(DEC 21%d4%d Tulip",
- device_id == PCI_DEVICE_ID_DEC_TULIP_FAST,
- device_id == PCI_DEVICE_ID_DEC_TULIP_PLUS);
-
- /* Stop the chip's Tx and Rx processes. */
- tio_write(tio_read(CSR6) & ~TCMOD_TRxSTART, CSR6);
- /* Clear the missed-packet counter. */
- i = tio_read(CSR8) & 0xffff;
-
- if (device_id == PCI_DEVICE_ID_DEC_TULIP_PLUS
- && (tio_read(CSR9) & 0x8000)) {
- mesgp += sprintf(mesgp, " treat as 21040");
- device_id = PCI_DEVICE_ID_DEC_TULIP;
- }
-
- /* The station address ROM is read byte serially. The register must
- be polled, waiting for the value to be read bit serially from the
- EEPROM.
- */
- sum = 0;
- if (device_id == PCI_DEVICE_ID_DEC_TULIP) {
- tio_write(0, CSR9);
- /* Reset the pointer with a dummy write. */
- bitsum = 0xff;
- for (i = 0; i < 6; i++) {
- int value, boguscnt = 100000;
- do
- value = tio_read(CSR9);
- while (value < 0 && --boguscnt > 0);
- dev->dev_addr[i] = value;
- sum += value & 0xFF;
- bitsum &= value;
- }
- } else {
- /* Must be a 21140/21041, with a serial EEPROM interface. */
- struct eeprom eep;
- u_char *addr;
-
- if (read_eeprom(ioaddr, &eep) < 0) {
- addr = eep.ng_addr;/* broken EEPROM structure */
- } else {
- addr = eep.ok_addr;/* DEC EtherWorks */
- }
- for (i = 0; i < ETH_ALEN; i++) {
- sum += addr[i];
- dev->dev_addr[i] = addr[i];
- }
- }
- /* Make certain the data structures are quadword aligned. */
-
- mesgp += sprintf(mesgp, ") at %016lx, ", ioaddr);
-
- /* On the Zynx 315 etherarray boards only the first Tulip has an EEPROM.
- The addresses of the subsequent ports are derived from the first. */
- if (sum == 0) {
- for (i = 0; i < ETH_ALEN - 1; i++)
- dev->dev_addr[i] = last_phys_addr[i];
- dev->dev_addr[i] = last_phys_addr[i] + 1;
- irq = last_irq;
- }
- for (i = 0; i < ETH_ALEN - 1; i++)
- mesgp += sprintf(mesgp, "%2.2x:", dev->dev_addr[i]);
- mesgp += sprintf(mesgp, "%2.2x, IRQ %d\n",
- last_phys_addr[i] = dev->dev_addr[i], irq);
- last_irq = irq;
-
- /* copy ethernet address */
- if (card_type(tp, device_id,
- htonl((*(int*)dev->dev_addr) & 0xFFFFFF)))
- for (i = 0; i < ETH_ALEN - 1; i++)
- last_phys_addr[i] = dev->dev_addr[i];
- /* We do a request_region() only to register /proc/ioports info. */
- request_region(ioaddr, TULIP_TOTAL_SIZE, tp->signature);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- /* The Tulip-specific entries in the device structure. */
- dev->open = &tulip_open;
- dev->hard_start_xmit = &tulip_start_xmit;
- dev->stop = &tulip_close;
- dev->get_stats = &tulip_get_stats;
- dev->set_config = &tulip_config;
- dev->set_multicast_list = &set_multicast_list;
-
-#ifdef MODULE
- if (if_port == TULIP_AUTO_PORT)
- if_port = TULIP_PORT;
- else
- tp->port_fix = 1;
- dev->if_port = if_port;
- tp->full_duplex = full_duplex;
- tp->next_module = root_tulip_dev;
- root_tulip_dev = dev;
+#ifdef NEW_MULTICAST
+static void set_multicast_list(struct device *dev)
#else
-#ifdef TULIP_FULL_DUPLEX
- tp->full_duplex = 1;
-#endif
- dev->if_port = TULIP_PORT;
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
#endif
-#ifdef TULIP_FIX_PORT
- tp->port_fix = 1;
-#endif
-
- printk("%s: %s %s", dev->name, tp->signature, detect_mesg);
-
- /* Reset the xcvr interface and turn on heartbeat. */
- tio_write(TSIAC_RESET, CSR13);
- tio_write(TSIAC_CONFIG, CSR13);
-
- return(0);
-}
-
-__initfunc(int tulip_probe(struct device *dev))
{
- static struct device *tulip_head=NULL;
-#ifdef __sparc_v9__
- struct pci_dev *pdev;
-#else
- u_char btmp;
- u_int itmp;
-#endif
- u_char pci_bus, pci_device_fn, pci_latency;
- u_int pci_irq;
- unsigned long pci_ioaddr;
- u_short pci_command, vendor_id, device_id;
- u_int pci_chips[] = {
- PCI_DEVICE_ID_DEC_TULIP,
- PCI_DEVICE_ID_DEC_TULIP_FAST,
- PCI_DEVICE_ID_DEC_TULIP_PLUS,
- PCI_DEVICE_ID_NONE
- };
- int num=0, cno;
- static int pci_index = 0;
-
- if (!pcibios_present())
- return(-ENODEV);
-
- 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;
-
-#ifdef __sparc_v9__
- for(pdev = pci_devices; pdev; pdev = pdev->next)
- if(pdev->bus->number == pci_bus &&
- pdev->devfn == pci_device_fn)
- break;
- if(!pdev)
- panic("tulip: Cannot find pci_dev for [%x:%x]\n",
- pci_bus, pci_device_fn);
-#endif
-
- /* get vendor id */
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID,
- &vendor_id);
- /* get device id */
- pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID,
- &device_id);
-
-#ifndef __sparc_v9__
- /* get IO address */
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
- &itmp);
- pci_ioaddr = itmp;
-
- /* get IRQ */
- pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE,
- &btmp);
- pci_irq = btmp;
-#else
- /* get IO address */
- pci_ioaddr = pdev->base_address[0];
-
- /* get IRQ */
- pci_irq = pdev->irq;
-#endif
-
- /* 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;
- }
+ int ioaddr = dev->base_addr;
+ int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
- /* 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);
- }
+ tp->csr6 &= ~0x00D5;
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ outl(csr6 | 0x00C0, ioaddr + CSR6);
+ /* Unconditionally log net taps. */
+ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ tp->csr6 |= 0xC0;
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ outl(csr6 | 0x0080, ioaddr + CSR6);
+ tp->csr6 |= 0x80;
+ } else {
+ u32 *setup_frm = tp->setup_frame;
+ struct dev_mc_list *mclist;
+ u16 *eaddrs;
+ u32 tx_flags;
+ int i;
- 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 (dev->mc_count > 14) { /* Must use a multicast hash table. */
+ u16 hash_table[32];
+ memset(hash_table, 0, sizeof(hash_table));
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ hash_table);
+ /* Copy the hash table to the setup frame.
+ NOTE that only the LOW SHORTWORD of setup_frame[] is valid! */
+ for (i = 0; i < 32; i++)
+ *setup_frm++ = hash_table[i];
+ setup_frm += 7;
+ tx_flags = 0x08400000 | 192;
+ /* Too clever: i > 15 for fall-though. */
+ } else {
+ /* We have <= 15 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ /* Note that only the low shortword of setup_frame[] is valid!
+ This code may require tweaking for non-x86 architectures! */
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs++;
+ }
+ /* Fill the rest of the table with our physical address.
+ Once again, only the low shortword or setup_frame[] is valid! */
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
+ *setup_frm++ = 0xffff;
+ tx_flags = 0x08000000 | 192;
}
+ eaddrs = (u16 *)dev->dev_addr;
+ do {
+ *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2];
+ } while (++i < 15);
+ /* Now add this frame to the Tx list. */
+ if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+ /* Same setup recently queued, we need not add it. */
+ } else {
+ unsigned long flags;
+ unsigned int entry;
+
+ save_flags(flags); cli();
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+
+ if (entry != 0) {
+ /* Avoid a chip errata by prefixing a dummy entry. */
+ tp->tx_skbuff[entry] = 0;
+ tp->tx_ring[entry].length =
+ (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+ tp->tx_ring[entry].buffer1 = 0;
+ tp->tx_ring[entry].status = 0x80000000;
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+ }
- if (tulip_hwinit(dev, pci_ioaddr, pci_irq, pci_chips[cno]) < 0) {
- continue;
+ tp->tx_skbuff[entry] = 0;
+ /* Put the setup frame on the Tx list. */
+ if (entry == TX_RING_SIZE-1)
+ tx_flags |= 0x02000000; /* Wrap ring. */
+ tp->tx_ring[entry].length = tx_flags;
+ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[entry].status = 0x80000000;
+ if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+ dev->tbusy = 1;
+ tp->tx_full = 1;
+ }
+ restore_flags(flags);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
}
- num++;
-#ifdef TULIP_MAX_CARDS
- if (num >= TULIP_MAX_CARDS) return(0);
-#endif
+ outl(csr6 | 0x0000, ioaddr + CSR6);
}
- return(num > 0 ? 0: -ENODEV);
}
-
+
#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+#endif
-/* The parameters that may be passed in... */
-/* This driver does nothing with options yet. It will later be used to
- pass the full-duplex flag, etc. */
-int debug = -1;
+/* An additional parameter that may be passed in... */
+static int debug = -1;
int
init_module(void)
{
+ if (debug >= 0)
+ tulip_debug = debug;
+
root_tulip_dev = NULL;
return tulip_probe(NULL);
}
@@ -1462,21 +2499,21 @@ cleanup_module(void)
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
while (root_tulip_dev) {
- next_dev =
- ((struct tulip_private *) root_tulip_dev->priv)->next_module;
+ next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
unregister_netdev(root_tulip_dev);
release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
kfree(root_tulip_dev);
root_tulip_dev = next_dev;
}
}
-#endif /* MODULE */
+#endif /* MODULE */
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c tulip.c"
+ * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
* c-indent-level: 4
+ * c-basic-offset: 4
* tab-width: 4
* End:
*/
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index a7a34551d..d49388b28 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -2821,7 +2821,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
wv_packet_write(dev, skb->data, skb->len);
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 6e0b1a47c..51b7e83cc 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -55,7 +55,7 @@ static void wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
static void wd_block_input(struct device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void wd_block_output(struct device *dev, int count,
- const unsigned char *buf, const start_page);
+ const unsigned char *buf, int start_page);
static int wd_close_card(struct device *dev);
@@ -497,11 +497,11 @@ cleanup_module(void)
struct device *dev = &dev_wd[this_dev];
if (dev->priv != NULL) {
int ioaddr = dev->base_addr - WD_NIC_OFFSET;
+ unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
free_irq(dev->irq, dev);
release_region(ioaddr, WD_IO_EXTENT);
- unregister_netdev(dev);
}
}
}
diff --git a/drivers/net/x25_asy.c b/drivers/net/x25_asy.c
index 275235ea7..9f20bf6cd 100644
--- a/drivers/net/x25_asy.c
+++ b/drivers/net/x25_asy.c
@@ -11,7 +11,6 @@
* checksum routines from ppp.c
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
@@ -244,7 +243,7 @@ static void x25_asy_bump(struct x25_asy *sl)
skb->protocol=htons(ETH_P_X25);
if((err=lapb_data_received(sl,skb))!=LAPB_OK)
{
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
}
else
@@ -342,13 +341,13 @@ static int x25_asy_xmit(struct sk_buff *skb, struct device *dev)
case 0x01: /* Connection request .. do nothing */
if((err=lapb_connect_request(sl))!=LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
case 0x02: /* Disconnect request .. do nothing - hang up ?? */
if((err=lapb_disconnect_request(sl))!=LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
default:
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
}
skb_pull(skb,1); /* Remove control byte */
@@ -385,7 +384,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct device *dev)
if((err=lapb_data_request(sl,skb))!=LAPB_OK)
{
printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return 0;
}
return 0;
@@ -418,7 +417,7 @@ static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
if(sl->dev->tbusy)
{
printk(KERN_ERR "x25_asy: tbusy drop\n");
- kfree_skb(skb, FREE_WRITE);
+ kfree_skb(skb);
return;
}
/* We were not busy, so we are now... :-) */
@@ -427,7 +426,7 @@ static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
x25_asy_lock(sl);
sl->tx_bytes+=skb->len;
x25_asy_encaps(sl, skb->data, skb->len);
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
}
}
diff --git a/drivers/net/zlib.c b/drivers/net/zlib.c
index a8231b550..e8db586d8 100644
--- a/drivers/net/zlib.c
+++ b/drivers/net/zlib.c
@@ -1,5 +1,5 @@
/*
- * This file is derived from various .h and .c files from the zlib-0.95
+ * This file is derived from various .h and .c files from the zlib-1.0.4
* distribution by Jean-loup Gailly and Mark Adler, with some additions
* by Paul Mackerras to aid in implementing Deflate compression and
* decompression for PPP packets. See zlib.h for conditions of
@@ -8,15 +8,13 @@
* Changes that have been made include:
* - added Z_PACKET_FLUSH (see zlib.h for details)
* - added inflateIncomp and deflateOutputPending
- * - changed DEBUG_ZLIB to DEBUG_ZLIB
- * - use ZALLOC_INIT rather than ZALLOC for allocations during initialization
* - allow strm->next_out to be NULL, meaning discard the output
*
- * $Id: zlib.c,v 1.2 1997/10/02 17:59:23 davem Exp $
+ * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
*/
/*
- * ==FILEVERSION 970501==
+ * ==FILEVERSION 971210==
*
* This marker is used by the Linux installation script to determine
* whether an up-to-date version of this file is already installed.
@@ -50,23 +48,20 @@
#include "zlib.h"
#if defined(KERNEL) || defined(_KERNEL)
-/* Assume this is a *BSD kernel */
+/* Assume this is a *BSD or SVR4 kernel */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/systm.h>
# define HAVE_MEMCPY
-# define zmemcpy(d, s, n) bcopy((s), (d), (n))
-# define zmemzero bzero
-# define zmemcmp bcmp
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memset(d, v, n) bzero((d), (n))
+# define memcmp bcmp
#else
#if defined(__KERNEL__)
/* Assume this is a Linux kernel */
#include <linux/string.h>
#define HAVE_MEMCPY
-#define zmemcpy memcpy
-#define zmemzero(dest, len) memset(dest, 0, len)
-#define zmemcmp memcmp
#else /* not kernel */
@@ -959,7 +954,7 @@ local void flush_pending(strm)
if (len > strm->avail_out) len = strm->avail_out;
if (len == 0) return;
- if (strm->next_out != NULL) {
+ if (strm->next_out != Z_NULL) {
zmemcpy(strm->next_out, s->pending_out, len);
strm->next_out += len;
}
@@ -4893,7 +4888,7 @@ int r;
z->adler = s->check = (*s->checkfn)(s->check, q, n);
/* copy as far as end of window */
- if (p != NULL) {
+ if (p != Z_NULL) {
zmemcpy(p, q, n);
p += n;
}
@@ -4921,7 +4916,7 @@ int r;
z->adler = s->check = (*s->checkfn)(s->check, q, n);
/* copy */
- if (p != NULL) {
+ if (p != Z_NULL) {
zmemcpy(p, q, n);
p += n;
}
diff --git a/drivers/net/zlib.h b/drivers/net/zlib.h
index f2e00c2db..cf9153562 100644
--- a/drivers/net/zlib.h
+++ b/drivers/net/zlib.h
@@ -1,14 +1,14 @@
-/* $Id: zlib.h,v 1.1 1997/10/02 02:35:37 paulus Exp $ */
+/* $Id: zlib.h,v 1.2 1997/12/23 10:47:44 paulus Exp $ */
/*
- * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
* distribution by Jean-loup Gailly and Mark Adler, with some additions
* by Paul Mackerras to aid in implementing Deflate compression and
* decompression for PPP packets.
*/
/*
- * ==FILEVERSION 970501==
+ * ==FILEVERSION 971127==
*
* This marker is used by the Linux installation script to determine
* whether an up-to-date version of this file is already installed.
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 8c11e3d9f..da6d30a53 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -395,7 +395,7 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev)
if (znet_debug > 4)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
- dev_kfree_skb(skb, FREE_WRITE);
+ dev_kfree_skb(skb);
return 0;
}