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/i386at/if_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  * Mach Operating System
    3  * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /* 
   27  * HISTORY
   28  * $Log:        if_3c501.c,v $
   29  * Revision 2.16  93/11/17  16:46:08  dbg
   30  *      Removed all non-MACH_KERNEL code.  Changed uses of 'HZ' to 'hz'.
   31  *      [93/05/21            dbg]
   32  * 
   33  * Revision 2.15  93/05/10  21:19:13  rvb
   34  *      Lint.
   35  *      [93/05/08  11:22:57  af]
   36  * 
   37  * Revision 2.14  93/03/11  13:58:09  danner
   38  *      u_long -> u_int.
   39  *      [93/03/09            danner]
   40  * 
   41  * Revision 2.13  93/01/14  17:30:30  danner
   42  *      Proper spl typing.
   43  *      [92/11/30            af]
   44  * 
   45  * Revision 2.12  91/08/24  11:57:53  af
   46  *      New MI autoconf.
   47  *      [91/08/02  02:54:56  af]
   48  * 
   49  * Revision 2.11  91/05/14  16:24:19  mrt
   50  *      Correcting copyright
   51  * 
   52  * Revision 2.10  91/05/13  06:02:32  af
   53  *      Made code under CMUCS standard.
   54  *      [91/05/12  15:50:59  af]
   55  * 
   56  * Revision 2.9  91/03/16  14:46:08  rpd
   57  *      Changed net_filter to net_packet.
   58  *      [91/01/15            rpd]
   59  * 
   60  * Revision 2.8  91/02/05  17:17:32  mrt
   61  *      Added OSF permision and disclaimer clause per instructions
   62  *      of Philippe Bernadat.
   63  *      [91/02/04            mrt]
   64  *      Changed to new Mach copyright
   65  *      [91/02/01  17:43:37  mrt]
   66  * 
   67  * Revision 2.7  91/01/08  15:11:34  rpd
   68  *      Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
   69  *      [91/01/05            rpd]
   70  * 
   71  * Revision 2.6  90/11/26  14:49:51  rvb
   72  *      jsb beat me to XMK34, sigh ...
   73  *      [90/11/26            rvb]
   74  *      Synched 2.5 & 3.0 at I386q (r2.1.1.4) & XMK35 (r2.6)
   75  *      [90/11/15            rvb]
   76  * 
   77  * Revision 2.5  90/08/27  22:00:04  dbg
   78  *      Change ushort to unsigned short.
   79  *      [90/07/17            dbg]
   80  * 
   81  * Revision 2.1.1.3  90/08/25  15:44:09  rvb
   82  *      Use take_<>_irq() vs direct manipulations of ivect and friends.
   83  *      [90/08/20            rvb]
   84  * 
   85  *      Fix DSF_RUNNING.  Some more cleanup.
   86  *      [90/08/14            rvb]
   87  * 
   88  * Revision 2.1.1.2  90/07/10  11:50:05  rvb
   89  *      Set etherheader in hwrst to fend off madness of the wtprobe().
   90  *      [90/07/02            rvb]
   91  * 
   92  *      New style probe/attach.
   93  *      [90/06/15            rvb]
   94  * 
   95  *      Fix xmt if jam to retry.  Set tcp_recvspace for better
   96  *      "sink" behaviour.
   97  *      [90/03/29            rvb]
   98  * 
   99  * Revision 2.4  90/06/02  14:49:05  rpd
  100  *      Converted to new IPC.
  101  *      [90/06/01            rpd]
  102  * 
  103  * Revision 2.3  90/05/21  13:27:01  dbg
  104  *      Fix bugs.
  105  *      [90/05/17            dbg]
  106  * 
  107  * Revision 2.2  90/05/03  15:43:38  dbg
  108  *      Convert for pure kernel.
  109  *      [90/04/27            dbg]
  110  * 
  111  * Revision 2.1.1.1  90/03/16  18:15:22  rvb
  112  *      Clean up the i386_dev/i386_ctlr confusion.
  113  *      Some minor cleanups
  114  *      installed.
  115  *      [90/03/13            rvb]
  116  *      Created by Philippe Bernadat
  117  */
  118 /*
  119  *      File:   if_3c501.c
  120  *      Author: Philippe Bernadat
  121  *      Date:   1989
  122  *      Copyright (c) 1989 OSF Research Institute 
  123  *
  124  *      3COM Etherlink 3C501 Mach Ethernet drvier
  125  */
  126 /*
  127   Copyright 1990 by Open Software Foundation,
  128 Cambridge, MA.
  129 
  130                 All Rights Reserved
  131 
  132   Permission to use, copy, modify, and distribute this software and
  133 its documentation for any purpose and without fee is hereby granted,
  134 provided that the above copyright notice appears in all copies and
  135 that both the copyright notice and this permission notice appear in
  136 supporting documentation, and that the name of OSF or Open Software
  137 Foundation not be used in advertising or publicity pertaining to
  138 distribution of the software without specific, written prior
  139 permission.
  140 
  141   OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  142 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  143 IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  144 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  145 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  146 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  147 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  148 */
  149 
  150 #include <at3c501.h>
  151 
  152 #include        <kern/kern_io.h>                /* printf */
  153 #include        <kern/strings.h>                /* strncmp */
  154 #include        <kern/time_out.h>
  155 #include        <device/device_types.h>
  156 #include        <device/errno.h>
  157 #include        <device/io_req.h>
  158 #include        <device/if_hdr.h>
  159 #include        <device/if_ether.h>
  160 #include        <device/net_status.h>
  161 #include        <device/net_io.h>
  162 
  163 #include        <i386/ipl.h>
  164 #include        <i386/machspl.h>
  165 #include        <i386/pio.h>
  166 #include        <chips/busses.h>
  167 #include        <i386at/if_3c501.h>
  168 
  169 #define SPLNET  spl6
  170 
  171 boolean_t at3c501probe(
  172         vm_offset_t     port,
  173         struct bus_device *dev);
  174 void at3c501attach(
  175         struct bus_device       *dev);
  176 int     at3c501intr();
  177 void at3c501init(
  178         int     unit);
  179 io_return_t at3c501output(
  180         dev_t           dev,
  181         io_req_t        ior);
  182 void at3c501xmt(
  183         int     unit,
  184         io_req_t m);
  185 void at3c501reset(int unit);
  186 void at3c501watch(void *b_ptr);
  187 void at3c501geteh(
  188         unsigned short  base,
  189         char *          ep);
  190 void at3c501seteh(
  191         unsigned short  base,
  192         char *          ep);
  193 
  194 static vm_offset_t at3c501_std[NAT3C501] = { 0 };
  195 static struct bus_device *at3c501_info[NAT3C501];
  196 struct  bus_driver      at3c501driver = 
  197         {at3c501probe, 0, at3c501attach, 0, at3c501_std, "et", at3c501_info, };
  198 
  199 int     watchdog_id;
  200 
  201 typedef struct { 
  202         struct  ifnet   ds_if;          /* generic interface header */
  203         u_char  ds_addr[6];             /* Ethernet hardware address */
  204         int     flags;
  205         int     timer;
  206         unsigned short base;            /* base address of IO ports */
  207         u_char   address[ETHER_ADD_SIZE];
  208         short   mode;
  209         int     badxmt;
  210         int     badrcv;
  211         int     spurious;
  212         int     rcv;
  213         int     xmt;
  214 } at3c501_softc_t;
  215 
  216 at3c501_softc_t at3c501_softc[NAT3C501];
  217 
  218 /*
  219  * at3c501probe:
  220  *
  221  *      This function "probes" or checks for the 3c501 board on the bus to see
  222  *      if it is there.  As far as I can tell, the best break between this
  223  *      routine and the attach code is to simply determine whether the board
  224  *      is configured in properly.  Currently my approach to this is to write
  225  *      and read a string from the Packet Buffer on the board being probed.
  226  *      If the string comes back properly then we assume the board is there.
  227  *      The config code expects to see a successful return from the probe
  228  *      routine before  attach will be called.
  229  *
  230  * input        : address device is mapped to, and unit # being checked
  231  * output       : a '1' is returned if the board exists, and a 0 otherwise
  232  *
  233  */
  234 boolean_t at3c501probe(
  235         vm_offset_t     port,
  236         struct bus_device *dev)
  237 {
  238         unsigned short  base = (unsigned short) dev->address;
  239         int             unit = dev->unit;
  240         char            inbuf[50];
  241         char            *str = "3c501 ethernet board %d out of range\n";
  242         int             strsize = strlen(str);
  243 
  244         if ((unit < 0) || (unit >= NAT3C501)) {
  245                 printf(str, unit);
  246                 return(0);
  247         }
  248 
  249         /* reset */
  250         outb(IE_CSR(base), IE_RESET);
  251 
  252         /* write a string to the packet buffer */
  253 
  254         outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
  255         outw(IE_GP(base), 0);
  256         loutb(IE_BFR(base), str, strsize);
  257 
  258         /* read it back */
  259 
  260         outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
  261         outw(IE_GP(base), 0);
  262         linb(IE_BFR(base), inbuf, strsize);
  263         /* compare them */
  264 
  265         if (strncmp(str, inbuf, strsize))
  266         {
  267                 return FALSE;
  268         }
  269         at3c501_softc[unit].base = base;
  270 
  271         return TRUE;
  272 }
  273 
  274 /*
  275  * at3c501attach:
  276  *
  277  *      This function attaches a 3C501 board to the "system".  The rest of
  278  *      runtime structures are initialized here (this routine is called after
  279  *      a successful probe of the board).  Once the ethernet address is read
  280  *      and stored, the board's ifnet structure is attached and readied.
  281  *
  282  * input        : bus_device structure setup in autoconfig
  283  * output       : board structs and ifnet is setup
  284  *
  285  */
  286 void at3c501attach(
  287         struct bus_device       *dev)
  288 {
  289         at3c501_softc_t *sp;
  290         struct  ifnet   *ifp;
  291         u_char          unit;
  292         unsigned short  base;
  293 
  294 #if     0       /* can`t do this! */
  295         extern int      tcp_recvspace;
  296         tcp_recvspace = 0x300;          /* empircal measure */
  297 #endif
  298 
  299         take_dev_irq(dev);
  300         unit = (u_char)dev->unit;       
  301         printf(", port = %x, spl = %d, pic = %d. ",
  302                 dev->address, dev->sysdep, dev->sysdep1);
  303 
  304         sp = &at3c501_softc[unit];
  305         base = sp->base;
  306         if (base != dev->address) {
  307                 printf("3C501 board %d attach address error\n", unit);
  308                 return;
  309         }
  310         sp->timer = -1;
  311         sp->flags = 0;
  312         sp->mode = 0;
  313         outb(IE_CSR(sp->base), IE_RESET);
  314         at3c501geteh(base, sp->ds_addr);
  315         at3c501geteh(base, sp->address);
  316         at3c501seteh(base, sp->address);
  317         printf("ethernet id [%x:%x:%x:%x:%x:%x]",
  318                 sp->address[0],sp->address[1],sp->address[2], 
  319                 sp->address[3],sp->address[4],sp->address[5]);
  320         ifp = &(sp->ds_if);
  321         ifp->if_unit = unit;
  322         ifp->if_mtu = ETHERMTU;
  323         ifp->if_flags = IFF_BROADCAST;
  324         ifp->if_header_size = sizeof(struct ether_header);
  325         ifp->if_header_format = HDR_ETHERNET;
  326         ifp->if_address_size = 6;
  327         ifp->if_address = (char *)&sp->address[0];
  328         if_init_queues(ifp);
  329 }
  330 
  331 /*
  332  * at3c501watch():
  333  *
  334  */
  335 void at3c501watch(void *b_ptr)
  336 {
  337         int     unit;
  338         at3c501_softc_t *is;
  339 
  340         unit = *(char *)b_ptr;
  341         timeout(at3c501watch,b_ptr,20*hz);
  342         is = &at3c501_softc[unit];
  343         printf("\nxmt/bad       rcv/bad spurious\n");
  344         printf("%d/%d           %d/%d   %d\n", is->xmt, is->badxmt, \
  345                 is->rcv, is->badrcv, is->spurious);
  346         is->rcv=is->badrcv=is->xmt=is->badxmt=is->spurious=0;
  347 }
  348 
  349 /*
  350  * at3c501geteh:
  351  *
  352  *      This function gets the ethernet address (array of 6 unsigned
  353  *      bytes) from the 3c501 board prom. 
  354  *
  355  */
  356 
  357 void at3c501geteh(
  358         unsigned short  base,
  359         char *          ep)
  360 {
  361         int     i;
  362 
  363         for (i = 0; i < ETHER_ADD_SIZE; i++) {
  364                 outw(IE_GP(base), i);
  365                 *ep++ = inb(IE_SAPROM(base));
  366         }
  367 }
  368 
  369 /*
  370  * at3c501seteh:
  371  *
  372  *      This function sets the ethernet address (array of 6 unsigned
  373  *      bytes) on the 3c501 board. 
  374  *
  375  */
  376 
  377 void at3c501seteh(
  378         unsigned short  base,
  379         char *          ep)
  380 {
  381         int     i;
  382 
  383         for (i = 0; i < ETHER_ADD_SIZE; i++) {
  384                 outb(EDLC_ADDR(base) + i, *ep++);
  385         }
  386 }
  387 
  388 void at3c501start(int unit);    /* forward */
  389 
  390 io_return_t
  391 at3c501output(
  392         dev_t           dev,
  393         io_req_t        ior)
  394 {
  395         register int    unit = minor(dev);
  396 
  397         if (unit < 0 || unit >= NAT3C501 ||
  398                 at3c501_softc[unit].base == 0)
  399             return ENXIO;
  400 
  401         return net_write(&at3c501_softc[unit].ds_if, at3c501start, ior);
  402 }
  403 
  404 io_return_t
  405 at3c501setinput(
  406         dev_t           dev,
  407         mach_port_t     receive_port,
  408         int             priority,
  409         filter_t        filter[],
  410         natural_t       filter_count)
  411 {
  412         register int unit = minor(dev);
  413 
  414         if (unit < 0 || unit >= NAT3C501 ||
  415                 at3c501_softc[unit].base == 0)
  416             return ENXIO;
  417 
  418         return net_set_filter(&at3c501_softc[unit].ds_if,
  419                         receive_port, priority,
  420                         filter, filter_count);
  421 }
  422 
  423 
  424 /*
  425  * at3c501reset:
  426  *
  427  *      This routine is in part an entry point for the "if" code.  Since most 
  428  *      of the actual initialization has already (we hope already) been done
  429  *      by calling at3c501attach().
  430  *
  431  * input        : unit number or board number to reset
  432  * output       : board is reset
  433  *
  434  */
  435 void at3c501reset(
  436         int     unit)
  437 {
  438         at3c501_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
  439         at3c501init(unit);
  440 }
  441 
  442 
  443 
  444 /*
  445  * at3c501init:
  446  *
  447  *      Another routine that interfaces the "if" layer to this driver.  
  448  *      Simply resets the structures that are used by "upper layers".  
  449  *      As well as calling at3c501hwrst that does reset the at3c501 board.
  450  *
  451  * input        : board number
  452  * output       : structures (if structs) and board are reset
  453  *
  454  */     
  455 void at3c501init(
  456         int     unit)
  457 {
  458         struct  ifnet   *ifp;
  459         int             stat;
  460         spl_t           oldpri;
  461 
  462         ifp = &(at3c501_softc[unit].ds_if);
  463         oldpri = SPLNET();
  464         if ((stat = at3c501hwrst(unit)) == TRUE) {
  465                 at3c501_softc[unit].ds_if.if_flags |= IFF_RUNNING;
  466                 at3c501_softc[unit].flags |= DSF_RUNNING;
  467                 at3c501start(unit);
  468         }
  469         else
  470                 printf("3C501 trouble resetting board %d\n", unit);
  471         at3c501_softc[unit].timer = 5;
  472         splx(oldpri);
  473         /* XXX no return value - callers ignore */
  474 }
  475 
  476 /*ARGSUSED*/
  477 at3c501open(dev, flag)
  478         dev_t   dev;
  479         int     flag;
  480 {
  481         register int    unit = minor(dev);
  482 
  483         if (unit < 0 || unit >= NAT3C501 ||
  484                 at3c501_softc[unit].base == 0)
  485             return (ENXIO);
  486 
  487         at3c501_softc[unit].ds_if.if_flags |= IFF_UP;
  488         at3c501init(unit);
  489         return(0);
  490 }
  491 
  492 /*
  493  * at3c501start:
  494  *
  495  *      This is yet another interface routine that simply tries to output a
  496  *      in an mbuf after a reset.
  497  *
  498  * input        : board number
  499  * output       : stuff sent to board if any there
  500  *
  501  */
  502 void at3c501start(
  503         int     unit)
  504 {
  505         io_req_t        m;
  506         struct  ifnet   *ifp;
  507 
  508         ifp = &(at3c501_softc[unit].ds_if);
  509         for(;;) {
  510                 IF_DEQUEUE(&ifp->if_snd, m);
  511                 if (m != 0)
  512                         at3c501xmt(unit, m);
  513                 else
  514                         return;
  515         }
  516 }
  517 
  518 /*ARGSUSED*/
  519 io_return_t
  520 at3c501getstat(
  521         dev_t           dev,
  522         dev_flavor_t    flavor,
  523         dev_status_t    status,         /* pointer to OUT array */
  524         natural_t       *count)         /* out */
  525 {
  526         register int    unit = minor(dev);
  527 
  528         if (unit < 0 || unit >= NAT3C501 ||
  529                 at3c501_softc[unit].base == 0)
  530             return ENXIO;
  531 
  532         return net_getstat(&at3c501_softc[unit].ds_if,
  533                             flavor,
  534                             status,
  535                             count);
  536 }
  537 
  538 io_return_t
  539 at3c501setstat(
  540         dev_t           dev,
  541         int             flavor,
  542         dev_status_t    status,
  543         natural_t       count)
  544 {
  545         register int    unit = minor(dev);
  546         register at3c501_softc_t *sp;
  547 
  548         if (unit < 0 || unit >= NAT3C501 ||
  549                 at3c501_softc[unit].base == 0)
  550             return (ENXIO);
  551 
  552         sp = &at3c501_softc[unit];
  553 
  554         switch (flavor) {
  555             case NET_STATUS:
  556             {
  557                 /*
  558                  * All we can change are flags, and not many of those.
  559                  */
  560                 register struct net_status *ns = (struct net_status *)status;
  561                 int     mode = 0;
  562 
  563                 if (count < NET_STATUS_COUNT)
  564                     return (D_INVALID_SIZE);
  565 
  566                 if (ns->flags & IFF_ALLMULTI)
  567                     mode |= MOD_ENAL;
  568                 if (ns->flags & IFF_PROMISC)
  569                     mode |= MOD_PROM;
  570 
  571                 /*
  572                  * Force a compilete reset if the receive mode changes
  573                  * so that these take effect immediately.
  574                  */
  575                 if (sp->mode != mode) {
  576                     sp->mode = mode;
  577                     if (sp->flags & DSF_RUNNING) {
  578                         sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
  579                         at3c501init(unit);
  580                     }
  581                 }
  582                 break;
  583             }
  584             case NET_ADDRESS:
  585             {
  586                 register union ether_cvt {
  587                     char        addr[6];
  588                     int         lwd[2];
  589                 } *ec = (union ether_cvt *)status;
  590 
  591                 if (count < sizeof(*ec)/sizeof(int))
  592                     return (D_INVALID_SIZE);
  593 
  594                 ec->lwd[0] = ntohl(ec->lwd[0]);
  595                 ec->lwd[1] = ntohl(ec->lwd[1]);
  596                 at3c501seteh(sp->base, ec->addr);
  597                 break;
  598             }
  599 
  600             default:
  601                 return (D_INVALID_OPERATION);
  602         }
  603         return (D_SUCCESS);
  604 }
  605 
  606 /*
  607  * at3c501hwrst:
  608  *
  609  *      This routine resets the at3c501 board that corresponds to the 
  610  *      board number passed in.
  611  *
  612  * input        : board number to do a hardware reset
  613  * output       : board is reset
  614  *
  615  */
  616 #define XMT_STAT (EDLC_16|EDLC_JAM|EDLC_UNDER|EDLC_IDLE)
  617 #define RCV_STAT (EDLC_STALE|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_OVER|EDLC_FCS)
  618 int 
  619 at3c501hwrst(unit)
  620 int unit;
  621 {
  622         u_char  stat;
  623         unsigned short  base = at3c501_softc[unit].base;
  624 
  625         outb(IE_CSR(base), IE_RESET);
  626         outb(IE_CSR(base), 0);
  627         at3c501seteh(base, at3c501_softc[unit].address);
  628         if ((stat = inb(IE_CSR(base))) != IE_RESET) {
  629                 printf("at3c501reset: can't reset CSR: %x\n", stat);
  630                 return(FALSE);
  631         }
  632         if ((stat = inb(EDLC_XMT(base))) & XMT_STAT) {
  633                 printf("at3c501reset: can't reset XMT: %x\n", stat);
  634                 return(FALSE);
  635         }
  636         if (((stat = inb(EDLC_RCV(base))) & RCV_STAT) != EDLC_STALE) {
  637                 printf("at3c501reset: can't reset RCV: %x\n", stat);
  638                 return(FALSE);
  639         }
  640         if (at3c501config(unit) == FALSE) {
  641                 printf("at3c501hwrst(): failed to config\n");
  642                 return(FALSE);
  643         }
  644         outb(IE_RP(base), 0);
  645         outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  646         return(TRUE);
  647 }
  648 
  649 /*
  650  * at3c501intr:
  651  *
  652  *      This function is the interrupt handler for the at3c501 ethernet
  653  *      board.  This routine will be called whenever either a packet
  654  *      is received, or a packet has successfully been transfered and
  655  *      the unit is ready to transmit another packet.
  656  *
  657  * input        : board number that interrupted
  658  * output       : either a packet is received, or a packet is transfered
  659  *
  660  */
  661 at3c501intr(unit)
  662 int unit;
  663 {
  664         at3c501rcv(unit);
  665         at3c501start(unit);
  666 
  667         return(0);
  668 }
  669 
  670 
  671 /*
  672  * at3c501rcv:
  673  *
  674  *      This routine is called by the interrupt handler to initiate a
  675  *      packet transfer from the board to the "if" layer above this
  676  *      driver.  This routine checks if a buffer has been successfully
  677  *      received by the at3c501.  If so, the routine at3c501read is called
  678  *      to do the actual transfer of the board data (including the
  679  *      ethernet header) into a packet (consisting of an mbuf chain).
  680  *
  681  * input        : number of the board to check
  682  * output       : if a packet is available, it is "sent up"
  683  *
  684  */
  685 at3c501rcv(unit)
  686 int     unit;
  687 {
  688         int stat;
  689         unsigned short  base;
  690         ipc_kmsg_t      new_kmsg;
  691         struct ether_header *ehp;
  692         struct packet_header *pkt;
  693         u_short len;
  694         register struct ifnet *ifp;
  695         register at3c501_softc_t        *is;
  696         struct  ether_header eh;
  697 
  698         is = &at3c501_softc[unit];
  699         ifp = &is->ds_if;
  700         base = at3c501_softc[unit].base;
  701         is->rcv++;
  702         if (inb(IE_CSR(base)) & IE_RCVBSY)
  703                 is->spurious++;
  704         while (!((stat=inb(EDLC_RCV(base))) & EDLC_STALE)) {
  705                 outb(IE_CSR(base), IE_SYSBFR);
  706                 if (!(stat & EDLC_ANY)) {
  707                         outw(IE_GP(base), 0);
  708                         len = inw(IE_RP(base))-sizeof(struct ether_header);
  709                         outb(IE_RP(base), 0);
  710                         outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  711                         is->badrcv++;
  712 #ifdef DEBUG
  713                         printf("at3c501rcv: received %d bad bytes", len);
  714                         if (stat & EDLC_SHORT)
  715                                 printf(" Short frame");
  716                         if (stat & EDLC_OVER) 
  717                                 printf(" Data overflow");
  718                         if (stat & EDLC_DRIBBLE)
  719                                 printf(" Dribble error");
  720                         if (stat & EDLC_FCS)
  721                                 printf(" CRC error");
  722                         printf("\n");
  723 #endif DEBUG
  724                 } else {
  725                         outw(IE_GP(base), 0);
  726                         len = inw(IE_RP(base));
  727                         if (len < 60) {
  728                                 outb(IE_RP(base), 0);
  729                                 outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  730                                 return;
  731                         }
  732                         linb(IE_BFR(base), &eh, sizeof(struct ether_header));
  733                         new_kmsg = net_kmsg_get();
  734                         if (new_kmsg == IKM_NULL) {
  735                             /*
  736                              * Drop the packet.
  737                              */
  738                             is->ds_if.if_rcvdrops++;
  739 
  740                             outb(IE_RP(base), 0);
  741                             outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  742                             return;
  743                         }
  744 
  745                         ehp = (struct ether_header *)
  746                                 (&net_kmsg(new_kmsg)->header[0]);
  747                         pkt = (struct packet_header *)
  748                                 (&net_kmsg(new_kmsg)->packet[0]);
  749 
  750                         /*
  751                          * Get header.
  752                          */
  753                         *ehp = eh;
  754 
  755                         /*
  756                          * Get body
  757                          */
  758                         linb(IE_BFR(base),
  759                              (char *)(pkt + 1),
  760                              len - sizeof(struct ether_header));
  761 
  762                         outb(IE_RP(base), 0);
  763                         outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  764 
  765                         pkt->type = ehp->ether_type;
  766                         pkt->length = len - sizeof(struct ether_header)
  767                                           + sizeof(struct packet_header);
  768 
  769                         /*
  770                          * Hand the packet to the network module.
  771                          */
  772                         net_packet(ifp, new_kmsg, pkt->length,
  773                                    ethernet_priority(new_kmsg));
  774 
  775                 }
  776         }
  777 }
  778 
  779 
  780 /*
  781  * at3c501xmt:
  782  *
  783  *      This routine fills in the appropriate registers and memory
  784  *      locations on the 3C501 board and starts the board off on
  785  *      the transmit.
  786  *
  787  * input        : board number of interest, and a pointer to the mbuf
  788  * output       : board memory and registers are set for xfer and attention
  789  *
  790  */
  791 void at3c501xmt(
  792         int     unit,
  793         io_req_t m)
  794 {
  795         int                     i;
  796         at3c501_softc_t         *is = &at3c501_softc[unit];
  797         unsigned short          base = is->base;
  798         u_short                 count = 0;
  799         u_short                 bytes_in_msg;
  800 
  801         is->xmt++;
  802         outb(IE_CSR(base), IE_SYSBFR);
  803         count = m->io_count;
  804 #define max(a,b)        (((a) > (b)) ? (a) : (b))
  805         bytes_in_msg = max(count,
  806                            ETHERMIN + sizeof(struct ether_header));
  807         outw(IE_GP(base), BFRSIZ-bytes_in_msg);
  808         loutb(IE_BFR(base), m->io_data, count);
  809         while (count < bytes_in_msg) {
  810                 outb(IE_BFR(base), 0);
  811                 count++;
  812         }
  813         do {
  814                 if (!(int)m) {
  815                         outb(IE_CSR(base), IE_SYSBFR);
  816                 }
  817                 outw(IE_GP(base), BFRSIZ-bytes_in_msg);
  818                 outb(IE_CSR(base), IE_RIDE|IE_XMTEDLC);
  819                 if (m) {
  820                         iodone(m);
  821                         m = 0;
  822                 }
  823                 for (i=0; inb(IE_CSR(base)) & IE_XMTBSY; i++);
  824                 if ((i=inb(EDLC_XMT(base))) & EDLC_JAM) {
  825                         is->badxmt++;
  826 #ifdef DEBUG
  827                         printf("at3c501xmt jam\n");
  828 #endif DEBUG
  829                 }
  830         } while ((i & EDLC_JAM) && !(i & EDLC_16));
  831 
  832         if (i & EDLC_16) {
  833                 printf("%%");
  834         }
  835         return;
  836 
  837 }
  838 
  839 /*
  840  * at3c501config:
  841  *
  842  *      This routine does a standard config of the at3c501 board.
  843  *
  844  */
  845 at3c501config(unit)
  846 int     unit;
  847 {
  848         unsigned short  base = at3c501_softc[unit].base;
  849 
  850         /* Enable DMA & Interrupts */
  851 
  852         outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
  853 
  854         /* No Transmit Interrupts */
  855 
  856         outb(EDLC_XMT(base), 0);
  857         inb(EDLC_XMT(base));
  858 
  859         /* Setup Receive Interrupts */
  860 
  861         outb(EDLC_RCV(base), EDLC_BROAD|EDLC_SHORT|EDLC_GOOD|EDLC_DRIBBLE|EDLC_OVER);
  862         inb(EDLC_RCV(base));
  863 
  864         outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
  865         outb(IE_RP(base), 0);
  866         outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
  867         return(TRUE);
  868 }
  869 
  870 /*
  871  * at3c501intoff:
  872  *
  873  *      This function turns interrupts off for the at3c501 board indicated.
  874  *
  875  */
  876 at3c501intoff(unit)
  877 int unit;
  878 {
  879         unsigned short  base = at3c501_softc[unit].base;
  880         outb(IE_CSR(base), 0);
  881 }
  882 

Cache object: c6991a8bde76d86cca564dab2bd081c5


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