|
|
1.1 ! root 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 [email protected], 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 ([email protected])\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, ! 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) ! 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 int 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) ! 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) ! 139: { ! 140: int i, status; ! 141: unsigned char *station_addr = dev->dev_addr; ! 142: static unsigned version_printed = 0; ! 143: ! 144: /* First check the station address for the Ctron prefix. */ ! 145: if (inb(ioaddr + E21_SAPROM + 0) != 0x00 ! 146: || inb(ioaddr + E21_SAPROM + 1) != 0x00 ! 147: || inb(ioaddr + E21_SAPROM + 2) != 0x1d) ! 148: return ENODEV; ! 149: ! 150: /* Verify by making certain that there is a 8390 at there. */ ! 151: outb(E8390_NODMA + E8390_STOP, ioaddr); ! 152: SLOW_DOWN_IO; ! 153: status = inb(ioaddr); ! 154: if (status != 0x21 && status != 0x23) ! 155: return ENODEV; ! 156: ! 157: /* Read the station address PROM. */ ! 158: for (i = 0; i < 6; i++) ! 159: station_addr[i] = inb(ioaddr + E21_SAPROM + i); ! 160: ! 161: inb(ioaddr + E21_MEDIA); /* Point to media selection. */ ! 162: outb(0, ioaddr + E21_ASIC); /* and disable the secondary interface. */ ! 163: ! 164: if (ei_debug && version_printed++ == 0) ! 165: printk(version); ! 166: ! 167: /* We should have a "dev" from Space.c or the static module table. */ ! 168: if (dev == NULL) { ! 169: printk("e2100.c: Passed a NULL device.\n"); ! 170: dev = init_etherdev(0, 0); ! 171: } ! 172: ! 173: printk("%s: E21** at %#3x,", dev->name, ioaddr); ! 174: for (i = 0; i < 6; i++) ! 175: printk(" %02X", station_addr[i]); ! 176: ! 177: if (dev->irq < 2) { ! 178: int irqlist[] = {15,11,10,12,5,9,3,4}, i; ! 179: for (i = 0; i < 8; i++) ! 180: if (request_irq (irqlist[i], NULL, 0, "bogus", NULL) != -EBUSY) { ! 181: dev->irq = irqlist[i]; ! 182: break; ! 183: } ! 184: if (i >= 8) { ! 185: printk(" unable to get IRQ %d.\n", dev->irq); ! 186: return EAGAIN; ! 187: } ! 188: } else if (dev->irq == 2) /* Fixup luser bogosity: IRQ2 is really IRQ9 */ ! 189: dev->irq = 9; ! 190: ! 191: /* Allocate dev->priv and fill in 8390 specific dev fields. */ ! 192: if (ethdev_init(dev)) { ! 193: printk (" unable to get memory for dev->priv.\n"); ! 194: return -ENOMEM; ! 195: } ! 196: ! 197: /* Grab the region so we can find a different board if IRQ select fails. */ ! 198: request_region(ioaddr, E21_IO_EXTENT, "e2100"); ! 199: ! 200: /* The 8390 is at the base address. */ ! 201: dev->base_addr = ioaddr; ! 202: ! 203: ei_status.name = "E2100"; ! 204: ei_status.word16 = 1; ! 205: ei_status.tx_start_page = E21_TX_START_PG; ! 206: ei_status.rx_start_page = E21_RX_START_PG; ! 207: ei_status.stop_page = E21_RX_STOP_PG; ! 208: ei_status.saved_irq = dev->irq; ! 209: ! 210: /* Check the media port used. The port can be passed in on the ! 211: low mem_end bits. */ ! 212: if (dev->mem_end & 15) ! 213: dev->if_port = dev->mem_end & 7; ! 214: else { ! 215: dev->if_port = 0; ! 216: inb(ioaddr + E21_MEDIA); /* Turn automatic media detection on. */ ! 217: for(i = 0; i < 6; i++) ! 218: if (station_addr[i] != inb(ioaddr + E21_SAPROM + 8 + i)) { ! 219: dev->if_port = 1; ! 220: break; ! 221: } ! 222: } ! 223: ! 224: /* Never map in the E21 shared memory unless you are actively using it. ! 225: Also, the shared memory has effective only one setting -- spread all ! 226: over the 128K region! */ ! 227: if (dev->mem_start == 0) ! 228: dev->mem_start = 0xd0000; ! 229: ! 230: #ifdef notdef ! 231: /* These values are unused. The E2100 has a 2K window into the packet ! 232: buffer. The window can be set to start on any page boundary. */ ! 233: dev->rmem_start = dev->mem_start + TX_PAGES*256; ! 234: dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024; ! 235: #endif ! 236: ! 237: printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq, ! 238: dev->if_port ? "secondary" : "primary", dev->mem_start); ! 239: ! 240: ei_status.reset_8390 = &e21_reset_8390; ! 241: ei_status.block_input = &e21_block_input; ! 242: ei_status.block_output = &e21_block_output; ! 243: ei_status.get_8390_hdr = &e21_get_8390_hdr; ! 244: dev->open = &e21_open; ! 245: dev->stop = &e21_close; ! 246: NS8390_init(dev, 0); ! 247: ! 248: return 0; ! 249: } ! 250: ! 251: static int ! 252: e21_open(struct device *dev) ! 253: { ! 254: short ioaddr = dev->base_addr; ! 255: ! 256: if (request_irq(dev->irq, ei_interrupt, 0, "e2100", NULL)) { ! 257: return EBUSY; ! 258: } ! 259: irq2dev_map[dev->irq] = dev; ! 260: ! 261: /* Set the interrupt line and memory base on the hardware. */ ! 262: inb(ioaddr + E21_IRQ_LOW); ! 263: outb(0, ioaddr + E21_ASIC + (dev->irq & 7)); ! 264: inb(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */ ! 265: outb(0, ioaddr + E21_ASIC + (dev->irq > 7 ? 1:0) ! 266: + (dev->if_port ? E21_ALT_IFPORT : 0)); ! 267: inb(ioaddr + E21_MEM_BASE); ! 268: outb(0, ioaddr + E21_ASIC + ((dev->mem_start >> 17) & 7)); ! 269: ! 270: ei_open(dev); ! 271: MOD_INC_USE_COUNT; ! 272: return 0; ! 273: } ! 274: ! 275: static void ! 276: e21_reset_8390(struct device *dev) ! 277: { ! 278: short ioaddr = dev->base_addr; ! 279: ! 280: outb(0x01, ioaddr); ! 281: if (ei_debug > 1) printk("resetting the E2180x3 t=%ld...", jiffies); ! 282: ei_status.txing = 0; ! 283: ! 284: /* Set up the ASIC registers, just in case something changed them. */ ! 285: ! 286: if (ei_debug > 1) printk("reset done\n"); ! 287: return; ! 288: } ! 289: ! 290: /* Grab the 8390 specific header. We put the 2k window so the header page ! 291: appears at the start of the shared memory. */ ! 292: ! 293: static void ! 294: e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ! 295: { ! 296: ! 297: short ioaddr = dev->base_addr; ! 298: char *shared_mem = (char *)dev->mem_start; ! 299: ! 300: mem_on(ioaddr, shared_mem, ring_page); ! 301: ! 302: #ifdef notdef ! 303: /* Officially this is what we are doing, but the readl() is faster */ ! 304: memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr)); ! 305: #else ! 306: ((unsigned int*)hdr)[0] = readl(shared_mem); ! 307: #endif ! 308: ! 309: /* Turn off memory access: we would need to reprogram the window anyway. */ ! 310: mem_off(ioaddr); ! 311: ! 312: } ! 313: ! 314: /* Block input and output are easy on shared memory ethercards. ! 315: The E21xx makes block_input() especially easy by wrapping the top ! 316: ring buffer to the bottom automatically. */ ! 317: static void ! 318: e21_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) ! 319: { ! 320: short ioaddr = dev->base_addr; ! 321: char *shared_mem = (char *)dev->mem_start; ! 322: ! 323: mem_on(ioaddr, shared_mem, (ring_offset>>8)); ! 324: ! 325: /* Packet is always in one chunk -- we can copy + cksum. */ ! 326: eth_io_copy_and_sum(skb, dev->mem_start + (ring_offset & 0xff), count, 0); ! 327: ! 328: mem_off(ioaddr); ! 329: } ! 330: ! 331: static void ! 332: e21_block_output(struct device *dev, int count, const unsigned char *buf, ! 333: const int start_page) ! 334: { ! 335: short ioaddr = dev->base_addr; ! 336: volatile char *shared_mem = (char *)dev->mem_start; ! 337: ! 338: /* Set the shared memory window start by doing a read, with the low address ! 339: bits specifying the starting page. */ ! 340: readb(shared_mem + start_page); ! 341: mem_on(ioaddr, shared_mem, start_page); ! 342: ! 343: memcpy_toio(shared_mem, buf, count); ! 344: mem_off(ioaddr); ! 345: } ! 346: ! 347: static int ! 348: e21_close(struct device *dev) ! 349: { ! 350: short ioaddr = dev->base_addr; ! 351: ! 352: if (ei_debug > 1) ! 353: printk("%s: Shutting down ethercard.\n", dev->name); ! 354: ! 355: free_irq(dev->irq, NULL); ! 356: dev->irq = ei_status.saved_irq; ! 357: ! 358: /* Shut off the interrupt line and secondary interface. */ ! 359: inb(ioaddr + E21_IRQ_LOW); ! 360: outb(0, ioaddr + E21_ASIC); ! 361: inb(ioaddr + E21_IRQ_HIGH); /* High IRQ bit, and if_port. */ ! 362: outb(0, ioaddr + E21_ASIC); ! 363: ! 364: irq2dev_map[dev->irq] = NULL; ! 365: ! 366: ei_close(dev); ! 367: ! 368: /* Double-check that the memory has been turned off, because really ! 369: really bad things happen if it isn't. */ ! 370: mem_off(ioaddr); ! 371: ! 372: MOD_DEC_USE_COUNT; ! 373: ! 374: return 0; ! 375: } ! 376: ! 377: #ifdef HAVE_DEVLIST ! 378: struct netdev_entry e21_drv = ! 379: {"e21", e21_probe1, E21_IO_EXTENT, e21_probe_list}; ! 380: #endif ! 381: ! 382: ! 383: #ifdef MODULE ! 384: #define MAX_E21_CARDS 4 /* Max number of E21 cards per module */ ! 385: #define NAMELEN 8 /* # of chars for storing dev->name */ ! 386: static char namelist[NAMELEN * MAX_E21_CARDS] = { 0, }; ! 387: static struct device dev_e21[MAX_E21_CARDS] = { ! 388: { ! 389: NULL, /* assign a chunk of namelist[] below */ ! 390: 0, 0, 0, 0, ! 391: 0, 0, ! 392: 0, 0, 0, NULL, NULL ! 393: }, ! 394: }; ! 395: ! 396: static int io[MAX_E21_CARDS] = { 0, }; ! 397: static int irq[MAX_E21_CARDS] = { 0, }; ! 398: static int mem[MAX_E21_CARDS] = { 0, }; ! 399: static int xcvr[MAX_E21_CARDS] = { 0, }; /* choose int. or ext. xcvr */ ! 400: ! 401: /* This is set up so that only a single autoprobe takes place per call. ! 402: ISA device autoprobes on a running machine are not recommended. */ ! 403: int ! 404: init_module(void) ! 405: { ! 406: int this_dev, found = 0; ! 407: ! 408: for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { ! 409: struct device *dev = &dev_e21[this_dev]; ! 410: dev->name = namelist+(NAMELEN*this_dev); ! 411: dev->irq = irq[this_dev]; ! 412: dev->base_addr = io[this_dev]; ! 413: dev->mem_start = mem[this_dev]; ! 414: dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */ ! 415: dev->init = e2100_probe; ! 416: if (io[this_dev] == 0) { ! 417: if (this_dev != 0) break; /* only autoprobe 1st one */ ! 418: printk(KERN_NOTICE "e2100.c: Presently autoprobing (not recommended) for a single card.\n"); ! 419: } ! 420: if (register_netdev(dev) != 0) { ! 421: printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]); ! 422: if (found != 0) return 0; /* Got at least one. */ ! 423: return -ENXIO; ! 424: } ! 425: found++; ! 426: } ! 427: ! 428: return 0; ! 429: } ! 430: ! 431: void ! 432: cleanup_module(void) ! 433: { ! 434: int this_dev; ! 435: ! 436: for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) { ! 437: struct device *dev = &dev_e21[this_dev]; ! 438: if (dev->priv != NULL) { ! 439: /* NB: e21_close() handles free_irq + irq2dev map */ ! 440: kfree(dev->priv); ! 441: dev->priv = NULL; ! 442: release_region(dev->base_addr, E21_IO_EXTENT); ! 443: unregister_netdev(dev); ! 444: } ! 445: } ! 446: } ! 447: #endif /* MODULE */ ! 448: ! 449: /* ! 450: * Local variables: ! 451: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c e2100.c" ! 452: * version-control: t ! 453: * tab-width: 4 ! 454: * kept-new-versions: 5 ! 455: * End: ! 456: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.