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/8390.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:       8390.c          May  02, 2000
    3 **
    4 **  Author:     Giovanni Falzoni <gfalzoni@inwind.it>
    5 **
    6 **  This file contains an ethernet device driver for NICs
    7 **  equipped with the National Semiconductor NS 8390 chip.
    8 **  It has to be associated with the board specific driver.
    9 **  Rewritten from Minix 2.0.0 ethernet driver dp8390.c
   10 **  to extract the NS 8390 common functions.
   11 **
   12 **  $Id: 8390.c,v 1.4 2005/09/04 18:52:16 beng Exp $
   13 */
   14 
   15 #include "drivers.h"
   16 #include <minix/com.h>
   17 #include <net/hton.h>
   18 #include <net/gen/ether.h>
   19 #include <net/gen/eth_io.h>
   20 #include "dp.h"
   21 
   22 #if (ENABLE_DP8390 == 1)
   23 
   24 #define PIO16   0       /* NOTE: pio 16 functions missing */
   25 
   26 #include "8390.h"
   27 
   28 #define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
   29         sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
   30                     (dstProc),D,(vir_bytes)(dstOffs),length)
   31 #define sys_user2nic(srcProc,srcOffs,dstOffs,length) \
   32         sys_vircopy((srcProc),D,(vir_bytes)(srcOffs),\
   33                     SELF,dep->de_memsegm,(vir_bytes)(dstOffs),length)
   34 
   35 static const char RdmaErrMsg[] = "remote dma failed to complete";
   36 
   37 /*
   38 **  Name:       void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
   39 **  Function:   Sets the board for reading/writing.
   40 */
   41 static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
   42 {
   43 
   44   if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
   45   outb_reg0(dep, DP_RBCR0, size & 0xFF);
   46   outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
   47   outb_reg0(dep, DP_RSAR0, offset & 0xFF);
   48   outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
   49   mode |= (CR_PS_P0 | CR_STA);
   50   outb_reg0(dep, DP_CR, mode);
   51   return;
   52 }
   53 
   54 /*
   55 **  Name:       void ns_start_xmit(dpeth_t *dep, int size, int pageno);
   56 **  Function:   Sets the board for for transmitting and fires it.
   57 */
   58 static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
   59 {
   60 
   61   outb_reg0(dep, DP_TPSR, pageno);
   62   outb_reg0(dep, DP_TBCR1, size >> 8);
   63   outb_reg0(dep, DP_TBCR0, size & 0xFF);
   64   outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP);   /* Fires transmission */
   65   return;
   66 }
   67 
   68 /*
   69 **  Name:       void mem_getblock(dpeth_t *dep, u16_t offset,
   70 **                              int size, void *dst)
   71 **  Function:   Reads a block of packet from board (shared memory).
   72 */
   73 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
   74 {
   75 
   76   sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
   77   return;
   78 }
   79 
   80 /*
   81 **  Name:       void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
   82 **  Function:   Copies a packet from board to user area (shared memory).
   83 */
   84 static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
   85 {
   86   phys_bytes offset, phys_user;
   87   iovec_dat_t *iovp = &dep->de_read_iovec;
   88   int bytes, ix = 0;
   89 
   90   /* Computes shared memory address (skipping receive header) */
   91   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
   92 
   93   do {                          /* Reads chuncks of packet into user area */
   94 
   95         bytes = iovp->iod_iovec[ix].iov_size;   /* Size of a chunck */
   96         if (bytes > pktsize) bytes = pktsize;
   97 
   98         /* Reads from board to user area */
   99         if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
  100 
  101                 /* Circular buffer wrap-around */
  102                 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
  103                 sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
  104                             iovp->iod_iovec[ix].iov_addr, bytes);
  105                 pktsize -= bytes;
  106                 phys_user += bytes;
  107                 bytes = iovp->iod_iovec[ix].iov_size - bytes;
  108                 if (bytes > pktsize) bytes = pktsize;
  109                 offset = dep->de_startpage * DP_PAGESIZE;
  110         }
  111         sys_nic2mem(dep->de_linmem + offset, iovp->iod_proc_nr,
  112                     iovp->iod_iovec[ix].iov_addr, bytes);
  113         offset += bytes;
  114 
  115         if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
  116                 dp_next_iovec(iovp);
  117                 ix = 0;
  118         }
  119         /* Till packet done */
  120   } while ((pktsize -= bytes) > 0);
  121   return;
  122 }
  123 
  124 /*
  125 **  Name:       void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
  126 **  Function:   Copies a packet from user area to board (shared memory).
  127 */
  128 static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
  129 {
  130   phys_bytes offset, phys_user;
  131   iovec_dat_t *iovp = &dep->de_write_iovec;
  132   int bytes, ix = 0;
  133 
  134   /* Computes shared memory address */
  135   offset = pageno * DP_PAGESIZE;
  136 
  137   do {                          /* Reads chuncks of packet from user area */
  138 
  139         bytes = iovp->iod_iovec[ix].iov_size;   /* Size of chunck */
  140         if (bytes > pktsize) bytes = pktsize;
  141 
  142         /* Reads from user area to board (shared memory) */
  143         sys_user2nic(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, 
  144                      dep->de_linmem + offset, bytes);
  145         offset += bytes;
  146 
  147         if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
  148                 dp_next_iovec(iovp);
  149                 ix = 0;
  150         }
  151         /* Till packet done */
  152   } while ((pktsize -= bytes) > 0);
  153   return;
  154 }
  155 
  156 /*
  157 **  Name:       void pio_getblock(dpeth_t *dep, u16_t offset,
  158 **                              int size, void *dst)
  159 **  Function:   Reads a block of packet from board (Prog. I/O).
  160 */
  161 static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
  162 {
  163 
  164   /* Sets up board for reading */
  165   ns_rw_setup(dep, CR_DM_RR, size, offset);
  166 
  167 #if PIO16 == 0
  168   insb(dep->de_data_port, SELF, dst, size);
  169 #else
  170   if (dep->de_16bit == TRUE) {
  171         insw(dep->de_data_port, dst, size);
  172   } else {
  173         insb(dep->de_data_port, dst, size);
  174   }
  175 #endif
  176   return;
  177 }
  178 
  179 /*
  180 **  Name:       void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
  181 **  Function:   Copies a packet from board to user area (Prog. I/O).
  182 */
  183 static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
  184 {
  185   phys_bytes phys_user;
  186   iovec_dat_t *iovp = &dep->de_read_iovec;
  187   unsigned offset; int bytes, ix = 0;
  188 
  189   /* Computes memory address (skipping receive header) */
  190   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
  191   /* Sets up board for reading */
  192   ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
  193         (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
  194 
  195   do {                          /* Reads chuncks of packet into user area */
  196 
  197         bytes = iovp->iod_iovec[ix].iov_size;   /* Size of a chunck */
  198         if (bytes > pktsize) bytes = pktsize;
  199 
  200         if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
  201 
  202                 /* Circular buffer wrap-around */
  203                 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
  204                 insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
  205                 pktsize -= bytes;
  206                 iovp->iod_iovec[ix].iov_addr += bytes;
  207                 bytes = iovp->iod_iovec[ix].iov_size - bytes;
  208                 if (bytes > pktsize) bytes = pktsize;
  209                 offset = dep->de_startpage * DP_PAGESIZE;
  210                 ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
  211         }
  212         insb(dep->de_data_port, iovp->iod_proc_nr, (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
  213         offset += bytes;
  214 
  215         if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
  216                 dp_next_iovec(iovp);
  217                 ix = 0;
  218         }
  219         /* Till packet done */
  220   } while ((pktsize -= bytes) > 0);
  221   return;
  222 }
  223 
  224 /*
  225 **  Name:       void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
  226 **  Function:   Copies a packet from user area to board (Prog. I/O).
  227 */
  228 static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
  229 {
  230   phys_bytes phys_user;
  231   iovec_dat_t *iovp = &dep->de_write_iovec;
  232   int bytes, ix = 0;
  233 
  234   /* Sets up board for writing */
  235   ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
  236   
  237   do {                          /* Reads chuncks of packet from user area */
  238 
  239         bytes = iovp->iod_iovec[ix].iov_size;   /* Size of chunck */
  240         if (bytes > pktsize) bytes = pktsize;
  241         outsb(dep->de_data_port, iovp->iod_proc_nr,
  242               (void*)(iovp->iod_iovec[ix].iov_addr), bytes);
  243 
  244         if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
  245                 dp_next_iovec(iovp);
  246                 ix = 0;
  247         }
  248         /* Till packet done */
  249   } while ((pktsize -= bytes) > 0);
  250 
  251   for (ix = 0; ix < 100; ix += 1) {
  252         if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
  253   }
  254   if (ix == 100) {
  255         panic(dep->de_name, RdmaErrMsg, NO_NUM);
  256   }
  257   return;
  258 }
  259 
  260 /*
  261 **  Name:       void ns_stats(dpeth_t * dep)
  262 **  Function:   Updates counters reading from device
  263 */
  264 static void ns_stats(dpeth_t * dep)
  265 {
  266 
  267   dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
  268   dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
  269   dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
  270   return;
  271 }
  272 
  273 /*
  274 **  Name:       void ns_dodump(dpeth_t * dep)
  275 **  Function:   Displays statistics (a request from F5 key).
  276 */
  277 static void ns_dodump(dpeth_t * dep)
  278 {
  279 
  280   ns_stats(dep);                /* Forces reading fo counters from board */
  281   return;
  282 }
  283 
  284 /*
  285 **  Name:       void ns_reinit(dpeth_t *dep)
  286 **  Function:   Updates receiver configuration.
  287 */
  288 static void ns_reinit(dpeth_t * dep)
  289 {
  290   int dp_reg = 0;
  291 
  292   if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
  293   if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
  294   if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
  295   outb_reg0(dep, DP_CR, CR_PS_P0);
  296   outb_reg0(dep, DP_RCR, dp_reg);
  297   return;
  298 }
  299 
  300 /*
  301 **  Name:       void ns_send(dpeth_t * dep, int from_int, int size)
  302 **  Function:   Transfers packet to device and starts sending.
  303 */
  304 static void ns_send(dpeth_t * dep, int from_int, int size)
  305 {
  306   int queue;
  307 
  308   if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
  309         if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
  310         dep->de_send_s = size;
  311         return;
  312   }
  313   (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
  314   dep->bytes_Tx += (long) size;
  315   dep->de_sendq[queue].sq_filled = TRUE;
  316   dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
  317   if (dep->de_sendq_tail == queue) {    /* there it goes.. */
  318         ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
  319   } else
  320         dep->de_sendq[queue].sq_size = size;
  321 
  322   if (++queue == dep->de_sendq_nr) queue = 0;
  323   dep->de_sendq_head = queue;
  324   dep->de_flags &= NOT(DEF_SENDING);
  325 
  326   return;
  327 }
  328 
  329 /*
  330 **  Name:       void ns_reset(dpeth_t *dep)
  331 **  Function:   Resets device.
  332 */
  333 static void ns_reset(dpeth_t * dep)
  334 {
  335   int ix;
  336 
  337   /* Stop chip */
  338   outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
  339   outb_reg0(dep, DP_RBCR0, 0);
  340   outb_reg0(dep, DP_RBCR1, 0);
  341   for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
  342          /* Do nothing */ ;
  343   outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
  344   outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
  345   outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
  346 
  347   /* Acknowledge the ISR_RDC (remote dma) interrupt. */
  348   for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
  349          /* Do nothing */ ;
  350   outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
  351 
  352   /* Reset the transmit ring. If we were transmitting a packet, we
  353    * pretend that the packet is processed. Higher layers will
  354    * retransmit if the packet wasn't actually sent. */
  355   dep->de_sendq_head = dep->de_sendq_tail = 0;
  356   for (ix = 0; ix < dep->de_sendq_nr; ix++)
  357         dep->de_sendq[ix].sq_filled = FALSE;
  358   ns_send(dep, TRUE, dep->de_send_s);
  359   return;
  360 }
  361 
  362 /*
  363 **  Name:       void ns_recv(dpeth_t *dep, int fromint, int size)
  364 **  Function:   Gets a packet from device
  365 */
  366 static void ns_recv(dpeth_t *dep, int fromint, int size)
  367 {
  368   dp_rcvhdr_t header;
  369   dp_rcvhdr_t dummy;
  370   unsigned pageno, curr, next;
  371   vir_bytes length;
  372   int packet_processed = FALSE;
  373 #ifdef ETH_IGN_PROTO
  374   u16_t eth_type;
  375 #endif
  376 
  377   pageno = inb_reg0(dep, DP_BNRY) + 1;
  378   if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
  379 
  380   do {
  381         /* */
  382         outb_reg0(dep, DP_CR, CR_PS_P1);
  383         curr = inb_reg1(dep, DP_CURR);
  384         outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
  385 
  386         if (curr == pageno) break;
  387 
  388         (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
  389 #ifdef ETH_IGN_PROTO
  390         (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
  391 #endif
  392         length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
  393         next = header.dr_next;
  394 
  395         if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
  396                 printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
  397                 dep->de_stat.ets_recvErr += 1;
  398                 next = curr;
  399 
  400         } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
  401                 printf("%s: strange next page\n", dep->de_name);
  402                 dep->de_stat.ets_recvErr += 1;
  403                 next = curr;
  404 
  405 #ifdef ETH_IGN_PROTO
  406         } else if (eth_type == eth_ign_proto) {
  407                 /* Hack: ignore packets of a given protocol */
  408                 static int first = TRUE;
  409                 if (first) {
  410                         first = FALSE;
  411                         printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
  412                 }
  413                 next = curr;
  414 #endif
  415         } else if (header.dr_status & RSR_FO) {
  416                 /* This is very serious, issue a warning and reset buffers */
  417                 printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
  418                 dep->de_stat.ets_fifoOver += 1;
  419                 next = curr;
  420 
  421         } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
  422 
  423                 if (!(dep->de_flags & DEF_READING)) break;
  424 
  425                 (dep->de_nic2userf) (dep, pageno, length);
  426                 dep->de_read_s = length;
  427                 dep->de_flags |= DEF_ACK_RECV;
  428                 dep->de_flags &= NOT(DEF_READING);
  429                 packet_processed = TRUE;
  430         }
  431         dep->bytes_Rx += (long) length;
  432         dep->de_stat.ets_packetR += 1;
  433         outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
  434         pageno = next;
  435 
  436   } while (!packet_processed);
  437 #if 0
  438   if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
  439         /* The chip is stopped, and all arrived packets delivered */
  440         (*dep->de_resetf) (dep);
  441   dep->de_flags &= NOT(DEF_STOPPED);
  442 #endif
  443   return;
  444 }
  445 
  446 /*
  447 **  Name:       void ns_interrupt(dpeth_t * dep)
  448 **  Function:   Handles interrupt.
  449 */
  450 static void ns_interrupt(dpeth_t * dep)
  451 {
  452   int isr, tsr;
  453   int size, queue;
  454 
  455   while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
  456 
  457         outb_reg0(dep, DP_ISR, isr);
  458         if (isr & (ISR_PTX | ISR_TXE)) {
  459 
  460                 tsr = inb_reg0(dep, DP_TSR);
  461                 if (tsr & TSR_PTX) {
  462                         dep->de_stat.ets_packetT++;
  463                 }
  464                 if (tsr & TSR_COL) dep->de_stat.ets_collision++;
  465                 if (tsr & (TSR_ABT | TSR_FU)) {
  466                         dep->de_stat.ets_fifoUnder++;
  467                 }
  468                 if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
  469                         printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
  470                         dep->de_stat.ets_sendErr++;
  471                 }
  472                 queue = dep->de_sendq_tail;
  473 
  474                 if (!(dep->de_sendq[queue].sq_filled)) {        /* Hardware bug? */
  475                         printf("%s: transmit interrupt, but not sending\n", dep->de_name);
  476                         continue;
  477                 }
  478                 dep->de_sendq[queue].sq_filled = FALSE;
  479                 if (++queue == dep->de_sendq_nr) queue = 0;
  480                 dep->de_sendq_tail = queue;
  481                 if (dep->de_sendq[queue].sq_filled) {
  482                         ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
  483                                 dep->de_sendq[queue].sq_sendpage);
  484                 }
  485                 if (dep->de_flags & DEF_SENDING) {
  486                         ns_send(dep, TRUE, dep->de_send_s);
  487                 }
  488         }
  489         if (isr & ISR_PRX) {
  490                 ns_recv(dep, TRUE, 0);
  491         }
  492         if (isr & ISR_RXE) {
  493                 printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
  494                 dep->de_stat.ets_recvErr++;
  495         }
  496         if (isr & ISR_CNT) {
  497                 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
  498                 dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
  499                 dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
  500         }
  501         if (isr & ISR_OVW) {
  502                 printf("%s: got overwrite warning\n", dep->de_name);
  503         }
  504         if (isr & ISR_RDC) {
  505                 /* Nothing to do */
  506         }
  507         if (isr & ISR_RST) {
  508                 /* This means we got an interrupt but the ethernet
  509                  * chip is shutdown. We set the flag DEF_STOPPED, and
  510                  * continue processing arrived packets. When the
  511                  * receive buffer is empty, we reset the dp8390. */
  512                 printf("%s: network interface stopped\n", dep->de_name);
  513                 dep->de_flags |= DEF_STOPPED;
  514                 break;
  515         }
  516   }
  517   if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
  518 
  519         /* The chip is stopped, and all arrived packets delivered */
  520         ns_reset(dep);
  521         dep->de_flags &= NOT(DEF_STOPPED);
  522   }
  523   return;
  524 }
  525 
  526 /*
  527 **  Name:       void ns_init(dpeth_t *dep)
  528 **  Function:   Initializes the NS 8390
  529 */
  530 void ns_init(dpeth_t * dep)
  531 {
  532   int dp_reg;
  533   int ix;
  534 
  535   /* NS8390 initialization (as recommended in National Semiconductor specs) */
  536   outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
  537 #if PIO16 == 0
  538   outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
  539 #else
  540   outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
  541                         DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
  542 #endif
  543   outb_reg0(dep, DP_RBCR0, 0);
  544   outb_reg0(dep, DP_RBCR1, 0);
  545   outb_reg0(dep, DP_RCR, RCR_MON);      /* Sets Monitor mode */
  546   outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
  547   outb_reg0(dep, DP_PSTART, dep->de_startpage);
  548   outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
  549   outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
  550   outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
  551   outb_reg0(dep, DP_IMR, 0);    /* Clears Interrupt Mask Register */
  552 
  553   /* Copies station address in page 1 registers */
  554   outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA);  /* Selects Page 1 */
  555   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)       /* Initializes address */
  556         outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
  557   for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1)    /* Initializes address */
  558         outb_reg1(dep, ix, 0xFF);
  559 
  560   outb_reg1(dep, DP_CURR, dep->de_startpage);
  561   outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA);  /* Selects Page 0 */
  562 
  563   inb_reg0(dep, DP_CNTR0);      /* Resets counters by reading them */
  564   inb_reg0(dep, DP_CNTR1);
  565   inb_reg0(dep, DP_CNTR2);
  566 
  567   dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
  568   outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
  569   outb_reg0(dep, DP_IMR, dp_reg);       /* Sets Interrupt Mask register */
  570 
  571   dp_reg = 0;
  572   if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
  573   if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
  574   if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
  575   outb_reg0(dep, DP_RCR, dp_reg);       /* Sets receive as requested */
  576   outb_reg0(dep, DP_TCR, TCR_NORMAL);   /* Sets transmitter */
  577 
  578   outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);    /* Starts board */
  579 
  580   /* Initializes the send queue. */
  581   for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
  582         dep->de_sendq[ix].sq_filled = 0;
  583   dep->de_sendq_head = dep->de_sendq_tail = 0;
  584 
  585   /* Device specific functions */
  586   if (!dep->de_prog_IO) {
  587         dep->de_user2nicf = mem_user2nic;
  588         dep->de_nic2userf = mem_nic2user;
  589         dep->de_getblockf = mem_getblock;
  590   } else {
  591 #if PIO16 == 0
  592         dep->de_user2nicf = pio_user2nic;
  593         dep->de_nic2userf = pio_nic2user;
  594         dep->de_getblockf = pio_getblock;
  595 #else
  596 #error  Missing I/O functions for pio 16 bits
  597 #endif
  598   }
  599   dep->de_recvf = ns_recv;
  600   dep->de_sendf = ns_send;
  601   dep->de_flagsf = ns_reinit;
  602   dep->de_resetf = ns_reset;
  603   dep->de_getstatsf = ns_stats;
  604   dep->de_dumpstatsf = ns_dodump;
  605   dep->de_interruptf = ns_interrupt;
  606 
  607   return;                       /* Done */
  608 }
  609 
  610 #if PIO16 == 1
  611 
  612 /*
  613 **  Name:       void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
  614 **  Function:   Copies a packet from user area to board (Prog. I/O, 16bits).
  615 */
  616 static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
  617 {
  618   u8_t two_bytes[2];
  619   phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
  620   vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
  621   int bytes, ix = 0, odd_byte = 0;
  622   iovec_dat_t *iovp = &dep->de_write_iovec;
  623 
  624   outb_reg0(dep, DP_ISR, ISR_RDC);
  625   dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
  626 
  627   do {
  628         bytes = iovp->iod_iovec[ix].iov_size;
  629         if (bytes > pktsize) bytes = pktsize;
  630 
  631         phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
  632         if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
  633 
  634         if (odd_byte) {
  635                 phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
  636                 out_word(dep->de_data_port, *(u16_t *)two_bytes);
  637                 pktsize--;
  638                 bytes--;
  639                 phys_user++;
  640                 odd_byte = 0;
  641                 if (!bytes) continue;
  642         }
  643         ecount = bytes & NOT(0x0001);
  644         if (ecount != 0) {
  645                 phys_outsw(dep->de_data_port, phys_user, ecount);
  646                 pktsize -= ecount;
  647                 bytes -= ecount;
  648                 phys_user += ecount;
  649         }
  650         if (bytes) {
  651                 phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
  652                 pktsize--;
  653                 bytes--;
  654                 phys_user++;
  655                 odd_byte = 1;
  656         }
  657         if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
  658                 dp_next_iovec(iovp);
  659                 ix = 0;
  660         }
  661 
  662   }  while (bytes > 0);
  663 
  664   if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
  665   for (ix = 0; ix < 100; ix++) {
  666         if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
  667   }
  668   if (ix == 100) {
  669         panic(dep->de_name, RdmaErrMsg, NO_NUM);
  670   }
  671   return;
  672 }
  673 
  674 /*
  675 **  Name:       void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
  676 **  Function:   Copies a packet from board to user area (Prog. I/O, 16bits).
  677 */
  678 static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
  679 {
  680   phys_bytes phys_user;
  681   vir_bytes ecount;
  682   int bytes, i;
  683   u8_t two_bytes[2];
  684   phys_bytes phys_2bytes;
  685   int odd_byte;
  686 
  687   ecount = (count + 1) & ~1;
  688   phys_2bytes = vir2phys(two_bytes);
  689   odd_byte = 0;
  690 
  691   dp_read_setup(dep, ecount, nic_addr);
  692 
  693   i = 0;
  694   while (count > 0) {
  695         if (i >= IOVEC_NR) {
  696                 dp_next_iovec(iovp);
  697                 i = 0;
  698                 continue;
  699         }
  700         bytes = iovp->iod_iovec[i].iov_size;
  701         if (bytes > count) bytes = count;
  702 
  703         phys_user = numap(iovp->iod_proc_nr,
  704                           iovp->iod_iovec[i].iov_addr, bytes);
  705         if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
  706         if (odd_byte) {
  707                 phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
  708                 count--;
  709                 bytes--;
  710                 phys_user++;
  711                 odd_byte = 0;
  712                 if (!bytes) continue;
  713         }
  714         ecount = bytes & ~1;
  715         if (ecount != 0) {
  716                 phys_insw(dep->de_data_port, phys_user, ecount);
  717                 count -= ecount;
  718                 bytes -= ecount;
  719                 phys_user += ecount;
  720         }
  721         if (bytes) {
  722                 *(u16_t *) two_bytes = in_word(dep->de_data_port);
  723                 phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
  724                 count--;
  725                 bytes--;
  726                 phys_user++;
  727                 odd_byte = 1;
  728         }
  729   }
  730   return;
  731 }
  732 
  733 #endif                          /* PIO16 == 1 */
  734 
  735 #endif                          /* ENABLE_DP8390 */
  736 
  737 /** end 8390.c **/

Cache object: f336c5bf3b3fc1e20aec85f328eb99eb


[ 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.