root/drivers/net/e2100.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mem_on
  2. mem_off
  3. e2100_probe
  4. e21_probe1
  5. e21_open
  6. e21_reset_8390
  7. e21_block_input
  8. e21_block_output
  9. e21_close

   1 /* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
   2 /*
   3     Written 1993 by Donald Becker.
   4     Copyright 1993 United States Government as represented by the
   5     Director, National Security Agency.  This software may be used and
   6     distributed according to the terms of the GNU Public License,
   7     incorporated herein by reference.
   8 
   9     This is a driver for the Cabletron E2100 series ethercards.
  10 
  11     The Author may be reached as becker@cesdis.gsfc.nasa.gov, or
  12     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
  13 
  14         The E2100 series ethercard is a fairly generic shared memory 8390
  15         implementation.  The only unusual aspect is the way the shared memory
  16         registers are set: first you do an inb() in what is normally the
  17         station address region, and the low four bits of next outb() is used
  18         as the write value for that register.  Either someone wasn't too used
  19         to dem bit en bites, or they were trying to obfusicate the programming
  20         interface.
  21 
  22         There is an additional complication when setting the window on the packet
  23         buffer.  You must first do a read into the packet buffer region with the
  24         low 8 address bits the address setting the page for the start of the packet
  25         buffer window, and then do the above operation.  See mem_on() for details.
  26 
  27         One bug on the chip is that even a hard reset won't disable the memory
  28         window, usually resulting in a hung machine if mem_off() isn't called.
  29         If this happens, you must power down the machine for about 30 seconds.
  30 */
  31 
  32 static char *version =
  33     "e2100.c:v0.01 11/21/93 Donald Becker (becker@super.org)\n";
  34 
  35 #include <linux/config.h>
  36 #include <linux/kernel.h>
  37 #include <linux/sched.h>
  38 #include <linux/errno.h>
  39 #include <linux/string.h>
  40 #include <asm/io.h>
  41 #include <asm/system.h>
  42 #ifndef PRE_PL13
  43 #include <linux/ioport.h>       /* Delete if your kernel doesn't have it. */
  44 #endif
  45 
  46 #include <linux/netdevice.h>
  47 #include "8390.h"
  48 
  49 /* Compatibility definitions for earlier kernel versions. */
  50 #ifndef HAVE_PORTRESERVE
  51 #define check_region(ioaddr, size)              0
  52 #define snarf_region(ioaddr, size);             do ; while (0)
  53 #endif
  54 #ifndef HAVE_AUTOIRQ
  55 /* From auto_irq.c, in ioport.h for later versions. */
  56 extern void autoirq_setup(int waittime);
  57 extern int autoirq_report(int waittime);
  58 /* The map from IRQ number (as passed to the interrupt handler) to
  59    'struct device'. */
  60 extern struct device *irq2dev_map[16];
  61 #endif
  62 
  63 /* Offsets from the base_addr.
  64    Read from the ASIC register, and the low 3(?) bits of the next outb() address
  65    is used to set the cooresponding register. */
  66 #define E21_NIC_OFFSET  0       /* Offset to the 8390 NIC. */
  67 #define E21_ASIC                0x10
  68 #define E21_MEM_ENABLE  0x10
  69 #define  E21_MEM_ON             0x05    /* Enable memory in 16 bit mode. */
  70 #define  E21_MEM_ON_8   0x07    /* Enable memory in  8 bit mode. */
  71 #define E21_MEM_BASE    0x11    
  72 #define E21_IRQ_LOW             0x12    /* The low three bits of the IRQ number. */
  73 #define E21_IRQ_HIGH    0x14    /* The high IRQ bit, and ...  */
  74 #define  E21_ALT_IFPORT 0x02    /* Set to use the other (BNC,AUI) port. */
  75 #define  E21_BIG_MEM    0x04    /* Use a bigger (64K) buffer (we don't) */
  76 #define E21_SAPROM      0x10    /* Offset to station address data. */
  77 #define ETHERCARD_TOTAL_SIZE    0x20
  78 
  79 extern inline void mem_on(short port, volatile char *mem_base,
     /* [previous][next][first][last][top][bottom][index][help] */
  80                                                   unsigned char start_page )
  81 {
  82         /* This is a little weird: set the shared memory window by doing a
  83            read.  The low address bits specify the starting page. */
  84         mem_base[start_page];
  85         inb(port + E21_MEM_ENABLE);
  86         outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
  87 }
  88 
  89 extern inline void mem_off(short port)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         inb(port + E21_MEM_ENABLE);
  92         outb(0x00, port + E21_MEM_ENABLE);
  93 }
  94 
  95 /* In other drivers I put the TX pages first, but the E2100 window circuitry
  96    is designed to have a 4K Tx region last. The windowing circuitry wraps the
  97    window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
  98    appear contiguously in the window. */
  99 #define E21_RX_START_PG    0x00    /* First page of RX buffer */
 100 #define E21_RX_STOP_PG     0x30    /* Last page +1 of RX ring */
 101 #define E21_BIG_RX_STOP_PG 0xF0    /* Last page +1 of RX ring */
 102 #define E21_TX_START_PG  E21_RX_STOP_PG    /* First page of TX buffer */
 103 
 104 int e2100_probe(struct device *dev);
 105 int e21_probe1(struct device *dev, int ioaddr);
 106 
 107 static int e21_open(struct device *dev);
 108 static void e21_reset_8390(struct device *dev);
 109 static int e21_block_input(struct device *dev, int count,
 110                           char *buf, int ring_offset);
 111 static void e21_block_output(struct device *dev, int count,
 112                             const unsigned char *buf, const start_page);
 113 static int e21_close(struct device *dev);
 114 
 115 
 116 /*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
 117         base address and the station address at both offset 0x10 and 0x18.  I read
 118         the station address from offset 0x18 to avoid the dataport of NE2000
 119         ethercards, and look for Ctron's unique ID (first three octets of the
 120         station address).
 121  */
 122 
 123 int e2100_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     int *port, ports[] = {0x300, 0x280, 0x380, 0x220, 0};
 126     short base_addr = dev->base_addr;
 127 
 128     if (base_addr > 0x1ff)              /* Check a single specified location. */
 129         return e21_probe1(dev, base_addr);
 130     else if (base_addr > 0)             /* Don't probe at all. */
 131         return ENXIO;
 132 
 133     for (port = &ports[0]; *port; port++) {
 134         ushort ioaddr = *port;
 135 
 136         if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
 137             continue;
 138         if (inb(ioaddr + E21_SAPROM + 0) == 0x00
 139                         && inb(ioaddr + E21_SAPROM + 1) == 0x00
 140                         && inb(ioaddr + E21_SAPROM + 2) == 0x1d
 141             && e21_probe1(dev, ioaddr) == 0)
 142             return 0;
 143     }
 144     return -ENODEV;
 145 }
 146 
 147 int e21_probe1(struct device *dev, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149         int i, status;
 150         unsigned char *station_addr = dev->dev_addr;
 151 
 152         /* We've already checked the station address prefix, now verify by making
 153            certain that there is a 8390 at the expected location. */
 154         outb(E8390_NODMA + E8390_STOP, ioaddr);
 155         SLOW_DOWN_IO;
 156         status = inb(ioaddr);
 157         if (status != 0x21 && status != 0x23)
 158                 return -ENODEV;
 159 
 160 #ifdef testing_only
 161         printk("%s: E21xx at %#3x (PAXI backwards): ", dev->name, ioaddr);
 162         for (i = 0; i < 16; i++)
 163                 printk(" %02X", inb(ioaddr + 0x1f - i));
 164         printk("\n");
 165 #endif
 166 
 167         /* Read the station address PROM.  */
 168         for (i = 0; i < 6; i++)
 169                 station_addr[i] = inb(ioaddr + E21_SAPROM + i);
 170 
 171         /* Grab the region so we can find another board if needed . */
 172         snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE);
 173 
 174         printk("%s: E21xx at %#3x, ", dev->name, ioaddr);
 175         for (i = 0; i < 6; i++)
 176                 printk(" %02X", station_addr[i]);
 177 
 178         if (dev->irq < 2) {
 179                 int irqlist[] = {15,11,10,12,5,9,3,4}, i;
 180                 for (i = 0; i < 8; i++)
 181                         if (request_irq (irqlist[i], NULL) != -EBUSY) {
 182                                 dev->irq = irqlist[i];
 183                                 break;
 184                         }
 185         } else if (dev->irq == 2)     /* Fixup bogosity: IRQ2 is really IRQ9 */
 186                 dev->irq = 9;
 187 
 188         /* Snarf the interrupt now. */
 189         if (irqaction (dev->irq, &ei_sigaction)) {
 190                 printk (" unable to get IRQ %d.\n", dev->irq);
 191                 return -EBUSY;
 192         }
 193 
 194         /* The 8390 is at the base address. */
 195         dev->base_addr = ioaddr;
 196 
 197         ethdev_init(dev);
 198 
 199         ei_status.name = "E2100";
 200         ei_status.word16 = 1;
 201         ei_status.tx_start_page = E21_TX_START_PG;
 202         ei_status.rx_start_page = E21_RX_START_PG;
 203         ei_status.stop_page = E21_RX_STOP_PG;
 204 
 205         /* Check the media port used.  The port can be passed in on the
 206            low mem_end bits. */
 207         if (dev->mem_end & 15)
 208                 dev->if_port = dev->mem_end & 7;
 209         else {
 210                 dev->if_port = 0;
 211                 inb_p(ioaddr + E21_IRQ_HIGH);   /* Select if_port detect. */
 212                 for(i = 0; i < 6; i++)
 213                         if (station_addr[i] != inb(ioaddr + E21_SAPROM))
 214                                 dev->if_port = 1;
 215         }
 216 
 217         /* Never map in the E21 shared memory unless you are actively using it.
 218            Also, the shared memory has effective only one setting -- spread all
 219            over the 128K region! */
 220         if (dev->mem_start == 0)
 221                 dev->mem_start = 0xd0000;
 222         
 223 #ifdef notdef
 224         /* These values are unused.  The E2100 has a 2K window into the packet
 225            buffer.  The window can be set to start on any page boundary. */
 226         dev->rmem_start = dev->mem_start + TX_PAGES*256;
 227         dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
 228 #endif
 229 
 230         printk(" IRQ %d, %s interface,  memory at %#x-%#x.\n", dev->irq,
 231                    dev->if_port ? "secondary" : "primary", dev->mem_start,
 232                    dev->mem_start + 2*1024 - 1);
 233 
 234         if (ei_debug > 0)
 235                 printk(version);
 236 
 237         ei_status.reset_8390 = &e21_reset_8390;
 238         ei_status.block_input = &e21_block_input;
 239         ei_status.block_output = &e21_block_output;
 240         dev->open = &e21_open;
 241         dev->stop = &e21_close;
 242         NS8390_init(dev, 0);
 243 
 244         return 0;
 245 }
 246 
 247 static int
 248 e21_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250     short ioaddr = dev->base_addr;
 251 
 252         /* Set the interrupt line and memory base on the hardware. */
 253         inb_p(ioaddr + E21_IRQ_LOW);
 254         outb_p(0, ioaddr + E21_ASIC + (dev->irq & 7));
 255         inb_p(ioaddr + E21_IRQ_HIGH);                   /* High IRQ bit, and if_port. */
 256         outb_p(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
 257                    + (dev->if_port ? E21_ALT_IFPORT : 0));
 258         inb_p(ioaddr + E21_MEM_BASE);
 259         outb_p(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
 260 
 261         return ei_open(dev);
 262 }
 263 
 264 static void
 265 e21_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267     short ioaddr = dev->base_addr;
 268 
 269     outb(0x01, ioaddr);
 270     if (ei_debug > 1) printk("resetting the E2180x3 t=%d...", jiffies);
 271     ei_status.txing = 0;
 272 
 273     /* Set up the ASIC registers, just in case something changed them. */
 274 
 275     if (ei_debug > 1) printk("reset done\n");
 276     return;
 277 }
 278 
 279 /* Block input and output are easy on shared memory ethercards.  The E21xx makes
 280    block_input() especially easy by wrapping the top ring buffer to the bottom
 281    automatically. */
 282 static int
 283 e21_block_input(struct device *dev, int count, char *buf, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285     short ioaddr = dev->base_addr;
 286         char *shared_mem = (char *)dev->mem_start;
 287         int start_page = (ring_offset>>8);
 288 
 289         mem_on(ioaddr, shared_mem, start_page);
 290 
 291     /* We'll always get a 4 byte header read first. */
 292     if (count == 4)
 293         ((int*)buf)[0] = ((int*)shared_mem)[0];
 294     else
 295         memcpy(buf, shared_mem + (ring_offset & 0xff), count);
 296 
 297     /* Turn off memory access: we would need to reprogram the window anyway. */
 298         mem_off(ioaddr);
 299 
 300     return 0;
 301 }
 302 
 303 static void
 304 e21_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 305                 int start_page)
 306 {
 307     short ioaddr = dev->base_addr;
 308         volatile char *shared_mem = (char *)dev->mem_start;
 309 
 310         /* Set the shared memory window start by doing a read, with the low address
 311            bits specifing the starting page. */
 312         *(shared_mem + start_page);
 313         mem_on(ioaddr, shared_mem, start_page);
 314 
 315         memcpy((char*)shared_mem, buf, count);
 316         mem_off(ioaddr);
 317 }
 318 
 319 static int
 320 e21_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 321 {
 322     short ioaddr = dev->base_addr;
 323 
 324     if (ei_debug > 1)
 325         printk("%s: Shutting down ethercard.\n", dev->name);
 326     NS8390_init(dev, 0);
 327 
 328         mem_off(ioaddr);
 329 
 330     return 0;
 331 }
 332 
 333 
 334 /*
 335  * Local variables:
 336  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c"
 337  *  version-control: t
 338  *  tab-width: 4
 339  *  kept-new-versions: 5
 340  * End:
 341  */

/* [previous][next][first][last][top][bottom][index][help] */