root/drivers/net/3c501.c

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

DEFINITIONS

This source file includes following definitions.
  1. el1_probe
  2. el_open
  3. el_start_xmit
  4. el_interrupt
  5. el_receive
  6. el_reset
  7. el1_close
  8. el1_get_stats
  9. set_multicast_list

   1 /* 3c501.c: A 3Com 3c501 ethernet driver for linux. */
   2 /*
   3     Copyright (C) 1992,1993  Donald Becker
   4 
   5     This is alpha test code.  No redistribution is permitted.
   6 
   7     If this code is distributed, it will carry the following:
   8     Copyright 1993 United States Government as represented by the
   9     Director, National Security Agency.  This software may be used and
  10     distributed according to the terms of the GNU Public License,
  11     incorporated herein by reference.
  12 
  13     This is a device driver for the 3Com Etherlink 3c501.
  14     Do not purchase this card, even as a joke.  It's performance is horrible,
  15     and it breaks in many ways.  
  16 
  17     The Author may be reached as becker@super.org or
  18     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
  19     I'll only accept bug fixes, not reports, for the 3c501 driver.
  20 */
  21 
  22 static char *version =
  23     "3c501.c:v13.13 1993 Donald Becker (becker@super.org).\n";
  24 
  25 /*
  26   Braindamage remaining:
  27   The 3c501 board.
  28   */
  29 
  30 #include <linux/config.h>
  31 #include <linux/kernel.h>
  32 #include <linux/sched.h>
  33 #include <linux/ptrace.h>
  34 #include <linux/fcntl.h>
  35 #include <linux/ioport.h>
  36 #include <linux/interrupt.h>
  37 #include <linux/malloc.h>
  38 #include <linux/ioport.h>
  39 #include <asm/bitops.h>
  40 #include <asm/io.h>
  41 #include <errno.h>
  42 
  43 #include "dev.h"
  44 #include "iow.h"
  45 #include "eth.h"
  46 #include "skbuff.h"
  47 #include "arp.h"
  48 
  49 #ifndef HAVE_AUTOIRQ
  50 /* From auto_irq.c, should be in a *.h file. */
  51 extern void autoirq_setup(int waittime);
  52 extern int autoirq_report(int waittime);
  53 extern struct device *irq2dev_map[16];
  54 #endif
  55 
  56 #ifndef HAVE_ALLOC_SKB
  57 #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
  58 #define kfree_skbmem(addr, size) kfree_s(addr,size);
  59 #endif
  60 
  61 
  62 /* Index to functions. */
  63 int el1_probe(struct device *dev);
  64 static int  el_open(struct device *dev);
  65 static int  el_start_xmit(struct sk_buff *skb, struct device *dev);
  66 static void el_interrupt(int reg_ptr);
  67 static void el_receive(struct device *dev);
  68 static void el_reset(struct device *dev);
  69 static int  el1_close(struct device *dev);
  70 static struct enet_statistics *el1_get_stats(struct device *dev);
  71 #ifdef HAVE_MULTICAST
  72 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
  73 #endif
  74 
  75 #define EL_NAME "EtherLink 3c501"
  76 
  77 #ifndef EL_DEBUG
  78 #define EL_DEBUG  2     /* use 0 for production, 1 for devel., >2 for debug */
  79 #endif                  /* Anything above 5 is wordy death! */
  80 static int el_debug = EL_DEBUG;
  81 static int el_base;
  82 static struct device *eldev;    /* Only for consistency checking.  */
  83  
  84 /* We could easily have this struct kmalloc()ed per-board, but
  85    who would want more than one 3c501?. */
  86 static struct {
  87     struct enet_statistics stats;
  88     int tx_pkt_start;           /* The length of the current Tx packet. */
  89     int collisions;             /* Tx collisions this packet */
  90 } el_status;                    /* This should be stored per-board */
  91 
  92 
  93 #define RX_STATUS (el_base + 0x06)
  94 #define RX_CMD    RX_STATUS
  95 #define TX_STATUS (el_base + 0x07)
  96 #define TX_CMD    TX_STATUS
  97 #define GP_LOW    (el_base + 0x08)
  98 #define GP_HIGH   (el_base + 0x09)
  99 #define RX_BUF_CLR (el_base + 0x0A)
 100 #define RX_LOW    (el_base + 0x0A)
 101 #define RX_HIGH   (el_base + 0x0B)
 102 #define SAPROM    (el_base + 0x0C)
 103 #define AX_STATUS (el_base + 0x0E)
 104 #define AX_CMD    AX_STATUS
 105 #define DATAPORT  (el_base + 0x0F)
 106 #define TX_RDY 0x08             /* In TX_STATUS */
 107 
 108 #define EL1_DATAPTR     0x08
 109 #define EL1_RXPTR       0x0A
 110 #define EL1_SAPROM      0x0C
 111 #define EL1_DATAPORT    0x0f
 112 
 113 /* Writes to the ax command register. */
 114 #define AX_OFF  0x00                    /* Irq off, buffer access on */
 115 #define AX_SYS  0x40                    /* Load the buffer */
 116 #define AX_XMIT 0x44                    /* Transmit a packet */
 117 #define AX_RX   0x48                    /* Receive a packet */
 118 #define AX_LOOP 0x0C                    /* Loopback mode */
 119 #define AX_RESET 0x80
 120 
 121 /* Normal receive mode written to RX_STATUS.  We must intr on short packets
 122    to avoid bogus rx lockups. */
 123 #define RX_NORM 0xA8            /* 0x68 == all addrs, 0xA8 only to me. */
 124 #define RX_PROM 0x68            /* Senior Prom, uhmm promiscuous mode. */
 125 #define RX_MULT 0xE8            /* Accept multicast packets. */
 126 #define TX_NORM 0x0A    /* Interrupt on everything that might hang the chip */
 127 
 128 /* TX_STATUS register. */
 129 #define TX_COLLISION 0x02
 130 #define TX_16COLLISIONS 0x04
 131 #define TX_READY 0x08
 132 
 133 #define RX_RUNT 0x08
 134 #define RX_MISSED 0x01          /* Missed a packet due to 3c501 braindamage. */
 135 #define RX_GOOD 0x30            /* Good packet 0x20, or simple overflow 0x10. */
 136 
 137 
 138 int
 139 el1_probe(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141     int i;
 142     int ioaddr;
 143     unsigned char station_addr[6];
 144     int autoirq = 0;
 145 
 146     eldev = dev;                /* Store for debugging. */
 147     el_base = dev->base_addr;
 148 
 149     if (el_base < 0x40)         /* Invalid?  Probe for it. */
 150         el_base = 0x280;
 151 
 152     ioaddr = el_base;
 153 
 154     /* Read the station address PROM data from the special port.  */
 155     for (i = 0; i < 6; i++) {
 156         outw(i, ioaddr + EL1_DATAPTR);
 157         station_addr[i] = inb(ioaddr + EL1_SAPROM);
 158     }
 159     /* Check the first three octets of the S.A. for 3Com's code. */ 
 160     if (station_addr[0] != 0x02  ||  station_addr[1] != 0x60
 161         || station_addr[2] != 0x8c) {
 162         return ENODEV;
 163     }
 164 
 165 #ifdef HAVE_PORTRESERVE
 166     /* Grab the region so we can find the another board if autoIRQ fails. */
 167     snarf_region(ioaddr, 16);
 168 #endif
 169 
 170     /* We auto-IRQ by shutting off the interrupt line and letting it float
 171        high. */
 172     if (dev->irq < 2) {
 173 
 174         autoirq_setup(2);
 175 
 176         inb(RX_STATUS);         /* Clear pending interrupts. */
 177         inb(TX_STATUS);
 178         outb(AX_LOOP + 1, AX_CMD);
 179 
 180         outb(0x00, AX_CMD);
 181 
 182         autoirq = autoirq_report(1);
 183 
 184         if (autoirq == 0) {
 185             printk("%s: 3c501 probe failed to detect IRQ line.\n", dev->name);
 186             return EAGAIN;
 187         }
 188         dev->irq = autoirq;
 189     }
 190 
 191     outb(AX_RESET+AX_LOOP, AX_CMD);                     /* Loopback mode. */
 192 
 193     dev->base_addr = el_base;
 194     memcpy(dev->dev_addr, station_addr, ETH_ALEN);
 195     if (dev->mem_start & 0xf)
 196         el_debug = dev->mem_start & 0x7;
 197 
 198     printk("%s: 3c501 EtherLink at %#x, using %sIRQ %d, melting ethernet.\n",
 199            dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq);
 200 
 201     if (el_debug)
 202         printk("%s", version);
 203 
 204     /* The EL1-specific entries in the device structure. */
 205     dev->open = &el_open;
 206     dev->hard_start_xmit = &el_start_xmit;
 207     dev->stop = &el1_close;
 208     dev->get_stats = &el1_get_stats;
 209 #ifdef HAVE_MULTICAST
 210     dev->set_multicast_list = &set_multicast_list;
 211 #endif
 212 
 213     /* Fill in the generic field of the device structure. */
 214     for (i = 0; i < DEV_NUMBUFFS; i++)
 215         dev->buffs[i] = NULL;
 216 
 217     dev->hard_header    = eth_header;
 218     dev->add_arp        = eth_add_arp;
 219     dev->queue_xmit     = dev_queue_xmit;
 220     dev->rebuild_header = eth_rebuild_header;
 221     dev->type_trans     = eth_type_trans;
 222 
 223     dev->type           = ARPHRD_ETHER;
 224     dev->hard_header_len = ETH_HLEN;
 225     dev->mtu            = 1500; /* eth_mtu */
 226     dev->addr_len       = ETH_ALEN;
 227     for (i = 0; i < ETH_ALEN; i++) {
 228         dev->broadcast[i]=0xff;
 229     }
 230 
 231     /* New-style flags. */
 232     dev->flags          = IFF_BROADCAST;
 233     dev->family         = AF_INET;
 234     dev->pa_addr        = 0;
 235     dev->pa_brdaddr     = 0;
 236     dev->pa_mask        = 0;
 237     dev->pa_alen        = sizeof(unsigned long);
 238 
 239     return 0;
 240 }
 241 
 242 /* Open/initialize the board. */
 243 static int
 244 el_open(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246 
 247   if (el_debug > 2)
 248       printk("%s: Doing el_open()...", dev->name);
 249 
 250   if (request_irq(dev->irq, &el_interrupt)) {
 251       if (el_debug > 2)
 252           printk("interrupt busy, exiting el_open().\n");
 253       return -EAGAIN;
 254   }
 255   irq2dev_map[dev->irq] = dev;
 256 
 257   el_reset(dev);
 258 
 259   dev->start = 1;
 260 
 261   outb(AX_RX, AX_CMD);  /* Aux control, irq and receive enabled */
 262   if (el_debug > 2)
 263      printk("finished el_open().\n");
 264   return (0);
 265 }
 266 
 267 static int
 268 el_start_xmit(struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270 
 271     if (dev->tbusy) {
 272         if (jiffies - dev->trans_start < 20) {
 273             if (el_debug > 2)
 274                 printk(" transmitter busy, deferred.\n");
 275             return 1;
 276         }
 277         if (el_debug)
 278             printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
 279                     dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
 280         el_status.stats.tx_errors++;
 281 #ifdef oldway
 282         el_reset(dev);
 283 #else
 284         outb(TX_NORM, TX_CMD);
 285         outb(RX_NORM, RX_CMD);
 286         outb(AX_OFF, AX_CMD);   /* Just trigger a false interrupt. */
 287 #endif
 288         outb(AX_RX, AX_CMD);    /* Aux control, irq and receive enabled */
 289         dev->tbusy = 0;
 290         dev->trans_start = jiffies;
 291     }
 292 
 293     if (skb == NULL) {
 294         dev_tint(dev);
 295         return 0;
 296     }
 297 
 298     /* Fill in the ethernet header. */
 299     if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
 300         skb->dev = dev;
 301         arp_queue (skb);
 302         return 0;
 303     }
 304     skb->arp=1;
 305 
 306     if (skb->len <= 0)
 307         return 0;
 308 
 309     if (el_debug > 2)
 310         printk("%s: el_start_xmit(%d)...", dev->name, skb->len);
 311 
 312     /* Avoid timer-based retransmission conflicts. */
 313     if (set_bit(0, (void*)&dev->tbusy) != 0)
 314         printk("%s: Transmitter access conflict.\n", dev->name);
 315     else {
 316         int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
 317         unsigned char *buf = (void *)(skb+1);
 318 
 319         el_status.tx_pkt_start = gp_start;
 320         el_status.collisions = 0;
 321 
 322         outb(AX_SYS, AX_CMD);
 323         inb(RX_STATUS);
 324         inb(TX_STATUS);
 325         outb(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
 326         outw(gp_start, GP_LOW);
 327         port_write_b(DATAPORT,buf,skb->len);
 328         outw(gp_start, GP_LOW);
 329         outb(AX_XMIT, AX_CMD);          /* Trigger xmit.  */
 330         dev->trans_start = jiffies;
 331     }
 332 
 333     if (el_debug > 2)
 334         printk(" queued xmit.\n");
 335     if (skb->free)
 336         kfree_skb (skb, FREE_WRITE);
 337     return 0;
 338 }
 339 
 340 
 341 /* The typical workload of the driver:
 342    Handle the ether interface interrupts. */
 343 static void
 344 el_interrupt(int reg_ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346     int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
 347     /*struct device *dev = (struct device *)(irq2dev_map[irq]);*/
 348     struct device *dev = eldev;
 349     int axsr;                   /* Aux. status reg. */
 350     short ioaddr;
 351 
 352     if (eldev->irq != irq) {
 353         printk (EL_NAME ": irq %d for unknown device\n", irq);
 354         return;
 355     }
 356 
 357     ioaddr = dev->base_addr;
 358 
 359     axsr = inb(AX_STATUS);
 360 
 361     if (el_debug > 3)
 362       printk("%s: el_interrupt() aux=%#02x", dev->name, axsr);
 363     if (dev->interrupt)
 364         printk("%s: Reentering the interrupt driver!\n", dev->name);
 365     dev->interrupt = 1;
 366 
 367     if (dev->tbusy) {
 368         int txsr = inb(TX_STATUS);
 369 
 370         if (el_debug > 6)
 371             printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),
 372                    inw(RX_LOW));
 373 
 374         if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
 375             printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
 376                    " gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
 377                    inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));
 378             dev->tbusy = 0;
 379             mark_bh(INET_BH);
 380         } else if (txsr & TX_16COLLISIONS) {
 381             if (el_debug)
 382                 printk("%s: Transmit failed 16 times, ethernet jammed?\n",
 383                        dev->name);
 384             outb(AX_SYS, AX_CMD);
 385             el_status.stats.tx_aborted_errors++;
 386         } else if (txsr & TX_COLLISION) {       /* Retrigger xmit. */
 387             if (el_debug > 6)
 388                 printk(" retransmitting after a collision.\n");
 389             outb(AX_SYS, AX_CMD);
 390             outw(el_status.tx_pkt_start, GP_LOW);
 391             outb(AX_XMIT, AX_CMD);
 392             el_status.stats.collisions++;
 393             dev->interrupt = 0;
 394             return;
 395         } else {
 396             el_status.stats.tx_packets++;
 397             if (el_debug > 6)
 398                 printk(" Tx succeeded %s\n",
 399                        (txsr & TX_RDY) ? "." : "but tx is busy!");
 400             dev->tbusy = 0;
 401             mark_bh(INET_BH);
 402         }
 403     } else {
 404         int rxsr = inb(RX_STATUS);
 405         if (el_debug > 5)
 406             printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),
 407                    inw(RX_LOW));
 408 
 409         /* Just reading rx_status fixes most errors. */
 410         if (rxsr & RX_MISSED)
 411             el_status.stats.rx_missed_errors++;
 412         if (rxsr & RX_RUNT) {   /* Handled to avoid board lock-up. */
 413             el_status.stats.rx_length_errors++;
 414             if (el_debug > 5) printk(" runt.\n");
 415         } else if (rxsr & RX_GOOD) {
 416             el_receive(eldev);
 417         } else {                        /* Nothing?  Something is broken! */
 418             if (el_debug > 2)
 419                 printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
 420                        dev->name, rxsr);
 421             el_reset(eldev);
 422         }
 423         if (el_debug > 3)
 424             printk(".\n");
 425     }
 426 
 427     outb(AX_RX, AX_CMD);
 428     outb(0x00, RX_BUF_CLR);
 429     inb(RX_STATUS);             /* Be certain that interrupts are cleared. */
 430     inb(TX_STATUS);
 431     dev->interrupt = 0;
 432     return;
 433 }
 434 
 435 
 436 /* We have a good packet. Well, not really "good", just mostly not broken.
 437    We must check everything to see if it is good. */
 438 static void
 439 el_receive(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441     int sksize, pkt_len;
 442     struct sk_buff *skb;
 443 
 444     pkt_len = inw(RX_LOW);
 445 
 446     if (el_debug > 4)
 447       printk(" el_receive %d.\n", pkt_len);
 448 
 449     if ((pkt_len < 60)  ||  (pkt_len > 1536)) {
 450         if (el_debug)
 451           printk("%s: bogus packet, length=%d\n", dev->name, pkt_len);
 452         el_status.stats.rx_over_errors++;
 453         return;
 454     }
 455     outb(AX_SYS, AX_CMD);
 456 
 457     sksize = sizeof(struct sk_buff) + pkt_len;
 458     skb = alloc_skb(sksize, GFP_ATOMIC);
 459     outw(0x00, GP_LOW);
 460     if (skb == NULL) {
 461         printk("%s: Memory squeeze, dropping packet.\n", dev->name);
 462         el_status.stats.rx_dropped++;
 463         return;
 464     } else {
 465         skb->mem_len = sksize;
 466         skb->mem_addr = skb;
 467         skb->len = pkt_len;
 468         skb->dev = dev;
 469 
 470         port_read_b(DATAPORT, (void *)(skb+1), pkt_len);
 471 
 472 #ifdef HAVE_NETIF_RX
 473             netif_rx(skb);
 474 #else
 475             skb->lock = 0;
 476             if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
 477                 kfree_skbmem(skb, sksize);
 478                 lp->stats.rx_dropped++;
 479                 break;
 480             }
 481 #endif
 482         el_status.stats.rx_packets++;
 483     }
 484     return;
 485 }
 486 
 487 static void 
 488 el_reset(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490     if (el_debug> 2)
 491         printk("3c501 reset...");
 492     outb(AX_RESET, AX_CMD);     /* Reset the chip */
 493     outb(AX_LOOP, AX_CMD);      /* Aux control, irq and loopback enabled */
 494     {
 495         int i;
 496         for (i = 0; i < 6; i++) /* Set the station address. */
 497             outb(dev->dev_addr[i], el_base + i);
 498     }
 499     
 500     outb(0, RX_BUF_CLR);                /* Set rx packet area to 0. */
 501     cli();                      /* Avoid glitch on writes to CMD regs */
 502     outb(TX_NORM, TX_CMD);              /* tx irq on done, collision */
 503     outb(RX_NORM, RX_CMD);      /* Set Rx commands. */
 504     inb(RX_STATUS);             /* Clear status. */
 505     inb(TX_STATUS);
 506     dev->interrupt = 0;
 507     dev->tbusy = 0;
 508     sti();
 509 }
 510 
 511 static int
 512 el1_close(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 513 {
 514     int ioaddr = dev->base_addr;
 515 
 516     if (el_debug > 2)
 517         printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr);
 518 
 519     dev->tbusy = 1;
 520     dev->start = 0;
 521 
 522     /* Free and disable the IRQ. */
 523     free_irq(dev->irq);
 524     outb(AX_RESET, AX_CMD);     /* Reset the chip */
 525     irq2dev_map[dev->irq] = 0;
 526 
 527     return 0;
 528 }
 529 
 530 static struct enet_statistics *
 531 el1_get_stats(struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533     return &el_status.stats;
 534 }
 535 
 536 #ifdef HAVE_MULTICAST
 537 /* Set or clear the multicast filter for this adaptor.
 538    num_addrs == -1      Promiscuous mode, receive all packets
 539    num_addrs == 0       Normal mode, clear multicast list
 540    num_addrs > 0        Multicast mode, receive normal and MC packets, and do
 541                         best-effort filtering.
 542  */
 543 static void
 544 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
     /* [previous][next][first][last][top][bottom][index][help] */
 545 {
 546     if (num_addrs > 0) {
 547         outb(RX_MULT, RX_CMD);
 548         inb(RX_STATUS);         /* Clear status. */
 549     } else if (num_addrs < 0) {
 550         outb(RX_PROM, RX_CMD);
 551         inb(RX_STATUS);
 552     } else {
 553         outb(RX_NORM, RX_CMD);
 554         inb(RX_STATUS);
 555     }
 556 }
 557 #endif
 558 
 559 /*
 560  * Local variables:
 561  *  compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer  -m486 -c -o 3c501.o 3c501.c"
 562  *  kept-new-versions: 5
 563  * End:
 564  */

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