The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/dpeth/3c501.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2 **  File:       3c501.c         Jan. 14, 1997
    3 **
    4 **  Author:     Giovanni Falzoni <gfalzoni@inwind.it>
    5 **
    6 **  This file contains specific implementation of the ethernet
    7 **  device driver for 3Com Etherlink (3c501) boards.  This is a
    8 **  very old board and its performances are very poor for today
    9 **  network environments.
   10 **
   11 **  $Id: 3c501.c,v 1.3 2005/08/05 19:08:43 beng Exp $
   12 */
   13 
   14 #include "drivers.h"
   15 #include <minix/com.h>
   16 #include <net/hton.h>
   17 #include <net/gen/ether.h>
   18 #include <net/gen/eth_io.h>
   19 #include "dp.h"
   20 
   21 #if (ENABLE_3C501 == 1)
   22 
   23 #include "3c501.h"
   24 
   25 static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,};
   26 static buff_t *TxBuff = NULL;
   27 
   28 /*
   29 **  Name:       void el1_getstats(dpeth_t *dep)
   30 **  Function:   Reads statistics counters from board.
   31 **/
   32 static void el1_getstats(dpeth_t * dep)
   33 {
   34 
   35   return;                       /* Nothing to do */
   36 }
   37 
   38 /*
   39 **  Name:       void el1_reset(dpeth_t *dep)
   40 **  Function:   Reset function specific for Etherlink hardware.
   41 */
   42 static void el1_reset(dpeth_t * dep)
   43 {
   44   int ix;
   45 
   46   for (ix = 0; ix < 8; ix += 1) /* Resets the board */
   47         outb_el1(dep, EL1_CSR, ECSR_RESET);
   48   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
   49 
   50   /* Set Ethernet Address on controller */
   51   outb_el1(dep, EL1_CSR, ECSR_LOOP);    /* Loopback mode */
   52   for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1)
   53         outb_el1(dep, ix, StationAddress[ix]);
   54 
   55   lock();
   56   /* Enable DMA/Interrupt, gain control of Buffer */
   57   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
   58   /* Clear RX packet area */
   59   outw_el1(dep, EL1_RECVPTR, 0);
   60   /* Enable transmit/receive configuration and flush pending interrupts */
   61   outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER);
   62   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
   63   inb_el1(dep, EL1_RECV);
   64   inb_el1(dep, EL1_XMIT);
   65   dep->de_flags &= NOT(DEF_XMIT_BUSY);
   66   unlock();
   67   return;                       /* Done */
   68 }
   69 
   70 /*
   71 **  Name:       void el1_dumpstats(dpeth_t *dep, int port, vir_bytes size)
   72 **  Function:   Dumps counter on screen (support for console display).
   73 */
   74 static void el1_dumpstats(dpeth_t * dep)
   75 {
   76 
   77   return;
   78 }
   79 
   80 /*
   81 **  Name:       void el1_mode_init(dpeth_t *dep)
   82 **  Function:   Initializes receicer mode
   83 */
   84 static void el1_mode_init(dpeth_t * dep)
   85 {
   86 
   87   if (dep->de_flags & DEF_BROAD) {
   88         dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK;
   89 
   90   } else if (dep->de_flags & DEF_PROMISC) {
   91         dep->de_recv_mode = ERSR_ALL | ERSR_RMASK;
   92 
   93   } else if (dep->de_flags & DEF_MULTI) {
   94         dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK;
   95 
   96   } else {
   97         dep->de_recv_mode = ERSR_NONE | ERSR_RMASK;
   98   }
   99   outb_el1(dep, EL1_RECV, dep->de_recv_mode);
  100   inb_el1(dep, EL1_RECV);
  101   return;
  102 }
  103 
  104 /*
  105 **  Name:       void el1_recv(dpeth_t *dep, int from, int size)
  106 **  Function:   Receive function.  Called from interrupt handler to
  107 **              unload recv. buffer or from main (packet to client)
  108 */
  109 static void el1_recv(dpeth_t * dep, int from, int size)
  110 {
  111   buff_t *rxptr;
  112 
  113   while ((dep->de_flags & DEF_READING) && (rxptr = dep->de_recvq_head)) {
  114 
  115         /* Remove buffer from queue and free buffer */
  116         lock();
  117         if (dep->de_recvq_tail == dep->de_recvq_head)
  118                 dep->de_recvq_head = dep->de_recvq_tail = NULL;
  119         else
  120                 dep->de_recvq_head = rxptr->next;
  121         unlock();
  122 
  123         /* Copy buffer to user area */
  124         mem2user(dep, rxptr);
  125 
  126         /* Reply information */
  127         dep->de_read_s = rxptr->size;
  128         dep->de_flags |= DEF_ACK_RECV;
  129         dep->de_flags &= NOT(DEF_READING);
  130 
  131         /* Return buffer to the idle pool */
  132         free_buff(dep, rxptr);
  133   }
  134   return;
  135 }
  136 
  137 /*
  138 **  Name:       void el1_send(dpeth_t *dep, int from_int, int pktsize)
  139 **  Function:   Send function.  Called from main to transit a packet or
  140 **              from interrupt handler when a new packet was queued.
  141 */
  142 static void el1_send(dpeth_t * dep, int from_int, int pktsize)
  143 {
  144   buff_t *txbuff;
  145   clock_t now;
  146 
  147   if (from_int == FALSE) {
  148 
  149         if ((txbuff = alloc_buff(dep, pktsize + sizeof(buff_t))) != NULL) {
  150 
  151                 /*  Fill transmit buffer from user area */
  152                 txbuff->next = NULL;
  153                 txbuff->size = pktsize;
  154                 txbuff->client = dep->de_client;
  155                 user2mem(dep, txbuff);
  156         } else
  157                 panic(dep->de_name, "out of memory for Tx", NO_NUM);
  158 
  159   } else if ((txbuff = dep->de_xmitq_head) != NULL) {
  160 
  161         /* Get first packet in queue */
  162         lock();
  163         if (dep->de_xmitq_tail == dep->de_xmitq_head)
  164                 dep->de_xmitq_head = dep->de_xmitq_tail = NULL;
  165         else
  166                 dep->de_xmitq_head = txbuff->next;
  167         unlock();
  168         pktsize = txbuff->size;
  169 
  170   } else
  171         panic(dep->de_name, "should not be sending ", NO_NUM);
  172 
  173   if ((dep->de_flags & DEF_XMIT_BUSY)) {
  174         if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
  175         getuptime(&now);
  176         if ((now - dep->de_xmit_start) > 4) {
  177                 /* Transmitter timed out */
  178                 DEBUG(printf("3c501: transmitter timed out ... \n"));
  179                 dep->de_stat.ets_sendErr += 1;
  180                 dep->de_flags &= NOT(DEF_XMIT_BUSY);
  181                 el1_reset(dep);
  182         }
  183 
  184         /* Queue packet */
  185         lock();                 /* Queue packet to receive queue */
  186         if (dep->de_xmitq_head == NULL)
  187                 dep->de_xmitq_head = txbuff;
  188         else
  189                 dep->de_xmitq_tail->next = txbuff;
  190         dep->de_xmitq_tail = txbuff;
  191         unlock();
  192   } else {
  193         /* Save for retransmission */
  194         TxBuff = txbuff;
  195         dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
  196 
  197         /* Setup board for packet loading */
  198         lock();                 /* Buffer to processor */
  199         outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
  200         inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */
  201         inb_el1(dep, EL1_XMIT);
  202         outw_el1(dep, EL1_RECVPTR, 0);  /* Clears RX packet area */
  203 
  204         /* Loads packet */
  205         outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
  206         outsb(dep->de_data_port, SELF, txbuff->buffer, pktsize);
  207         /* Starts transmitter */
  208         outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - pktsize));
  209         outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);  /* There it goes... */
  210         unlock();
  211 
  212         getuptime(&dep->de_xmit_start);
  213         dep->de_flags &= NOT(DEF_SENDING);
  214   }
  215   return;
  216 }
  217 
  218 /*
  219 **  Name:       void el1_stop(dpeth_t *dep)
  220 **  Function:   Stops board and disable interrupts.
  221 */
  222 static void el1_stop(dpeth_t * dep)
  223 {
  224   int ix;
  225 
  226   DEBUG(printf("%s: stopping Etherlink ....\n", dep->de_name));
  227   for (ix = 0; ix < 8; ix += 1) /* Reset board */
  228         outb_el1(dep, EL1_CSR, ECSR_RESET);
  229   outb_el1(dep, EL1_CSR, ECSR_SYS);
  230   sys_irqdisable(&dep->de_hook);        /* Disable interrupt */
  231   return;
  232 }
  233 
  234 /*
  235 **  Name:       void el1_interrupt(dpeth_t *dep)
  236 **  Function:   Interrupt handler.  Acknwledges transmit interrupts
  237 **              or unloads receive buffer to memory queue.
  238 */
  239 static void el1_interrupt(dpeth_t * dep)
  240 {
  241   u16_t csr, isr;
  242   int pktsize;
  243   buff_t *rxptr;
  244 
  245   csr = inb_el1(dep, EL1_CSR);
  246   if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) {
  247 
  248         /* Got a transmit interrupt */
  249         isr = inb_el1(dep, EL1_XMIT);
  250         if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) {
  251         DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr));
  252                 if (isr & EXSR_JAM) {
  253                         /* Sending, packet got a collision */
  254                         dep->de_stat.ets_collision += 1;
  255                         /* Put pointer back to beginning of packet */
  256                         outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
  257                         outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size));
  258                         /* And retrigger transmission */
  259                         outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT);
  260                         return;
  261 
  262                 } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) {
  263                         dep->de_stat.ets_sendErr += 1;
  264 
  265                 } else if (isr & EXSR_UNDER) {
  266                         dep->de_stat.ets_fifoUnder += 1;
  267                 }
  268                 DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr));
  269                 el1_reset(dep);
  270 
  271         } else {
  272                 /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/
  273                 /* Packet transmitted successfully */
  274                 dep->de_stat.ets_packetT += 1;
  275                 dep->bytes_Tx += (long) (TxBuff->size);
  276                 free_buff(dep, TxBuff);
  277                 dep->de_flags &= NOT(DEF_XMIT_BUSY);
  278                 if ((dep->de_flags & DEF_SENDING) && dep->de_xmitq_head) {
  279                         /* Pending transmit request available in queue */
  280                         el1_send(dep, TRUE, 0);
  281                         if (dep->de_flags & (DEF_XMIT_BUSY | DEF_ACK_SEND))
  282                                 return;
  283                 }
  284         }
  285 
  286   } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) {
  287 
  288         /* Got a receive interrupt */
  289         isr = inb_el1(dep, EL1_RECV);
  290         pktsize = inw_el1(dep, EL1_RECVPTR);
  291         if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) {
  292         DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
  293                 dep->de_stat.ets_recvErr += 1;
  294 
  295         } else if (pktsize < ETH_MIN_PACK_SIZE || pktsize > ETH_MAX_PACK_SIZE) {
  296         DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", csr, isr, pktsize));
  297                 dep->de_stat.ets_recvErr += 1;
  298 
  299         } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) {
  300                 /* Memory not available. Drop packet */
  301                 dep->de_stat.ets_fifoOver += 1;
  302 
  303         } else if (isr & (ERSR_GOOD | ERSR_ANY)) {
  304                 /* Got a good packet. Read it from buffer */
  305                 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS);
  306                 outw_el1(dep, EL1_XMITPTR, 0);
  307                 insb(dep->de_data_port, SELF, rxptr->buffer, pktsize);
  308                 rxptr->next = NULL;
  309                 rxptr->size = pktsize;
  310                 dep->de_stat.ets_packetR += 1;
  311                 dep->bytes_Rx += (long) pktsize;
  312                 lock();         /* Queue packet to receive queue */
  313                 if (dep->de_recvq_head == NULL)
  314                         dep->de_recvq_head = rxptr;
  315                 else
  316                         dep->de_recvq_tail->next = rxptr;
  317                 dep->de_recvq_tail = rxptr;
  318                 unlock();
  319 
  320                 /* Reply to pending Receive requests, if any */
  321                 el1_recv(dep, TRUE, 0);
  322         }
  323   } else {                      /* Nasty condition, should never happen */
  324         DEBUG(
  325               printf("3c501: got interrupt with status 0x%02X\n"
  326                      "       de_flags=0x%04X  XSR=0x%02X RSR=0x%02X \n"
  327                      "       xmit buffer = 0x%4X recv buffer = 0x%4X\n",
  328                         csr, dep->de_flags,
  329                         inb_el1(dep, EL1_RECV),
  330                         inb_el1(dep, EL1_XMIT),
  331                         inw_el1(dep, EL1_XMITPTR),
  332                         inw_el1(dep, EL1_RECVPTR))
  333                 );
  334         el1_reset(dep);
  335   }
  336 
  337   /* Move into receive mode */
  338   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
  339   outw_el1(dep, EL1_RECVPTR, 0);
  340   /* Be sure that interrupts are cleared */
  341   inb_el1(dep, EL1_RECV);
  342   inb_el1(dep, EL1_XMIT);
  343   return;
  344 }
  345 
  346 /*
  347 **  Name:       void el1_init(dpeth_t *dep)
  348 **  Function:   Initalizes board hardware and driver data structures.
  349 */
  350 static void el1_init(dpeth_t * dep)
  351 {
  352   int ix;
  353 
  354   dep->de_irq &= NOT(DEI_DEFAULT);      /* Strip the default flag. */
  355   dep->de_offset_page = 0;
  356   dep->de_data_port = dep->de_base_port + EL1_DATAPORT;
  357 
  358   el1_reset(dep);               /* Reset and initialize board */
  359 
  360   /* Start receiver (default mode) */
  361   outw_el1(dep, EL1_RECVPTR, 0);
  362   outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV);
  363 
  364   /* Initializes buffer pool */
  365   init_buff(dep, NULL);
  366   el1_mode_init(dep);
  367 
  368   printf("%s: Etherlink (%s) at %X:%d - ",
  369          dep->de_name, "3c501", dep->de_base_port, dep->de_irq);
  370   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)
  371         printf("%02X%c", (dep->de_address.ea_addr[ix] = StationAddress[ix]),
  372                ix < SA_ADDR_LEN - 1 ? ':' : '\n');
  373 
  374   /* Device specific functions */
  375   dep->de_recvf = el1_recv;
  376   dep->de_sendf = el1_send;
  377   dep->de_flagsf = el1_mode_init;
  378   dep->de_resetf = el1_reset;
  379   dep->de_getstatsf = el1_getstats;
  380   dep->de_dumpstatsf = el1_dumpstats;
  381   dep->de_interruptf = el1_interrupt;
  382 
  383   return;                       /* Done */
  384 }
  385 
  386 /*
  387 **  Name:       int el1_probe(dpeth_t *dep)
  388 **  Function:   Checks for presence of the board.
  389 */
  390 PUBLIC int el1_probe(dpeth_t * dep)
  391 {
  392   int ix;
  393 
  394   for (ix = 0; ix < 8; ix += 1) /* Reset the board */
  395         outb_el1(dep, EL1_CSR, ECSR_RESET);
  396   outb_el1(dep, EL1_CSR, ECSR_SYS);     /* Leaves buffer to system */
  397 
  398   /* Check station address */
  399   for (ix = 0; ix < SA_ADDR_LEN; ix += 1) {
  400         outw_el1(dep, EL1_XMITPTR, ix);
  401         StationAddress[ix] = inb_el1(dep, EL1_SAPROM);
  402   }
  403   if (StationAddress[0] != 0x02 ||      /* Etherlink Station address  */
  404       StationAddress[1] != 0x60 ||      /* MUST be 02:60:8c:xx:xx:xx  */
  405       StationAddress[2] != 0x8C)
  406         return FALSE;           /* No Etherlink board at this address */
  407 
  408   dep->de_ramsize = 0;          /* RAM size is meaningless */
  409   dep->de_linmem = 0L;          /* Access is via I/O port  */
  410 
  411   /* Device specific functions */
  412   dep->de_initf = el1_init;
  413   dep->de_stopf = el1_stop;
  414 
  415   return TRUE;                  /* Etherlink board found */
  416 }
  417 
  418 #endif                          /* ENABLE_3C501 */
  419 
  420 /** 3c501.c **/

Cache object: 651653612d8b3701b0ea583d8826d182


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.