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_get_8390_hdr
  8. e21_block_input
  9. e21_block_output
  10. e21_close
  11. init_module
  12. cleanup_module

   1 /* e2100.c: A Cabletron E2100 series ethernet driver for linux. */
   2 /*
   3         Written 1993-1994 by Donald Becker.
   4 
   5         Copyright 1994 by Donald Becker.
   6         Copyright 1993 United States Government as represented by the
   7         Director, National Security Agency.  This software may be used and
   8         distributed according to the terms of the GNU Public License,
   9         incorporated herein by reference.
  10 
  11         This is a driver for the Cabletron E2100 series ethercards.
  12 
  13         The Author may be reached as becker@cesdis.gsfc.nasa.gov, or
  14         C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
  15 
  16         The E2100 series ethercard is a fairly generic shared memory 8390
  17         implementation.  The only unusual aspect is the way the shared memory
  18         registers are set: first you do an inb() in what is normally the
  19         station address region, and the low three bits of next outb() *address*
  20         is used as the write value for that register.  Either someone wasn't
  21         too used to dem bit en bites, or they were trying to obfuscate the
  22         programming interface.
  23 
  24         There is an additional complication when setting the window on the packet
  25         buffer.  You must first do a read into the packet buffer region with the
  26         low 8 address bits the address setting the page for the start of the packet
  27         buffer window, and then do the above operation.  See mem_on() for details.
  28 
  29         One bug on the chip is that even a hard reset won't disable the memory
  30         window, usually resulting in a hung machine if mem_off() isn't called.
  31         If this happens, you must power down the machine for about 30 seconds.
  32 */
  33 
  34 static const char *version =
  35         "e2100.c:v1.01 7/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
  36 
  37 #include <linux/module.h>
  38 
  39 #include <linux/kernel.h>
  40 #include <linux/sched.h>
  41 #include <linux/errno.h>
  42 #include <linux/string.h>
  43 #include <linux/ioport.h>
  44 #include <linux/netdevice.h>
  45 #include <linux/etherdevice.h>
  46 
  47 #include <asm/io.h>
  48 #include <asm/system.h>
  49 
  50 #include "8390.h"
  51 
  52 static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
  53 
  54 /* Offsets from the base_addr.
  55    Read from the ASIC register, and the low three bits of the next outb()
  56    address is used to set the corresponding register. */
  57 #define E21_NIC_OFFSET  0               /* Offset to the 8390 NIC. */
  58 #define E21_ASIC                0x10
  59 #define E21_MEM_ENABLE  0x10
  60 #define  E21_MEM_ON             0x05    /* Enable memory in 16 bit mode. */
  61 #define  E21_MEM_ON_8   0x07    /* Enable memory in  8 bit mode. */
  62 #define E21_MEM_BASE    0x11    
  63 #define E21_IRQ_LOW             0x12    /* The low three bits of the IRQ number. */
  64 #define E21_IRQ_HIGH    0x14    /* The high IRQ bit and media select ...  */
  65 #define E21_MEDIA               0x14    /* (alias). */
  66 #define  E21_ALT_IFPORT 0x02    /* Set to use the other (BNC,AUI) port. */
  67 #define  E21_BIG_MEM    0x04    /* Use a bigger (64K) buffer (we don't) */
  68 #define E21_SAPROM              0x10    /* Offset to station address data. */
  69 #define E21_IO_EXTENT    0x20
  70 
  71 extern inline void mem_on(short port, volatile char *mem_base,
     /* [previous][next][first][last][top][bottom][index][help] */
  72                                                   unsigned char start_page )
  73 {
  74         /* This is a little weird: set the shared memory window by doing a
  75            read.  The low address bits specify the starting page. */
  76         mem_base[start_page];
  77         inb(port + E21_MEM_ENABLE);
  78         outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
  79 }
  80 
  81 extern inline void mem_off(short port)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         inb(port + E21_MEM_ENABLE);
  84         outb(0x00, port + E21_MEM_ENABLE);
  85 }
  86 
  87 /* In other drivers I put the TX pages first, but the E2100 window circuitry
  88    is designed to have a 4K Tx region last. The windowing circuitry wraps the
  89    window at 0x2fff->0x0000 so that the packets at e.g. 0x2f00 in the RX ring
  90    appear contiguously in the window. */
  91 #define E21_RX_START_PG         0x00    /* First page of RX buffer */
  92 #define E21_RX_STOP_PG          0x30    /* Last page +1 of RX ring */
  93 #define E21_BIG_RX_STOP_PG      0xF0    /* Last page +1 of RX ring */
  94 #define E21_TX_START_PG         E21_RX_STOP_PG  /* First page of TX buffer */
  95 
  96 int e2100_probe(struct device *dev);
  97 int e21_probe1(struct device *dev, int ioaddr);
  98 
  99 static int e21_open(struct device *dev);
 100 static void e21_reset_8390(struct device *dev);
 101 static void e21_block_input(struct device *dev, int count,
 102                                                    struct sk_buff *skb, int ring_offset);
 103 static void e21_block_output(struct device *dev, int count,
 104                                                          const unsigned char *buf, const start_page);
 105 static void e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
 106                                                         int ring_page);
 107 
 108 static int e21_close(struct device *dev);
 109 
 110 
 111 /*  Probe for the E2100 series ethercards.  These cards have an 8390 at the
 112         base address and the station address at both offset 0x10 and 0x18.  I read
 113         the station address from offset 0x18 to avoid the dataport of NE2000
 114         ethercards, and look for Ctron's unique ID (first three octets of the
 115         station address).
 116  */
 117 
 118 int e2100_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         int *port;
 121         int base_addr = dev->base_addr;
 122 
 123         if (base_addr > 0x1ff)          /* Check a single specified location. */
 124                 return e21_probe1(dev, base_addr);
 125         else if (base_addr != 0)        /* Don't probe at all. */
 126                 return ENXIO;
 127 
 128         for (port = e21_probe_list; *port; port++) {
 129                 if (check_region(*port, E21_IO_EXTENT))
 130                         continue;
 131                 if (e21_probe1(dev, *port) == 0)
 132                         return 0;
 133         }
 134 
 135         return ENODEV;
 136 }
 137 
 138 int e21_probe1(struct device *dev, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140         int i, status;
 141         unsigned char *station_addr = dev->dev_addr;
 142 
 143         /* First check the station address for the Ctron prefix. */
 144         if (inb(ioaddr + E21_SAPROM + 0) != 0x00
 145                 || inb(ioaddr + E21_SAPROM + 1) != 0x00
 146                 || inb(ioaddr + E21_SAPROM + 2) != 0x1d)
 147                 return ENODEV;
 148 
 149         /* Verify by making certain that there is a 8390 at there. */
 150         outb(E8390_NODMA + E8390_STOP, ioaddr);
 151         SLOW_DOWN_IO;
 152         status = inb(ioaddr);
 153         if (status != 0x21 && status != 0x23)
 154                 return ENODEV;
 155 
 156         /* Read the station address PROM.  */
 157         for (i = 0; i < 6; i++)
 158                 station_addr[i] = inb(ioaddr + E21_SAPROM + i);
 159 
 160         inb(ioaddr + E21_MEDIA);                /* Point to media selection. */
 161         outb(0, ioaddr + E21_ASIC);     /* and disable the secondary interface. */
 162 
 163         printk("%s: E21** at %#3x,", dev->name, ioaddr);
 164         for (i = 0; i < 6; i++)
 165                 printk(" %02X", station_addr[i]);
 166 
 167         if (dev->irq < 2) {
 168                 int irqlist[] = {15,11,10,12,5,9,3,4}, i;
 169                 for (i = 0; i < 8; i++)
 170                         if (request_irq (irqlist[i], NULL, 0, "bogus") != -EBUSY) {
 171                                 dev->irq = irqlist[i];
 172                                 break;
 173                         }
 174                 if (i >= 8) {
 175                         printk(" unable to get IRQ %d.\n", dev->irq);
 176                         return EAGAIN;
 177                 }
 178         } else if (dev->irq == 2)       /* Fixup luser bogosity: IRQ2 is really IRQ9 */
 179                 dev->irq = 9;
 180 
 181         /* Grab the region so we can find a different board if IRQ select fails. */
 182         request_region(ioaddr, E21_IO_EXTENT, "e2100");
 183 
 184         /* The 8390 is at the base address. */
 185         dev->base_addr = ioaddr;
 186 
 187         ethdev_init(dev);
 188 
 189         ei_status.name = "E2100";
 190         ei_status.word16 = 1;
 191         ei_status.tx_start_page = E21_TX_START_PG;
 192         ei_status.rx_start_page = E21_RX_START_PG;
 193         ei_status.stop_page = E21_RX_STOP_PG;
 194         ei_status.saved_irq = dev->irq;
 195 
 196         /* Check the media port used.  The port can be passed in on the
 197            low mem_end bits. */
 198         if (dev->mem_end & 15)
 199                 dev->if_port = dev->mem_end & 7;
 200         else {
 201                 dev->if_port = 0;
 202                 inb(ioaddr + E21_MEDIA);        /* Turn automatic media detection on. */
 203                 for(i = 0; i < 6; i++)
 204                         if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) {
 205                                 dev->if_port = 1;
 206                                 break;
 207                         }
 208         }
 209 
 210         /* Never map in the E21 shared memory unless you are actively using it.
 211            Also, the shared memory has effective only one setting -- spread all
 212            over the 128K region! */
 213         if (dev->mem_start == 0)
 214                 dev->mem_start = 0xd0000;
 215         
 216 #ifdef notdef
 217         /* These values are unused.  The E2100 has a 2K window into the packet
 218            buffer.  The window can be set to start on any page boundary. */
 219         dev->rmem_start = dev->mem_start + TX_PAGES*256;
 220         dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
 221 #endif
 222 
 223         printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
 224                    dev->if_port ? "secondary" : "primary", dev->mem_start);
 225 
 226         if (ei_debug > 0)
 227                 printk(version);
 228 
 229         ei_status.reset_8390 = &e21_reset_8390;
 230         ei_status.block_input = &e21_block_input;
 231         ei_status.block_output = &e21_block_output;
 232         ei_status.get_8390_hdr = &e21_get_8390_hdr;
 233         dev->open = &e21_open;
 234         dev->stop = &e21_close;
 235         NS8390_init(dev, 0);
 236 
 237         return 0;
 238 }
 239 
 240 static int
 241 e21_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243         short ioaddr = dev->base_addr;
 244         int rc;
 245 
 246         if (request_irq(dev->irq, ei_interrupt, 0, "e2100")) {
 247                 return EBUSY;
 248         }
 249         irq2dev_map[dev->irq] = dev;
 250 
 251         /* Set the interrupt line and memory base on the hardware. */
 252         inb(ioaddr + E21_IRQ_LOW);
 253         outb(0, ioaddr + E21_ASIC + (dev->irq & 7));
 254         inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
 255         outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0)
 256                    + (dev->if_port ? E21_ALT_IFPORT : 0));
 257         inb(ioaddr + E21_MEM_BASE);
 258         outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7));
 259 
 260         rc = ei_open(dev);
 261         if (rc != 0) return rc;
 262         MOD_INC_USE_COUNT;
 263         return 0;
 264 }
 265 
 266 static void
 267 e21_reset_8390(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 268 {
 269         short ioaddr = dev->base_addr;
 270 
 271         outb(0x01, ioaddr);
 272         if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies);
 273         ei_status.txing = 0;
 274 
 275         /* Set up the ASIC registers, just in case something changed them. */
 276 
 277         if (ei_debug > 1) printk("reset done\n");
 278         return;
 279 }
 280 
 281 /* Grab the 8390 specific header. We put the 2k window so the header page
 282    appears at the start of the shared memory. */
 283 
 284 static void
 285 e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287 
 288         short ioaddr = dev->base_addr;
 289         char *shared_mem = (char *)dev->mem_start;
 290 
 291         mem_on(ioaddr, shared_mem, ring_page);
 292 
 293         memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
 294 
 295         /* Turn off memory access: we would need to reprogram the window anyway. */
 296         mem_off(ioaddr);
 297 
 298 }
 299 
 300 /*  Block input and output are easy on shared memory ethercards.
 301         The E21xx makes block_input() especially easy by wrapping the top
 302         ring buffer to the bottom automatically. */
 303 static void
 304 e21_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306         short ioaddr = dev->base_addr;
 307         char *shared_mem = (char *)dev->mem_start;
 308 
 309         mem_on(ioaddr, shared_mem, (ring_offset>>8));
 310 
 311         /* Packet is always in one chunk -- we can copy + cksum. */
 312         eth_io_copy_and_sum(skb, dev->mem_start + (ring_offset & 0xff), count, 0);
 313 
 314         mem_off(ioaddr);
 315 }
 316 
 317 static void
 318 e21_block_output(struct device *dev, int count, const unsigned char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 319                                  int start_page)
 320 {
 321         short ioaddr = dev->base_addr;
 322         volatile char *shared_mem = (char *)dev->mem_start;
 323 
 324         /* Set the shared memory window start by doing a read, with the low address
 325            bits specifying the starting page. */
 326         readb(shared_mem + start_page);
 327         mem_on(ioaddr, shared_mem, start_page);
 328 
 329         memcpy_toio(shared_mem, buf, count);
 330         mem_off(ioaddr);
 331 }
 332 
 333 static int
 334 e21_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336         short ioaddr = dev->base_addr;
 337 
 338         if (ei_debug > 1)
 339                 printk("%s: Shutting down ethercard.\n", dev->name);
 340 
 341     free_irq(dev->irq);
 342     dev->irq = ei_status.saved_irq;
 343 
 344         /* Shut off the interrupt line and secondary interface. */
 345         inb(ioaddr + E21_IRQ_LOW);
 346         outb(0, ioaddr + E21_ASIC);
 347         inb(ioaddr + E21_IRQ_HIGH);                     /* High IRQ bit, and if_port. */
 348         outb(0, ioaddr + E21_ASIC);
 349 
 350     irq2dev_map[dev->irq] = NULL;
 351 
 352         NS8390_init(dev, 0);
 353 
 354         /* Double-check that the memory has been turned off, because really
 355            really bad things happen if it isn't. */
 356         mem_off(ioaddr);
 357 
 358         MOD_DEC_USE_COUNT;
 359 
 360         return 0;
 361 }
 362 
 363 #ifdef HAVE_DEVLIST
 364 struct netdev_entry e21_drv =
 365 {"e21", e21_probe1, E21_IO_EXTENT, e21_probe_list};
 366 #endif
 367 
 368 #ifdef MODULE
 369 static char devicename[9] = { 0, };
 370 static struct device dev_e2100 = {
 371         devicename, /* device name is inserted by linux/drivers/net/net_init.c */
 372         0, 0, 0, 0,
 373         0, 0,
 374         0, 0, 0, NULL, e2100_probe };
 375 
 376 static int io = 0x300;
 377 static int irq = 0;
 378 
 379 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381         if (io == 0)
 382                 printk("e2100: You should not use auto-probing with insmod!\n");
 383         dev_e2100.base_addr = io;
 384         dev_e2100.irq       = irq;
 385         if (register_netdev(&dev_e2100) != 0) {
 386                 printk("e2100: register_netdev() returned non-zero.\n");
 387                 return -EIO;
 388         }
 389         return 0;
 390 }
 391 
 392 void
 393 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 394 {
 395         unregister_netdev(&dev_e2100);
 396 
 397         /* If we don't do this, we can't re-insmod it later. */
 398         release_region(dev_e2100.base_addr, E21_IO_EXTENT);
 399 }
 400 #endif /* MODULE */
 401 
 402 /*
 403  * Local variables:
 404  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c"
 405  *  version-control: t
 406  *  tab-width: 4
 407  *  kept-new-versions: 5
 408  * End:
 409  */

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