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_pc586.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) 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_pc586.c,v $
   29  * Revision 2.22  93/05/10  21:19:37  rvb
   30  *      Lint.
   31  *      [93/05/08  11:21:38  af]
   32  * 
   33  * Revision 2.21  93/01/24  13:17:39  danner
   34  *      Found a pc586 with octets 0:0:1c
   35  *      [93/01/15            rvb]
   36  * 
   37  * Revision 2.20  93/01/14  17:30:55  danner
   38  *      Proper spl typing.
   39  *      [92/11/30            af]
   40  * 
   41  * Revision 2.19  92/07/09  22:54:30  rvb
   42  *      Check for pc586 signature, rather than just for writable memory.
   43  *      [92/05/18            rvb]
   44  * 
   45  * Revision 2.18  91/11/12  11:09:47  rvb
   46  *      Undo 2.16.1.1
   47  *      [91/10/25            rvb]
   48  *      Typo in transcribing the 2.5 changes missed ! before pc586read().
   49  *      Funny thing is that we did have this fixed in a branch once.
   50  *      [91/10/16            rvb]
   51  * 
   52  * Revision 2.17  91/10/07  17:25:48  af
   53  *      Add a lot of fixes/improvements from 2.5.
   54  *      [91/09/04            rvb]
   55  * 
   56  * Revision 2.16.1.1  91/09/03  17:27:39  af
   57  *      Be strict on matching the port and the device in the probe routine.
   58  *
   59  * Revision 2.16  91/08/24  11:58:12  af
   60  *      New MI autoconf.
   61  *      [91/08/02  02:54:27  af]
   62  * 
   63  * Revision 2.15  91/05/14  16:25:37  mrt
   64  *      Correcting copyright
   65  * 
   66  * Revision 2.14  91/05/13  06:02:51  af
   67  *      Made code under CMUCS standard.
   68  *      [91/05/12  15:50:10  af]
   69  * 
   70  * Revision 2.13  91/03/16  14:46:38  rpd
   71  *      Updated for new kmem_alloc interface.
   72  *      [91/03/03            rpd]
   73  *      Changed net_filter to net_packet.
   74  *      [91/01/15            rpd]
   75  * 
   76  * Revision 2.12  91/02/14  14:43:03  mrt
   77  *      You must check RBD_SW_EOF for rbd chain termination, a link of 0xffff
   78  *      does not work.  Also we've just seen a status of 0xffff in rcv() with
   79  *      a bad fd_p->link_offset; we'll now reset.
   80  *      [91/01/17            rvb]
   81  * 
   82  * Revision 2.11  91/02/05  17:18:19  mrt
   83  *      Changed to new Mach copyright
   84  *      [91/02/01  17:44:30  mrt]
   85  * 
   86  * Revision 2.10  91/01/08  15:11:45  rpd
   87  *      Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
   88  *      [91/01/05            rpd]
   89  * 
   90  * Revision 1.8.1.11  90/12/07  22:53:44  rvb
   91  *      Fix a few problems if your hardware goes haywire.
   92  *      Noted by Ali.
   93  *      [90/12/11            rvb]
   94  * 
   95  * Revision 2.9  90/12/20  16:38:09  jeffreyh
   96  *      Changes for __STDC__
   97  *      [90/12/07            jeffreyh]
   98  * 
   99  * Revision 1.8.1.12  91/01/06  22:11:54  rvb
  100  *      Try try again to get the ram_to_ptr problem in requeue.
  101  *      [90/11/29            rvb]
  102  * 
  103  * Revision 2.8  90/11/26  14:49:59  rvb
  104  *      jsb bet me to XMK34, sigh ...
  105  *      [90/11/26            rvb]
  106  *      Synched 2.5 & 3.0 at I386q (r1.8.1.10) & XMK35 (r2.8)
  107  *      [90/11/15            rvb]
  108  * 
  109  * Revision 2.7  90/11/05  14:28:11  rpd
  110  *      Convert for pure kernel
  111  *      [90/11/02            rvb]
  112  * 
  113  *      Init scb and reset as per spec.  Use bcopy16 vs pc586copy as per spec.
  114  *      Accumulate counters at hwrst.  Add counters everywhere.
  115  *      Editing and style and consistency cleanup.
  116  *      Flush NOP's: this required major mods to hwrst and everything it
  117  *      called -- testing OK is not correct if the command is not COMPLETE.
  118  *      Lot's of code clean up in xmt, rcv, reqfd.
  119  *      Flush pc_softc_t "address" and pc586ehcpy.
  120  *      Handle loopback of our ownbroadcast.
  121  *      The rcv and xmt loops have been rewriten not copy sram
  122  *      to the t_packet buffer.  This yields a teriffic thruput
  123  *      improvement.
  124  *      Add Notes and sram map.
  125  *      [90/09/28            rvb]
  126  * 
  127  * Revision 1.8.1.9  90/09/18  08:39:03  rvb
  128  *      Debugging printout to find shutdown reason.
  129  *      [90/09/14            rvb]
  130  * 
  131  * Revision 1.8.1.8  90/08/25  15:44:14  rvb
  132  *      Use take_<>_irq() vs direct manipulations of ivect and friends.
  133  *      [90/08/20            rvb]
  134  * 
  135  *      Fix DSF_RUNNING.  Some more cleanup.
  136  *      [90/08/14            rvb]
  137  * 
  138  * Revision 1.8.1.7  90/07/27  11:26:06  rvb
  139  *      Fix Intel Copyright as per B. Davies authorization.
  140  *      [90/07/27            rvb]
  141  * 
  142  * Revision 1.8.1.6  90/07/10  11:43:44  rvb
  143  *      New style probe/attach.
  144  *      [90/06/15            rvb]
  145  * 
  146  * Revision 2.4  90/06/02  14:49:13  rpd
  147  *      Converted to new IPC.
  148  *      [90/06/01            rpd]
  149  * 
  150  * Revision 2.3  90/05/29  18:48:51  rwd
  151  *      Test for next_rbd_offset NULL instead of RBD_SW_EOF in
  152  *      pc586reqfd.  I don't know why this is needed on the pure kernel
  153  *      but not in the mainline - our slower device interface triggers a
  154  *      race?
  155  *      [90/05/25            dbg]
  156  * 
  157  * Revision 2.2  90/05/03  15:44:10  dbg
  158  *      Check whether device exists on open.
  159  *      [90/05/02            dbg]
  160  *      MACH_KERNEL conversion.
  161  *      [90/04/23            dbg]
  162  * 
  163  * Revision 1.8.1.5  90/03/16  18:15:26  rvb
  164  *      Clean up the i386_dev/i386_ctlr confusion.
  165  *      [90/03/15            rvb]
  166  * 
  167  * Revision 1.8.1.4  90/02/28  15:49:46  rvb
  168  *      Fix numerous typo's in Olivetti disclaimer.
  169  *      Revision 1.10  90/02/07  11:29:37  [eugene]
  170  *      expanded NOP's and loops to allow for faster machines
  171  * 
  172  * Revision 1.8.1.3  90/01/08  13:31:17  rvb
  173  *      Add Intel copyright.
  174  *      Add Olivetti copyright.
  175  *      [90/01/08            rvb]
  176  * 
  177  * Revision 1.8.1.2  89/11/10  09:52:15  rvb
  178  *      Revision 1.7  89/10/31  16:05:45  eugene
  179  *      added changes for new include files
  180  * 
  181  * Revision 1.7  89/10/31  16:05:45  eugene
  182  * added changes for new include files
  183  * 
  184  * Revision 1.6  89/10/02  10:32:04  eugene
  185  * got the previous change correct
  186  * 
  187  * Revision 1.8  89/09/20  17:28:33  rvb
  188  *      Revision 1.3  89/08/01  11:17:32  eugene
  189  *      Fixed ethernet driver hang on 25Mhz machines
  190  * 
  191  * Revision 1.7  89/08/08  21:46:46  jsb
  192  *      Just count overruns and do not print anything.
  193  *      [89/08/03            rvb]
  194  * 
  195  * Revision 1.6  89/07/17  10:40:38  rvb
  196  *      Olivetti Changes to X79 upto 5/12/89:
  197  *              & Fixed reseting when RNR is detected.
  198  *      [89/07/11            rvb]
  199  * 
  200  * Revision 1.5  89/04/05  13:00:53  rvb
  201  *      Moved "softc" structure from .h to here and some cleanup
  202  *      [89/03/07            rvb]
  203  * 
  204  *      made ac_t and scb_t volatile pointers for gcc.
  205  *      [89/03/07            rvb]
  206  * 
  207  *      collapse pack_u_long_t for gcc.
  208  *      [89/03/06            rvb]
  209  * 
  210  * Revision 1.4  89/03/09  20:06:01  rpd
  211  *      More cleanup.
  212  * 
  213  * Revision 1.3  89/02/26  12:42:12  gm0w
  214  *      Changes for cleanup.
  215  * 
  216  */
  217 
  218 /* 
  219  *      Olivetti PC586 Mach Ethernet driver v1.0
  220  *      Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
  221  *      All rights reserved.
  222  *
  223  */ 
  224 
  225 /*
  226   Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
  227 Cupertino, California.
  228 
  229                 All Rights Reserved
  230 
  231   Permission to use, copy, modify, and distribute this software and
  232 its documentation for any purpose and without fee is hereby
  233 granted, provided that the above copyright notice appears in all
  234 copies and that both the copyright notice and this permission notice
  235 appear in supporting documentation, and that the name of Olivetti
  236 not be used in advertising or publicity pertaining to distribution
  237 of the software without specific, written prior permission.
  238 
  239   OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  240 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  241 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  242 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  243 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  244 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
  245 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  246 */
  247 
  248 /*
  249   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
  250 
  251                 All Rights Reserved
  252 
  253 Permission to use, copy, modify, and distribute this software and
  254 its documentation for any purpose and without fee is hereby
  255 granted, provided that the above copyright notice appears in all
  256 copies and that both the copyright notice and this permission notice
  257 appear in supporting documentation, and that the name of Intel
  258 not be used in advertising or publicity pertaining to distribution
  259 of the software without specific, written prior permission.
  260 
  261 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  262 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  263 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  264 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  265 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  266 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  267 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  268 */
  269 
  270 /*
  271  * NOTE:
  272  *              by rvb:
  273  *  1.  The best book on the 82586 is:
  274  *              LAN Components User's Manual by Intel
  275  *      The copy I found was dated 1984.  This really tells you
  276  *      what the state machines are doing
  277  *  2.  In the current design, we only do one write at a time,
  278  *      though the hardware is capable of chaining and possibly
  279  *      even batching.  The problem is that we only make one
  280  *      transmit buffer available in sram space.
  281  *  3.  
  282  *  n.  Board Memory Map
  283         RFA/FD  0   -   227     0x228 bytes
  284                  226 = 0x19 * 0x16 bytes
  285         RBD      228 - 3813     0x35ec bytes
  286                 35e8 = 0x19 *   0x228 bytes
  287                                 == 0x0a bytes (bd) + 2 bytes + 21c bytes
  288         CU      3814 - 3913     0x100 bytes
  289         TBD     3914 - 39a3     0x90 bytes 
  290                   90 = No 18 * 0x08 bytes 
  291         TBUF    39a4 - 3fdd     0x63a bytes (= 1594(10))
  292         SCB     3fde - 3fed     0x10 bytes
  293         ISCP    3fee - 3ff5     0x08 bytes
  294         SCP     3ff6 - 3fff     0x0a bytes
  295  *              
  296  */
  297 
  298 /*
  299  * NOTE:
  300  *
  301  *      Currently this driver doesn't support trailer protocols for
  302  *      packets.  Once that is added, please remove this comment.
  303  *
  304  *      Also, some lacking material includes the DLI code.  If you
  305  *      are compiling this driver with DLI set, lookout, that code
  306  *      has not been looked at.
  307  *
  308  */
  309 
  310 #define DEBUG
  311 #define IF_CNTRS        MACH
  312 #define NDLI    0
  313 
  314 #include        <pc586.h>
  315 
  316 #ifdef  MACH_KERNEL
  317 #include        <kern/time_out.h>
  318 #include        <device/device_types.h>
  319 #include        <device/errno.h>
  320 #include        <device/io_req.h>
  321 #include        <device/if_hdr.h>
  322 #include        <device/if_ether.h>
  323 #include        <device/net_status.h>
  324 #include        <device/net_io.h>
  325 #else   MACH_KERNEL
  326 #include        <sys/param.h>
  327 #include        <mach/machine/vm_param.h>
  328 #include        <sys/systm.h>
  329 #include        <sys/mbuf.h>
  330 #include        <sys/buf.h>
  331 #include        <sys/protosw.h>
  332 #include        <sys/socket.h>
  333 #include        <sys/vmmac.h>
  334 #include        <sys/ioctl.h>
  335 #include        <sys/errno.h>
  336 #include        <sys/syslog.h>
  337 
  338 #include        <net/if.h>
  339 #include        <net/netisr.h>
  340 #include        <net/route.h>
  341 
  342 #ifdef  INET
  343 #include        <netinet/in.h>
  344 #include        <netinet/in_systm.h>
  345 #include        <netinet/in_var.h>
  346 #include        <netinet/ip.h>
  347 #include        <netinet/if_ether.h>
  348 #endif
  349 
  350 #ifdef  NS
  351 #include        <netns/ns.h>
  352 #include        <netns/ns_if.h>
  353 #endif
  354 
  355 #if     DLI
  356 #include        <net/dli_var.h>
  357 struct  dli_var de_dlv[NDE];
  358 #endif  DLI
  359 #endif  MACH_KERNEL
  360 
  361 #include        <i386/ipl.h>
  362 #include        <mach/vm_param.h>
  363 #include        <vm/vm_kern.h>
  364 #include        <chips/busses.h>
  365 #include        <i386at/if_pc586.h>
  366 
  367 #define SPLNET  spl6
  368 #if     __STDC__
  369 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y)
  370 #else   __STDC__
  371 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y)
  372 #endif  __STDC__
  373 
  374 #define pc586chatt(unit)  CMD(CHANATT, 0x0001, unit)
  375 #define pc586inton(unit)  CMD(INTENAB, CMD_1,  unit)
  376 #define pc586intoff(unit) CMD(INTENAB, CMD_0,  unit)
  377 
  378 int     pc586probe();
  379 void    pc586attach();
  380 int     pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset();
  381 int     pc586watch(), pc586rcv(), pc586xmt(), pc586bldcu();
  382 int     pc586diag(), pc586config();
  383 char    *pc586bldru();
  384 char    *ram_to_ptr();
  385 u_short ptr_to_ram();
  386 
  387 static vm_offset_t pc586_std[NPC586] = { 0 };
  388 static struct bus_device *pc586_info[NPC586];
  389 struct  bus_driver      pcdriver = 
  390         {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0};
  391 
  392 char    t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
  393 int     xmt_watch = 0;
  394 
  395 typedef struct { 
  396 #ifdef  MACH_KERNEL
  397         struct  ifnet   ds_if;          /* generic interface header */
  398         u_char  ds_addr[6];             /* Ethernet hardware address */
  399 #else   MACH_KERNEL
  400         struct  arpcom  pc586_ac;
  401 #define ds_if   pc586_ac.ac_if
  402 #define ds_addr pc586_ac.ac_enaddr
  403 #endif  MACH_KERNEL
  404         int     flags;
  405         int     seated;
  406         int     timer;
  407         int     open;
  408         fd_t    *begin_fd;
  409         fd_t    *end_fd;
  410         rbd_t   *end_rbd;
  411         char    *prom;
  412         char    *sram;
  413         int     tbusy;
  414         short   mode;
  415 } pc_softc_t;
  416 pc_softc_t      pc_softc[NPC586];
  417 
  418 struct pc586_cntrs {
  419         struct {
  420                 u_int xmt, xmti;
  421                 u_int defer;
  422                 u_int busy;
  423                 u_int sleaze, intrinsic, intrinsic_count;
  424                 u_int chain;
  425         } xmt; 
  426         struct {
  427                 u_int rcv;
  428                 u_int ovw;
  429                 u_int crc;
  430                 u_int frame;
  431                 u_int rscerrs, ovrnerrs;
  432                 u_int partial, bad_chain, fill;
  433         } rcv;
  434         u_int watch;
  435 } pc586_cntrs[NPC586];
  436 
  437 
  438 #ifdef  IF_CNTRS
  439 int pc586_narp = 1, pc586_arp = 0;
  440 int pc586_ein[32], pc586_eout[32]; 
  441 int pc586_lin[128/8], pc586_lout[128/8]; 
  442 static
  443 log_2(no)
  444 unsigned long no;
  445 {
  446         return ({ unsigned long _temp__;
  447                 asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" :
  448                     "=r" (_temp__) : "a" (no));
  449                 _temp__;});
  450 }
  451 #endif  IF_CNTRS
  452 
  453 /*
  454  * pc586probe:
  455  *
  456  *      This function "probes" or checks for the pc586 board on the bus to see
  457  *      if it is there.  As far as I can tell, the best break between this
  458  *      routine and the attach code is to simply determine whether the board
  459  *      is configured in properly.  Currently my approach to this is to write
  460  *      and read a word from the SRAM on the board being probed.  If the word
  461  *      comes back properly then we assume the board is there.  The config
  462  *      code expects to see a successful return from the probe routine before
  463  *      attach will be called.
  464  *
  465  * input        : address device is mapped to, and unit # being checked
  466  * output       : a '1' is returned if the board exists, and a 0 otherwise
  467  *
  468  */
  469 pc586probe(port, dev)
  470 struct bus_device       *dev;
  471 {
  472         caddr_t         addr = (caddr_t)dev->address;
  473         int             unit = dev->unit;
  474         int             len = round_page(0x4000);
  475         int             sram_len = round_page(0x4000);
  476         extern          vm_size_t mem_size;
  477         int             i;
  478         volatile char   *b_prom;
  479         volatile char   *b_sram;
  480         volatile u_short*t_ps;
  481 
  482         if ((unit < 0) || (unit > NPC586)) {
  483                 printf("pc%d: board out of range [0..%d]\n",
  484                         unit, NPC586);
  485                 return(0);
  486         }
  487         if (addr < (caddr_t)mem_size && addr > (caddr_t)0x100000)
  488                 return 0;
  489 
  490         if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len)
  491                                                         != KERN_SUCCESS) {
  492                 printf("pc%d: can not allocate memory for prom.\n", unit);
  493                 return 0;
  494         }
  495         if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len)
  496                                                         != KERN_SUCCESS) {
  497                 printf("pc%d: can not allocate memory for sram.\n", unit);
  498                 return 0;
  499         }
  500         (void)pmap_map(b_prom, (vm_offset_t)addr, 
  501                         (vm_offset_t)addr+len, 
  502                         VM_PROT_READ | VM_PROT_WRITE);
  503         if ((int)addr > 0x100000)                       /* stupid hardware */
  504                 addr += EXTENDED_ADDR;
  505         addr += 0x4000;                                 /* sram space */
  506         (void)pmap_map(b_sram, (vm_offset_t)addr, 
  507                         (vm_offset_t)addr+sram_len, 
  508                         VM_PROT_READ | VM_PROT_WRITE);
  509 
  510         *(b_prom + OFFSET_RESET) = 1;
  511         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
  512         *(b_prom + OFFSET_RESET) = 0;
  513         t_ps = (u_short *)(b_sram + OFFSET_SCB);
  514         *(t_ps) = (u_short)0x5a5a;
  515         if (*(t_ps) != (u_short)0x5a5a) {
  516                 kmem_free(kernel_map, b_prom, len);
  517                 kmem_free(kernel_map, b_sram, sram_len);
  518                 return(0);
  519         }
  520         t_ps = (u_short *)(b_prom +  + OFFSET_PROM);
  521 #define ETHER0 0x00
  522 #define ETHER1 0xaa
  523 #define ETHER2 0x00
  524         if ((t_ps[0]&0xff) == ETHER0 &&
  525             (t_ps[1]&0xff) == ETHER1 &&
  526             (t_ps[2]&0xff) == ETHER2)
  527                 pc_softc[unit].seated = TRUE;
  528 #undef  ETHER0
  529 #undef  ETHER1
  530 #undef  ETHER2
  531 #define ETHER0 0x00
  532 #define ETHER1 0x00
  533 #define ETHER2 0x1c
  534         if ((t_ps[0]&0xff) == ETHER0 ||
  535             (t_ps[1]&0xff) == ETHER1 ||
  536             (t_ps[2]&0xff) == ETHER2)
  537                 pc_softc[unit].seated = TRUE;
  538 #undef  ETHER0
  539 #undef  ETHER1
  540 #undef  ETHER2
  541         if (pc_softc[unit].seated != TRUE) {
  542                 kmem_free(kernel_map, b_prom, len);
  543                 kmem_free(kernel_map, b_sram, sram_len);
  544                 return(0);
  545         }
  546         (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom;
  547         (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram;
  548         return(1);
  549 }
  550 
  551 /*
  552  * pc586attach:
  553  *
  554  *      This function attaches a PC586 board to the "system".  The rest of
  555  *      runtime structures are initialized here (this routine is called after
  556  *      a successful probe of the board).  Once the ethernet address is read
  557  *      and stored, the board's ifnet structure is attached and readied.
  558  *
  559  * input        : bus_device structure setup in autoconfig
  560  * output       : board structs and ifnet is setup
  561  *
  562  */
  563 void pc586attach(dev)
  564         struct bus_device       *dev;
  565 {
  566         struct  ifnet   *ifp;
  567         u_char          *addr_p;
  568         u_short         *b_addr;
  569         u_char          unit = (u_char)dev->unit;       
  570         pc_softc_t      *sp = &pc_softc[unit];
  571         volatile scb_t  *scb_p;
  572 
  573         take_dev_irq(dev);
  574         printf(", port = %x, spl = %d, pic = %d. ",
  575                 dev->address, dev->sysdep, dev->sysdep1);
  576 
  577         sp->timer = -1;
  578         sp->flags = 0;
  579         sp->mode = 0;
  580         sp->open = 0;
  581         CMD(RESET, CMD_1, unit);
  582         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
  583         CMD(RESET, CMD_0, unit);
  584         b_addr = (u_short *)(sp->prom + OFFSET_PROM);
  585         addr_p = (u_char *)sp->ds_addr;
  586         addr_p[0] = b_addr[0];
  587         addr_p[1] = b_addr[1];
  588         addr_p[2] = b_addr[2];
  589         addr_p[3] = b_addr[3];
  590         addr_p[4] = b_addr[4];
  591         addr_p[5] = b_addr[5];
  592         printf("ethernet id [%x:%x:%x:%x:%x:%x]",
  593                 addr_p[0], addr_p[1], addr_p[2],
  594                 addr_p[3], addr_p[4], addr_p[5]);
  595 
  596         scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB);
  597         scb_p->scb_crcerrs = 0;                 /* initialize counters */
  598         scb_p->scb_alnerrs = 0;
  599         scb_p->scb_rscerrs = 0;
  600         scb_p->scb_ovrnerrs = 0;
  601 
  602         ifp = &(sp->ds_if);
  603         ifp->if_unit = unit;
  604         ifp->if_mtu = ETHERMTU;
  605         ifp->if_flags = IFF_BROADCAST;
  606 #ifdef  MACH_KERNEL
  607         ifp->if_header_size = sizeof(struct ether_header);
  608         ifp->if_header_format = HDR_ETHERNET;
  609         ifp->if_address_size = 6;
  610         ifp->if_address = (char *)&sp->ds_addr[0];
  611         if_init_queues(ifp);
  612 #else   MACH_KERNEL
  613         ifp->if_name = "pc";
  614         ifp->if_init = pc586init;
  615         ifp->if_output = pc586output;
  616         ifp->if_ioctl = pc586ioctl;
  617         ifp->if_reset = pc586reset;
  618         ifp->if_next = NULL;
  619         if_attach(ifp);
  620 #endif  MACH_KERNEL
  621 }
  622 
  623 /*
  624  * pc586reset:
  625  *
  626  *      This routine is in part an entry point for the "if" code.  Since most 
  627  *      of the actual initialization has already (we hope already) been done
  628  *      by calling pc586attach().
  629  *
  630  * input        : unit number or board number to reset
  631  * output       : board is reset
  632  *
  633  */
  634 pc586reset(unit)
  635 int     unit;
  636 {
  637         pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
  638         pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING);
  639         return(pc586init(unit));
  640 
  641 }
  642 
  643 /*
  644  * pc586init:
  645  *
  646  *      Another routine that interfaces the "if" layer to this driver.  
  647  *      Simply resets the structures that are used by "upper layers".  
  648  *      As well as calling pc586hwrst that does reset the pc586 board.
  649  *
  650  * input        : board number
  651  * output       : structures (if structs) and board are reset
  652  *
  653  */     
  654 pc586init(unit)
  655 int     unit;
  656 {
  657         struct  ifnet   *ifp;
  658         int             stat;
  659         spl_t           oldpri;
  660 
  661         ifp = &(pc_softc[unit].ds_if);
  662 #ifdef  MACH_KERNEL
  663 #else   MACH_KERNEL
  664         if (ifp->if_addrlist == (struct ifaddr *)0) {
  665                 return;
  666         }
  667 #endif  MACH_KERNEL
  668         oldpri = SPLNET();
  669         if ((stat = pc586hwrst(unit)) == TRUE) {
  670 #ifdef  MACH_KERNEL
  671 #undef  HZ
  672 #define HZ hz
  673 #endif  MACH_KERNEL
  674                 timeout(pc586watch, &(ifp->if_unit), 5*HZ);
  675                 pc_softc[unit].timer = 5;
  676 
  677                 pc_softc[unit].ds_if.if_flags |= IFF_RUNNING;
  678                 pc_softc[unit].flags |= DSF_RUNNING;
  679                 pc_softc[unit].tbusy = 0;
  680                 pc586start(unit);
  681 #if     DLI
  682                 dli_init();
  683 #endif  DLI
  684         } else
  685                 printf("pc%d init(): trouble resetting board.\n", unit);
  686         splx(oldpri);
  687         return(stat);
  688 }
  689 
  690 #ifdef  MACH_KERNEL
  691 /*ARGSUSED*/
  692 pc586open(dev, flag)
  693         dev_t   dev;
  694         int     flag;
  695 {
  696         register int    unit;
  697         pc_softc_t      *sp;
  698 
  699         unit = minor(dev);      /* XXX */
  700         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  701             return (ENXIO);
  702 
  703         pc_softc[unit].ds_if.if_flags |= IFF_UP;
  704         pc586init(unit);
  705         return (0);
  706 }
  707 #endif  MACH_KERNEL
  708 
  709 /*
  710  * pc586start:
  711  *
  712  *      This is yet another interface routine that simply tries to output a
  713  *      in an mbuf after a reset.
  714  *
  715  * input        : board number
  716  * output       : stuff sent to board if any there
  717  *
  718  */
  719 pc586start(unit)
  720 int     unit;
  721 {
  722 #ifdef  MACH_KERNEL
  723         io_req_t        m;
  724 #else   MACH_KERNEL
  725         struct  mbuf            *m;
  726 #endif  MACH_KERNEL
  727         struct  ifnet           *ifp;
  728         register pc_softc_t     *is = &pc_softc[unit];
  729         volatile scb_t          *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
  730 
  731         if (is->tbusy) {
  732                 if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */
  733                         is->tbusy = 0;
  734                         pc586_cntrs[unit].xmt.busy++;
  735                         /*
  736                          * This is probably just a race.  The xmt'r is just
  737                          * became idle but WE have masked interrupts so ...
  738                          */
  739                         if (xmt_watch) printf("!!");
  740                 } else
  741                         return;
  742         }
  743 
  744         ifp = &(pc_softc[unit].ds_if);
  745         IF_DEQUEUE(&ifp->if_snd, m);
  746 #ifdef  MACH_KERNEL
  747         if (m != 0)
  748 #else   MACH_KERNEL
  749         if (m != (struct mbuf *)0) 
  750 #endif  MACH_KERNEL
  751         {
  752                 is->tbusy++;
  753                 pc586_cntrs[unit].xmt.xmt++;
  754                 pc586xmt(unit, m);
  755         }
  756         return;
  757 }
  758 
  759 /*
  760  * pc586read:
  761  *
  762  *      This routine does the actual copy of data (including ethernet header
  763  *      structure) from the pc586 to an mbuf chain that will be passed up
  764  *      to the "if" (network interface) layer.  NOTE:  we currently
  765  *      don't handle trailer protocols, so if that is needed, it will
  766  *      (at least in part) be added here.  For simplicities sake, this
  767  *      routine copies the receive buffers from the board into a local (stack)
  768  *      buffer until the frame has been copied from the board.  Once in
  769  *      the local buffer, the contents are copied to an mbuf chain that
  770  *      is then enqueued onto the appropriate "if" queue.
  771  *
  772  * input        : board number, and an frame descriptor pointer
  773  * output       : the packet is put into an mbuf chain, and passed up
  774  * assumes      : if any errors occur, packet is "dropped on the floor"
  775  *
  776  */
  777 pc586read(unit, fd_p)
  778 int     unit;
  779 fd_t    *fd_p;
  780 {
  781         register pc_softc_t     *is = &pc_softc[unit];
  782         register struct ifnet   *ifp = &is->ds_if;
  783         struct  ether_header    eh;
  784 #ifdef  MACH_KERNEL
  785         ipc_kmsg_t      new_kmsg;
  786         struct ether_header *ehp;
  787         struct packet_header *pkt;
  788         char    *dp;
  789 #else   MACH_KERNEL
  790         struct  mbuf            *m, *tm;
  791 #endif  MACH_KERNEL
  792         rbd_t                   *rbd_p;
  793         u_char                  *buffer_p;
  794         u_char                  *mb_p;
  795         u_short                 mlen, len, clen;
  796         u_short                 bytes_in_msg, bytes_in_mbuf, bytes;
  797 
  798 
  799         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  800                 printf("pc%d read(): board is not running.\n", ifp->if_unit);
  801                 pc586intoff(ifp->if_unit);
  802         }
  803         pc586_cntrs[unit].rcv.rcv++;
  804 #ifdef  MACH_KERNEL
  805         new_kmsg = net_kmsg_get();
  806         if (new_kmsg == IKM_NULL) {
  807             /*
  808              * Drop the received packet.
  809              */
  810             is->ds_if.if_rcvdrops++;
  811 
  812             /*
  813              * not only do we want to return, we need to drop the packet on
  814              * the floor to clear the interrupt.
  815              */
  816             return 1;
  817         }
  818         ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
  819         pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]);
  820 
  821         /*
  822          * Get ether header.
  823          */
  824         ehp->ether_type = fd_p->length;
  825         len = sizeof(struct ether_header);
  826         bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE);
  827         bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE);
  828 
  829         /*
  830          * Get packet body.
  831          */
  832         dp = (char *)(pkt + 1);
  833 
  834         rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
  835         if (rbd_p == 0) {
  836             printf("pc%d read(): Invalid buffer\n", unit);
  837             if (pc586hwrst(unit) != TRUE) {
  838                 printf("pc%d read(): hwrst trouble.\n", unit);
  839             }
  840             net_kmsg_put(new_kmsg);
  841             return 0;
  842         }
  843 
  844         do {
  845             buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
  846             bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
  847             bcopy16((u_short *)buffer_p,
  848                        (u_short *)dp,
  849                        (bytes_in_msg + 1) & ~1);        /* but we know it's even */
  850             len += bytes_in_msg;
  851             dp += bytes_in_msg;
  852             if (rbd_p->status & RBD_SW_EOF)
  853                 break;
  854             rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit);
  855         } while ((int) rbd_p);
  856 
  857         pkt->type = ehp->ether_type;
  858         pkt->length =
  859                 len - sizeof(struct ether_header)
  860                     + sizeof(struct packet_header);
  861 
  862         /*
  863          * Send the packet to the network module.
  864          */
  865         net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg));
  866         return 1;
  867 #else   MACH_KERNEL
  868         eh.ether_type = ntohs(fd_p->length);
  869         bcopy16(fd_p->source, eh.ether_shost, ETHER_ADD_SIZE);
  870         bcopy16(fd_p->destination, eh.ether_dhost, ETHER_ADD_SIZE);
  871 
  872         if ((rbd_p =(rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit))== (rbd_t *)NULL) {
  873                 printf("pc%d read(): Invalid buffer\n", unit);
  874                 if (pc586hwrst(unit) != TRUE) {
  875                         printf("pc%d read(): hwrst trouble.\n", unit);
  876                 }
  877                 return 0;
  878         }
  879 
  880         bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
  881         buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
  882         MGET(m, M_DONTWAIT, MT_DATA);
  883         tm = m;
  884         if (m == (struct mbuf *)0) {
  885                 /*
  886                  * not only do we want to return, we need to drop the packet on
  887                  * the floor to clear the interrupt.
  888                  *
  889                  */
  890                 printf("pc%d read(): No mbuf 1st\n", unit);
  891                 if (pc586hwrst(unit) != TRUE) {
  892                         pc586intoff(unit);
  893                         printf("pc%d read(): hwrst trouble.\n", unit);
  894                         pc_softc[unit].timer = 0;
  895                 }
  896                 return 0;
  897         }
  898 m->m_next = (struct mbuf *) 0;
  899         m->m_len = MLEN;
  900         if (bytes_in_msg > 2 * MLEN - sizeof (struct ifnet **)) {
  901                 MCLGET(m);
  902         }
  903         /*
  904          * first mbuf in the packet must contain a pointer to the
  905          * ifnet structure.  other mbufs that follow and make up
  906          * the packet do not need this pointer in the mbuf.
  907          *
  908          */
  909         *(mtod(tm, struct ifnet **)) = ifp;
  910         mlen = sizeof (struct ifnet **);
  911         clen = mlen;
  912         bytes_in_mbuf = m->m_len - sizeof(struct ifnet **);
  913         mb_p = mtod(tm, u_char *) + sizeof (struct ifnet **);
  914         bytes = min(bytes_in_mbuf, bytes_in_msg);
  915         do {
  916                 if (bytes & 1)
  917                         len = bytes + 1;
  918                 else
  919                         len = bytes;
  920                 bcopy16(buffer_p, mb_p, len);
  921                 clen += bytes;
  922                 mlen += bytes;
  923 
  924                 if (!(bytes_in_mbuf -= bytes)) {
  925                         MGET(tm->m_next, M_DONTWAIT, MT_DATA);
  926                         tm = tm->m_next;
  927                         if (tm == (struct mbuf *)0) {
  928                                 m_freem(m);
  929                                 printf("pc%d read(): No mbuf nth\n", unit);
  930                                 if (pc586hwrst(unit) != TRUE) {
  931                                         pc586intoff(unit);
  932                                         printf("pc%d read(): hwrst trouble.\n", unit);
  933                                         pc_softc[unit].timer = 0;
  934                                 }
  935                                 return 0;
  936                         }
  937                         mlen = 0;
  938                         tm->m_len = MLEN;
  939                         bytes_in_mbuf = MLEN;
  940                         mb_p = mtod(tm, u_char *);
  941                 } else
  942                         mb_p += bytes;
  943 
  944                 if (!(bytes_in_msg  -= bytes)) {
  945                         if (rbd_p->status & RBD_SW_EOF ||
  946                             (rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit)) ==
  947                              NULL) {
  948                                 tm->m_len = mlen;
  949                                 break;
  950                         } else {
  951                                 bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
  952                                 buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
  953                         }
  954                 } else
  955                         buffer_p += bytes;
  956 
  957                 bytes = min(bytes_in_mbuf, bytes_in_msg);
  958         } while(1);
  959 #ifdef  IF_CNTRS
  960 /*      clen -= (sizeof (struct ifnet **)
  961         clen += 4 /* crc */;
  962         clen += sizeof (struct ether_header);
  963         pc586_ein[log_2(clen)]++;
  964         if (clen < 128) pc586_lin[clen>>3]++;
  965 
  966         if (eh.ether_type == ETHERTYPE_ARP) {
  967                 pc586_arp++;
  968                 if (pc586_narp) {
  969                         pc586_ein[log_2(clen)]--;
  970                         if (clen < 128) pc586_lin[clen>>3]--;
  971                 }
  972         }
  973 #endif  IF_CNTRS
  974         /*
  975          * received packet is now in a chain of mbuf's.  next step is
  976          * to pass the packet upwards.
  977          *
  978          */
  979         pc586send_packet_up(m, &eh, is);
  980         return 1;
  981 #endif  MACH_KERNEL
  982 }
  983 
  984 /*
  985  * Send a packet composed of an mbuf chain to the higher levels
  986  *
  987  */
  988 #ifndef MACH_KERNEL
  989 pc586send_packet_up(m, eh, is)
  990 struct mbuf *m;
  991 struct ether_header *eh;
  992 pc_softc_t *is;
  993 {
  994         register struct ifqueue *inq;
  995         spl_t                   opri;
  996 
  997         switch (eh->ether_type) {
  998 #ifdef INET
  999         case ETHERTYPE_IP:
 1000                 schednetisr(NETISR_IP);
 1001                 inq = &ipintrq;
 1002                 break;
 1003         case ETHERTYPE_ARP:
 1004                 arpinput(&is->pc586_ac, m);
 1005                 return;
 1006 #endif
 1007 #ifdef NS
 1008         case ETHERTYPE_NS:
 1009                 schednetisr(NETISR_NS);
 1010                 inq = &nsintrq;
 1011                 break;
 1012 #endif
 1013         default:
 1014 #if     DLI
 1015                 {
 1016                         eh.ether_type = htons(eh.ether_type);
 1017                         dli_input(m,eh.ether_type,&eh.ether_shost[0],
 1018                         &de_dlv[ds->ds_if.if_unit], &eh);
 1019                 }
 1020 #else   DLI
 1021                 m_freem(m);
 1022 #endif  DLI
 1023                 return;
 1024         }
 1025         opri = SPLNET();
 1026         if (IF_QFULL(inq)) {
 1027                 IF_DROP(inq);
 1028                 splx(opri);
 1029                 m_freem(m);
 1030                 return;
 1031         }
 1032         IF_ENQUEUE(inq, m);
 1033         splx(opri);
 1034         return;
 1035 }
 1036 #endif  MACH_KERNEL
 1037 
 1038 #ifdef  MACH_KERNEL
 1039 pc586output(dev, ior)
 1040         dev_t   dev;
 1041         io_req_t ior;
 1042 {
 1043         register int    unit;
 1044 
 1045         unit = minor(dev);      /* XXX */
 1046         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
 1047             return (ENXIO);
 1048 
 1049         return (net_write(&pc_softc[unit].ds_if, pc586start, ior));
 1050 }
 1051 
 1052 pc586setinput(dev, receive_port, priority, filter, filter_count)
 1053         dev_t           dev;
 1054         mach_port_t     receive_port;
 1055         int             priority;
 1056         filter_t        filter[];
 1057         unsigned int    filter_count;
 1058 {
 1059         register int unit = minor(dev);
 1060         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
 1061             return (ENXIO);
 1062 
 1063         return (net_set_filter(&pc_softc[unit].ds_if,
 1064                         receive_port, priority,
 1065                         filter, filter_count));
 1066 }
 1067 #else   MACH_KERNEL
 1068 /*
 1069  * pc586output:
 1070  *
 1071  *      This routine is called by the "if" layer to output a packet to
 1072  *      the network.  This code resolves the local ethernet address, and
 1073  *      puts it into the mbuf if there is room.  If not, then a new mbuf
 1074  *      is allocated with the header information and precedes the data
 1075  *      to be transmitted.  The routines that actually transmit the
 1076  *      data (pc586xmt()) expect the ethernet structure to precede
 1077  *      the data in the mbuf.  This information is required by the
 1078  *      82586's transfer command segment, and thus mbuf's cannot
 1079  *      be simply "slammed" out onto the network.
 1080  *
 1081  * input:       ifnet structure pointer, an mbuf with data, and address
 1082  *              to be resolved
 1083  * output:      mbuf is updated to hold enet address, or a new mbuf
 1084  *              with the address is added
 1085  *
 1086  */
 1087 pc586output(ifp, m0, dst)
 1088 struct ifnet    *ifp;
 1089 struct mbuf     *m0;
 1090 struct sockaddr *dst;
 1091 {
 1092         register pc_softc_t             *is = &pc_softc[ifp->if_unit];
 1093         register struct mbuf            *m = m0;
 1094         int                             type, error;
 1095         spl_t                           opri;
 1096         u_char                          edst[6];
 1097         struct in_addr                  idst;
 1098         register struct ether_header    *eh;
 1099         register int                    off;
 1100         int                             usetrailers;
 1101 
 1102         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
 1103                 printf("pc%d output(): board is not running.\n", ifp->if_unit);
 1104                 pc586intoff(ifp->if_unit);
 1105                 error = ENETDOWN;
 1106                 goto bad;
 1107         }
 1108         switch (dst->sa_family) {
 1109 
 1110 #ifdef INET
 1111         case AF_INET:
 1112                 idst = ((struct sockaddr_in *)dst)->sin_addr;
 1113                 if (!arpresolve(&is->pc586_ac, m, &idst, edst, &usetrailers)){
 1114                         return (0);     /* if not yet resolved */
 1115                 }
 1116                 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
 1117 
 1118                 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
 1119                     m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
 1120                         type = ETHERTYPE_TRAIL + (off>>9);
 1121                         m->m_off -= 2 * sizeof (u_short);
 1122                         m->m_len += 2 * sizeof (u_short);
 1123                         *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
 1124                         *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
 1125                         goto gottrailertype;
 1126                 }
 1127                 type = ETHERTYPE_IP;
 1128                 off = 0;
 1129                 goto gottype;
 1130 #endif
 1131 #ifdef NS
 1132         case AF_NS:
 1133                 type = ETHERTYPE_NS;
 1134                 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
 1135                 (caddr_t)edst, sizeof (edst));
 1136                 off = 0;
 1137                 goto gottype;
 1138 #endif
 1139 
 1140 #if     DLI
 1141         case AF_DLI:
 1142                 if (m->m_len < sizeof(struct ether_header))
 1143                 {
 1144                         error = EMSGSIZE;
 1145                         goto bad;
 1146                 }
 1147                 eh = mtod(m, struct ether_header *);
 1148                 bcopy(dst->sa_data, (caddr_t)eh->ether_dhost, 
 1149                                                 sizeof (eh->ether_dhost));
 1150                 goto gotheader;
 1151 #endif  DLI
 1152 
 1153         case AF_UNSPEC:
 1154                 eh = (struct ether_header *)dst->sa_data;
 1155                 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
 1156                 type = eh->ether_type;
 1157                 goto gottype;
 1158 
 1159         default:
 1160                 printf("pc%d output(): can't handle af%d\n",
 1161                         ifp->if_unit, dst->sa_family);
 1162                 error = EAFNOSUPPORT;
 1163                 goto bad;
 1164         }
 1165 
 1166 gottrailertype:
 1167         /*
 1168          * Packet to be sent as trailer: move first packet
 1169          * (control information) to end of chain.
 1170          */
 1171         while (m->m_next)
 1172                 m = m->m_next;
 1173         m->m_next = m0;
 1174         m = m0->m_next;
 1175         m0->m_next = 0;
 1176         m0 = m;
 1177 
 1178 gottype:
 1179         /*
 1180          * Add local net header.  If no space in first mbuf,
 1181          * allocate another.
 1182          */
 1183         if (m->m_off > MMAXOFF ||
 1184             MMINOFF + sizeof (struct ether_header) > m->m_off) {
 1185                 m = m_get(M_DONTWAIT, MT_HEADER);
 1186                 if (m == 0) {
 1187                         error = ENOBUFS;
 1188                         goto bad;
 1189                 }
 1190                 m->m_next = m0;
 1191                 m->m_off = MMINOFF;
 1192                 m->m_len = sizeof (struct ether_header);
 1193         } else {
 1194                 m->m_off -= sizeof (struct ether_header);
 1195                 m->m_len += sizeof (struct ether_header);
 1196         }
 1197         eh = mtod(m, struct ether_header *);
 1198         eh->ether_type = htons((u_short)type);
 1199         bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
 1200         bcopy((caddr_t)is->ds_addr,(caddr_t)eh->ether_shost, sizeof(edst));
 1201 #if     DLI
 1202 gotheader:
 1203 #endif  DLI
 1204 
 1205         /*
 1206          * Queue message on interface, and start output if interface
 1207          * not yet active.
 1208          */
 1209         opri = SPLNET();
 1210         if (IF_QFULL(&ifp->if_snd)) {
 1211                 IF_DROP(&ifp->if_snd);
 1212                 splx(opri);
 1213                 m_freem(m);
 1214                 return (ENOBUFS);
 1215         }
 1216         IF_ENQUEUE(&ifp->if_snd, m);
 1217         /*
 1218          * Some action needs to be added here for checking whether the
 1219          * board is already transmitting.  If it is, we don't want to
 1220          * start it up (ie call pc586start()).  We will attempt to send
 1221          * packets that are queued up after an interrupt occurs.  Some
 1222          * flag checking action has to happen here and/or in the start
 1223          * routine.  This note is here to remind me that some thought
 1224          * is needed and there is a potential problem here.
 1225          *
 1226          */
 1227         pc586start(ifp->if_unit);
 1228         splx(opri);
 1229         return (0);
 1230 bad:
 1231         m_freem(m0);
 1232         return (error);
 1233 }
 1234 #endif  MACH_KERNEL
 1235 
 1236 #ifdef  MACH_KERNEL
 1237 pc586getstat(dev, flavor, status, count)
 1238         dev_t   dev;
 1239         int     flavor;
 1240         dev_status_t    status;         /* pointer to OUT array */
 1241         unsigned int    *count;         /* out */
 1242 {
 1243         register int    unit = minor(dev);
 1244         register pc_softc_t     *sp;
 1245 
 1246         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
 1247             return (ENXIO);
 1248 
 1249         sp = &pc_softc[unit];
 1250         return (net_getstat(&sp->ds_if, flavor, status, count));
 1251 }
 1252 
 1253 pc586setstat(dev, flavor, status, count)
 1254         dev_t   dev;
 1255         int     flavor;
 1256         dev_status_t    status;
 1257         unsigned int    count;
 1258 {
 1259         register int    unit = minor(dev);
 1260         register pc_softc_t     *sp;
 1261 
 1262         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
 1263             return (ENXIO);
 1264 
 1265         sp = &pc_softc[unit];
 1266 
 1267         switch (flavor) {
 1268             case NET_STATUS:
 1269             {
 1270                 /*
 1271                  * All we can change are flags, and not many of those.
 1272                  */
 1273                 register struct net_status *ns = (struct net_status *)status;
 1274                 int     mode = 0;
 1275 
 1276                 if (count < NET_STATUS_COUNT)
 1277                     return (D_INVALID_OPERATION);
 1278 
 1279                 if (ns->flags & IFF_ALLMULTI)
 1280                     mode |= MOD_ENAL;
 1281                 if (ns->flags & IFF_PROMISC)
 1282                     mode |= MOD_PROM;
 1283 
 1284                 /*
 1285                  * Force a complete reset if the receive mode changes
 1286                  * so that these take effect immediately.
 1287                  */
 1288                 if (sp->mode != mode) {
 1289                     sp->mode = mode;
 1290                     if (sp->flags & DSF_RUNNING) {
 1291                         sp->flags &= ~(DSF_LOCK|DSF_RUNNING);
 1292                         pc586init(unit);
 1293                     }
 1294                 }
 1295                 break;
 1296             }
 1297 
 1298             default:
 1299                 return (D_INVALID_OPERATION);
 1300         }
 1301         return (D_SUCCESS);
 1302 
 1303 }
 1304 #else   MACH_KERNEL
 1305 /*
 1306  * pc586ioctl:
 1307  *
 1308  *      This routine processes an ioctl request from the "if" layer
 1309  *      above.
 1310  *
 1311  * input        : pointer the appropriate "if" struct, command, and data
 1312  * output       : based on command appropriate action is taken on the
 1313  *                pc586 board(s) or related structures
 1314  * return       : error is returned containing exit conditions
 1315  *
 1316  */
 1317 pc586ioctl(ifp, cmd, data)
 1318 struct ifnet    *ifp;
 1319 int     cmd;
 1320 caddr_t data;
 1321 {
 1322         register struct ifaddr  *ifa = (struct ifaddr *)data;
 1323         int                     unit = ifp->if_unit;
 1324         register pc_softc_t     *is = &pc_softc[unit];
 1325         short                   mode = 0;
 1326         int                     error = 0;
 1327         spl_t                   opri;
 1328 
 1329         opri = SPLNET();
 1330         switch (cmd) {
 1331         case SIOCSIFADDR:
 1332                 ifp->if_flags |= IFF_UP;
 1333                 pc586init(unit);
 1334                 switch (ifa->ifa_addr.sa_family) {
 1335 #ifdef INET
 1336                 case AF_INET:
 1337                         ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
 1338                         arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
 1339                         break;
 1340 #endif
 1341 #ifdef NS
 1342                 case AF_NS:
 1343                         {
 1344                         register struct ns_addr *ina = 
 1345                         &(IA_SNS(ifa)->sns_addr);
 1346                         if (ns_nullhost(*ina))
 1347                                 ina->x_host = *(union ns_host *)(ds->ds_addr);
 1348                         else
 1349                                 pc586setaddr(ina->x_host.c_host, unit);
 1350                         break;
 1351                         }
 1352 #endif
 1353                 }
 1354                 break;
 1355         case SIOCSIFFLAGS:
 1356                 if (ifp->if_flags & IFF_ALLMULTI)
 1357                         mode |= MOD_ENAL;
 1358                 if (ifp->if_flags & IFF_PROMISC)
 1359                         mode |= MOD_PROM;
 1360                 /*
 1361                  * force a complete reset if the receive multicast/
 1362                  * promiscuous mode changes so that these take 
 1363                  * effect immediately.
 1364                  *
 1365                  */
 1366                 if (is->mode != mode) {
 1367                         is->mode = mode;
 1368                         if (is->flags & DSF_RUNNING) {
 1369                                 is->flags &= ~(DSF_LOCK|DSF_RUNNING);
 1370                                 pc586init(unit);
 1371                         }
 1372                 }
 1373                 if ((ifp->if_flags & IFF_UP) == 0 && is->flags & DSF_RUNNING) {
 1374                         printf("pc%d ioctl(): board is not running\n", unit);
 1375                         is->flags &= ~(DSF_LOCK | DSF_RUNNING);
 1376                         is->timer = -1;
 1377                         pc586intoff(unit);
 1378                 } else if (ifp->if_flags & IFF_UP && (is->flags & DSF_RUNNING) == 0) {
 1379                         pc586init(unit);
 1380                 }
 1381                 break;
 1382 #ifdef  IF_CNTRS
 1383         case SIOCCIFCNTRS:
 1384                 if (!suser()) {
 1385                         error = EPERM;
 1386                         break;
 1387                 }
 1388                 bzero((caddr_t)pc586_ein, sizeof (pc586_ein));
 1389                 bzero((caddr_t)pc586_eout, sizeof (pc586_eout));
 1390                 bzero((caddr_t)pc586_lin, sizeof (pc586_lin));
 1391                 bzero((caddr_t)pc586_lout, sizeof (pc586_lout));
 1392                 bzero((caddr_t)&pc586_arp, sizeof (int));
 1393                 bzero((caddr_t)&pc586_cntrs, sizeof (pc586_cntrs));
 1394                 break;
 1395 #endif  IF_CNTRS
 1396         default:
 1397                 error = EINVAL;
 1398         }
 1399         splx(opri);
 1400         return (error);
 1401 }
 1402 #endif  MACH_KERNEL
 1403 
 1404 /*
 1405  * pc586hwrst:
 1406  *
 1407  *      This routine resets the pc586 board that corresponds to the 
 1408  *      board number passed in.
 1409  *
 1410  * input        : board number to do a hardware reset
 1411  * output       : board is reset
 1412  *
 1413  */
 1414 pc586hwrst(unit)
 1415 int unit;
 1416 {
 1417         CMD(CHANATT, CMD_0, unit);
 1418         CMD(RESET, CMD_1, unit);
 1419         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
 1420         CMD(RESET,CMD_0, unit);
 1421 
 1422 /*
 1423  *      for (i = 0; i < 1000000; i++); 
 1424  *      with this loop above and with the reset toggle also looping to
 1425  *      1000000.  We don't see the reset behaving as advertised.  DOES
 1426  *      IT HAPPEN AT ALL.  In particular, NORMODE, ENABLE, and XFER
 1427  *      should all be zero and they have not changed at all.
 1428  */
 1429         CMD(INTENAB, CMD_0, unit);
 1430         CMD(NORMMODE, CMD_0, unit);
 1431         CMD(XFERMODE, CMD_1, unit);
 1432 
 1433         pc586bldcu(unit);
 1434 
 1435         if (pc586diag(unit) == FALSE)
 1436                 return(FALSE);
 1437 
 1438         if (pc586config(unit) == FALSE)
 1439                 return(FALSE);
 1440         /* 
 1441          * insert code for loopback test here
 1442          *
 1443          */
 1444         pc586rustrt(unit);
 1445 
 1446         pc586inton(unit);
 1447         CMD(NORMMODE, CMD_1, unit);
 1448         return(TRUE);
 1449 }
 1450 
 1451 /*
 1452  * pc586watch():
 1453  *
 1454  *      This routine is the watchdog timer routine for the pc586 chip.  If
 1455  *      chip wedges, this routine will fire and cause a board reset and
 1456  *      begin again.
 1457  *
 1458  * input        : which board is timing out
 1459  * output       : potential board reset if wedged
 1460  *
 1461  */
 1462 int watch_dead = 0;
 1463 pc586watch(b_ptr)
 1464 caddr_t b_ptr;
 1465 {
 1466         spl_t   opri;
 1467         int     unit = *b_ptr;
 1468 
 1469         if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0)  {
 1470                 return;
 1471         }
 1472         if (pc_softc[unit].timer == -1) {
 1473                 timeout(pc586watch, b_ptr, 5*HZ);
 1474                 return;
 1475         }
 1476         if (--pc_softc[unit].timer != -1) {
 1477                 timeout(pc586watch, b_ptr, 1*HZ);
 1478                 return;
 1479         }
 1480 
 1481         opri = SPLNET();
 1482 #ifdef  notdef
 1483         printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead);
 1484 #endif  notdef
 1485         pc586_cntrs[unit].watch++;
 1486         if (pc586hwrst(unit) != TRUE) {
 1487                 printf("pc%d watch(): hwrst trouble.\n", unit);
 1488                 pc_softc[unit].timer = 0;
 1489         } else {
 1490                 timeout(pc586watch, b_ptr, 1*HZ);
 1491                 pc_softc[unit].timer = 5;
 1492         }
 1493         splx(opri);
 1494 }
 1495 
 1496 /*
 1497  * pc586intr:
 1498  *
 1499  *      This function is the interrupt handler for the pc586 ethernet
 1500  *      board.  This routine will be called whenever either a packet
 1501  *      is received, or a packet has successfully been transfered and
 1502  *      the unit is ready to transmit another packet.
 1503  *
 1504  * input        : board number that interrupted
 1505  * output       : either a packet is received, or a packet is transfered
 1506  *
 1507  */
 1508 pc586intr(unit)
 1509 int unit;
 1510 {
 1511         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1512         volatile ac_t   *cb_p  = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
 1513         int             next, x;
 1514         int             i;
 1515         u_short         int_type;
 1516 
 1517         if (pc_softc[unit].seated == FALSE) { 
 1518                 printf("pc%d intr(): board not seated\n", unit);
 1519                 return(-1);
 1520         }
 1521 
 1522         while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) {
 1523                 pc586ack(unit);
 1524                 if (int_type & SCB_SW_FR) {
 1525                         pc586rcv(unit);
 1526                         watch_dead=0;
 1527                 }
 1528                 if (int_type & SCB_SW_RNR) {
 1529                         pc586_cntrs[unit].rcv.ovw++;
 1530 #ifdef  notdef
 1531                         printf("pc%d intr(): receiver overrun! begin_fd = %x\n",
 1532                                 unit, pc_softc[unit].begin_fd);
 1533 #endif  notdef
 1534                         pc586rustrt(unit);
 1535                 }
 1536                 if (int_type & SCB_SW_CNA) {
 1537                         /*
 1538                          * At present, we don't care about CNA's.  We
 1539                          * believe they are a side effect of XMT.
 1540                          */
 1541                 }
 1542                 if (int_type & SCB_SW_CX) {
 1543                         /*
 1544                          * At present, we only request Interrupt for
 1545                          * XMT.
 1546                          */
 1547                         if ((!(cb_p->ac_status & AC_SW_OK)) ||
 1548                             (cb_p->ac_status & (0xfff^TC_SQE))) {
 1549                                 if (cb_p->ac_status & TC_DEFER) {
 1550                                         if (xmt_watch) printf("DF");
 1551                                         pc586_cntrs[unit].xmt.defer++;
 1552                                 } else if (cb_p->ac_status & (TC_COLLISION|0xf)) {
 1553                                         if (xmt_watch) printf("%x",cb_p->ac_status & 0xf);
 1554                                 } else if (xmt_watch) 
 1555                                         printf("pc%d XMT: %x %x\n",
 1556                                                 unit, cb_p->ac_status, cb_p->ac_command);
 1557                         }
 1558                         pc586_cntrs[unit].xmt.xmti++;
 1559                         pc_softc[unit].tbusy = 0;
 1560                         pc586start(unit);
 1561                 }
 1562                 pc_softc[unit].timer = 5;
 1563         }
 1564         return(0);
 1565 }
 1566 
 1567 /*
 1568  * pc586rcv:
 1569  *
 1570  *      This routine is called by the interrupt handler to initiate a
 1571  *      packet transfer from the board to the "if" layer above this
 1572  *      driver.  This routine checks if a buffer has been successfully
 1573  *      received by the pc586.  If so, the routine pc586read is called
 1574  *      to do the actual transfer of the board data (including the
 1575  *      ethernet header) into a packet (consisting of an mbuf chain).
 1576  *
 1577  * input        : number of the board to check
 1578  * output       : if a packet is available, it is "sent up"
 1579  *
 1580  */
 1581 pc586rcv(unit)
 1582 int     unit;
 1583 {
 1584         fd_t    *fd_p;
 1585 
 1586         for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL;
 1587              fd_p = pc_softc[unit].begin_fd) {
 1588                 if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) {
 1589                         if (pc586hwrst(unit) != TRUE)
 1590                                 printf("pc%d rcv(): hwrst ffff trouble.\n",
 1591                                         unit);
 1592                         return;
 1593                 } else if (fd_p->status & AC_SW_C) {
 1594                         fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit);
 1595 
 1596                         if (fd_p->status == (RFD_DONE|RFD_RSC)) {
 1597                                         /* lost one */;
 1598 #ifdef  notdef
 1599                                 printf("pc%d RCV: RSC %x\n",
 1600                                         unit, fd_p->status);
 1601 #endif  notdef
 1602                                 pc586_cntrs[unit].rcv.partial++;
 1603                         } else if (!(fd_p->status & RFD_OK))
 1604                                 printf("pc%d RCV: !OK %x\n",
 1605                                         unit, fd_p->status);
 1606                         else if (fd_p->status & 0xfff)
 1607                                 printf("pc%d RCV: ERRs %x\n",
 1608                                         unit, fd_p->status);
 1609                         else
 1610                                 if (!pc586read(unit, fd_p))
 1611                                         return;
 1612                         if (!pc586requeue(unit, fd_p)) {        /* abort on chain error */
 1613                                 if (pc586hwrst(unit) != TRUE)
 1614                                         printf("pc%d rcv(): hwrst trouble.\n", unit);
 1615                                 return;
 1616                         }
 1617                         pc_softc[unit].begin_fd = bfd;
 1618                 } else
 1619                         break;
 1620         }
 1621         return;
 1622 }
 1623 
 1624 /*
 1625  * pc586requeue:
 1626  *
 1627  *      This routine puts rbd's used in the last receive back onto the
 1628  *      free list for the next receive.
 1629  *
 1630  */
 1631 pc586requeue(unit, fd_p)
 1632 int     unit;
 1633 fd_t    *fd_p;
 1634 {
 1635         rbd_t   *l_rbdp;
 1636         rbd_t   *f_rbdp;
 1637 
 1638 #ifndef REQUEUE_DBG
 1639         if (bad_rbd_chain(fd_p->rbd_offset, unit))
 1640                 return 0;
 1641 #endif  REQUEUE_DBG
 1642         f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
 1643         if (f_rbdp != NULL) {
 1644                 l_rbdp = f_rbdp;
 1645                 while ( (!(l_rbdp->status & RBD_SW_EOF)) && 
 1646                         (l_rbdp->next_rbd_offset != 0xffff)) 
 1647                 {
 1648                         l_rbdp->status = 0;
 1649                         l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset,
 1650                                                      unit);
 1651                 }
 1652                 l_rbdp->next_rbd_offset = PC586NULL;
 1653                 l_rbdp->status = 0;
 1654                 l_rbdp->size |= AC_CW_EL;
 1655                 pc_softc[unit].end_rbd->next_rbd_offset = 
 1656                         ptr_to_ram((char *)f_rbdp, unit);
 1657                 pc_softc[unit].end_rbd->size &= ~AC_CW_EL;
 1658                 pc_softc[unit].end_rbd= l_rbdp;
 1659         }
 1660 
 1661         fd_p->status = 0;
 1662         fd_p->command = AC_CW_EL;
 1663         fd_p->link_offset = PC586NULL;
 1664         fd_p->rbd_offset = PC586NULL;
 1665 
 1666         pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit);
 1667         pc_softc[unit].end_fd->command = 0;
 1668         pc_softc[unit].end_fd = fd_p;
 1669 
 1670         return 1;
 1671 }
 1672 
 1673 /*
 1674  * pc586xmt:
 1675  *
 1676  *      This routine fills in the appropriate registers and memory
 1677  *      locations on the PC586 board and starts the board off on
 1678  *      the transmit.
 1679  *
 1680  * input        : board number of interest, and a pointer to the mbuf
 1681  * output       : board memory and registers are set for xfer and attention
 1682  *
 1683  */
 1684 #ifdef  DEBUG
 1685 int xmt_debug = 0;
 1686 #endif  DEBUG
 1687 pc586xmt(unit, m)
 1688 int     unit;
 1689 #ifdef  MACH_KERNEL
 1690 io_req_t        m;
 1691 #else   MACH_KERNEL
 1692 struct  mbuf    *m;
 1693 #endif  MACH_KERNEL
 1694 {
 1695         pc_softc_t                      *is = &pc_softc[unit];
 1696         register u_char                 *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF);
 1697         register u_short                *xmtshort_p;
 1698 #ifdef  MACH_KERNEL
 1699         register struct ether_header    *eh_p = (struct ether_header *)m->io_data;
 1700 #else   MACH_KERNEL
 1701         struct  mbuf                    *tm_p = m;
 1702         register struct ether_header    *eh_p = mtod(m, struct ether_header *);
 1703         u_char                          *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
 1704         u_short                         count = m->m_len - sizeof(struct ether_header);
 1705 #endif  MACH_KERNEL
 1706         volatile scb_t                  *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB);
 1707         volatile ac_t                   *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU);
 1708         tbd_t                           *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
 1709         u_short                         tbd = OFFSET_TBD;
 1710         u_short                         len, clen = 0;
 1711 
 1712         cb_p->ac_status = 0;
 1713         cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
 1714         cb_p->ac_link_offset = PC586NULL;
 1715         cb_p->cmd.transmit.tbd_offset = OFFSET_TBD;
 1716 
 1717         bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE);
 1718         cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type);
 1719 
 1720 #ifndef MACH_KERNEL
 1721 #ifdef  DEBUG
 1722         if (xmt_debug)
 1723                 printf("XMT    mbuf: L%d @%x ", count, mb_p);
 1724 #endif  DEBUG
 1725 #endif  MACH_KERNEL
 1726         tbd_p->act_count = 0;
 1727         tbd_p->buffer_base = 0;
 1728         tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
 1729 #ifdef  MACH_KERNEL
 1730         { int Rlen, Llen;
 1731             clen = m->io_count - sizeof(struct ether_header);
 1732             Llen = clen & 1;
 1733             Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1;
 1734 
 1735             bcopy16(m->io_data + sizeof(struct ether_header) - Rlen,
 1736                     xmtdata_p,
 1737                     clen + (Rlen + Llen) );
 1738             xmtdata_p += clen + Llen;
 1739             tbd_p->act_count = clen;
 1740             tbd_p->buffer_addr += Rlen;
 1741         }
 1742 #else   MACH_KERNEL
 1743         do {
 1744                 if (count) {
 1745                         if (clen + count > ETHERMTU)
 1746                                 break;
 1747                         if (count & 1)
 1748                                 len = count + 1;
 1749                         else
 1750                                 len = count;
 1751                         bcopy16(mb_p, xmtdata_p, len);
 1752                         clen += count;
 1753                         tbd_p->act_count += count;
 1754                         xmtdata_p += len;
 1755                         if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1756                                 break;
 1757                         if (count & 1) {
 1758                                 /* go to the next descriptor */
 1759                                 tbd_p++->next_tbd_offset = (tbd += sizeof (tbd_t));
 1760                                 tbd_p->act_count = 0;
 1761                                 tbd_p->buffer_base = 0;
 1762                                 tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
 1763                                 /* at the end -> coallesce remaining mbufs */
 1764                                 if (tbd == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
 1765                                         pc586sftwsleaze(&count, &mb_p, &tm_p, unit);
 1766                                         continue;
 1767                                 }
 1768                                 /* next mbuf short -> coallesce as needed */
 1769                                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
 1770 #define HDW_THRESHOLD 55
 1771                                       tm_p->m_len > HDW_THRESHOLD)
 1772                                         /* ok */;
 1773                                 else {
 1774                                         pc586hdwsleaze(&count, &mb_p, &tm_p, unit);
 1775                                         continue;
 1776                                 }
 1777                         }
 1778                 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1779                         break;
 1780                 count = tm_p->m_len;
 1781                 mb_p = mtod(tm_p, u_char *);
 1782 #ifdef  DEBUG
 1783                 if (xmt_debug)
 1784                         printf("mbuf+ L%d @%x ", count, mb_p);
 1785 #endif  DEBUG
 1786         } while (1);
 1787 #endif  MACH_KERNEL
 1788 #ifdef  DEBUG
 1789         if (xmt_debug)
 1790                 printf("CLEN = %d\n", clen);
 1791 #endif  DEBUG
 1792         if (clen < ETHERMIN) {
 1793                 tbd_p->act_count += ETHERMIN - clen;
 1794                 for (xmtshort_p = (u_short *)xmtdata_p;
 1795                      clen < ETHERMIN;
 1796                      clen += 2) *xmtshort_p++ = 0;
 1797         }
 1798         tbd_p->act_count |= TBD_SW_EOF;
 1799         tbd_p->next_tbd_offset = PC586NULL;
 1800 #ifdef  IF_CNTRS
 1801         clen += sizeof (struct ether_header) + 4 /* crc */;
 1802         pc586_eout[log_2(clen)]++;
 1803         if (clen < 128)  pc586_lout[clen>>3]++;
 1804 #endif  IF_CNTRS
 1805 #ifdef  DEBUG
 1806         if (xmt_debug) {
 1807                 pc586tbd(unit);
 1808                 printf("\n");
 1809         }
 1810 #endif  DEBUG
 1811 
 1812         while (scb_p->scb_command) ;
 1813         scb_p->scb_command = SCB_CU_STRT;
 1814         pc586chatt(unit);
 1815 
 1816 #ifdef  MACH_KERNEL
 1817         iodone(m);
 1818 #else   MACH_KERNEL
 1819         for (count=0; ((count < 6) && (eh_p->ether_dhost[count] == 0xff)); count++)  ;
 1820         if (count == 6) {
 1821                 pc586send_packet_up(m, eh_p, is);
 1822         } else
 1823                 m_freem(m);
 1824 #endif  MACH_KERNEL
 1825         return;
 1826 }
 1827 
 1828 /*
 1829  * pc586bldcu:
 1830  *
 1831  *      This function builds up the command unit structures.  It inits
 1832  *      the scp, iscp, scb, cb, tbd, and tbuf.
 1833  *
 1834  */
 1835 pc586bldcu(unit)
 1836 {
 1837         char            *sram = pc_softc[unit].sram;
 1838         scp_t           *scp_p = (scp_t *)(sram + OFFSET_SCP);
 1839         iscp_t          *iscp_p = (iscp_t *)(sram + OFFSET_ISCP);
 1840         volatile scb_t  *scb_p = (volatile scb_t *)(sram + OFFSET_SCB);
 1841         volatile ac_t   *cb_p = (volatile ac_t *)(sram + OFFSET_CU);
 1842         tbd_t           *tbd_p = (tbd_t *)(sram + OFFSET_TBD);
 1843         int             i;
 1844 
 1845         scp_p->scp_sysbus = 0;
 1846         scp_p->scp_iscp = OFFSET_ISCP;
 1847         scp_p->scp_iscp_base = 0;
 1848 
 1849         iscp_p->iscp_busy = 1;
 1850         iscp_p->iscp_scb_offset = OFFSET_SCB;
 1851         iscp_p->iscp_scb = 0;
 1852         iscp_p->iscp_scb_base = 0;
 1853 
 1854         pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs;
 1855         pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs;
 1856         pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs;
 1857         pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs;
 1858         scb_p->scb_status = 0;
 1859         scb_p->scb_command = 0;
 1860         scb_p->scb_cbl_offset = OFFSET_CU;
 1861         scb_p->scb_rfa_offset = OFFSET_RU;
 1862         scb_p->scb_crcerrs = 0;
 1863         scb_p->scb_alnerrs = 0;
 1864         scb_p->scb_rscerrs = 0;
 1865         scb_p->scb_ovrnerrs = 0;
 1866 
 1867         scb_p->scb_command = SCB_RESET;
 1868         pc586chatt(unit);
 1869         for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); );
 1870         if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit);
 1871         for (i = STATUS_TRIES; i-- > 0; ) {
 1872                 if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA)) 
 1873                         break;
 1874         }
 1875         if (!i)
 1876                 printf("pc%d bldcu(): not ready after reset.\n", unit);
 1877         pc586ack(unit);
 1878 
 1879         cb_p->ac_status = 0;
 1880         cb_p->ac_command = AC_CW_EL;
 1881         cb_p->ac_link_offset = OFFSET_CU;
 1882 
 1883         tbd_p->act_count = 0;
 1884         tbd_p->next_tbd_offset = PC586NULL;
 1885         tbd_p->buffer_addr = 0;
 1886         tbd_p->buffer_base = 0;
 1887         return;
 1888 }
 1889 
 1890 /*
 1891  * pc586bldru:
 1892  *
 1893  *      This function builds the linear linked lists of fd's and
 1894  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
 1895  *
 1896  */
 1897 char *
 1898 pc586bldru(unit)
 1899 int unit;
 1900 {
 1901         fd_t    *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
 1902         ru_t    *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD);
 1903         int     i;
 1904 
 1905         pc_softc[unit].begin_fd = fd_p;
 1906         for(i = 0; i < N_FD; i++, fd_p++) {
 1907                 fd_p->status = 0;
 1908                 fd_p->command   = 0;
 1909                 fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit);
 1910                 fd_p->rbd_offset = PC586NULL;
 1911         }
 1912         pc_softc[unit].end_fd = --fd_p;
 1913         fd_p->link_offset = PC586NULL;
 1914         fd_p->command = AC_CW_EL;
 1915         fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
 1916 
 1917         fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit);
 1918         for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) {
 1919                 rbd_p->r.status = 0;
 1920                 rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer),
 1921                                                    unit);
 1922                 rbd_p->r.buffer_base = 0;
 1923                 rbd_p->r.size = RCVBUFSIZE;
 1924                 if (i != N_RBD-1) {
 1925                         rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]),
 1926                                                             unit);
 1927                 } else {
 1928                         rbd_p->r.next_rbd_offset = PC586NULL;
 1929                         rbd_p->r.size |= AC_CW_EL;
 1930                         pc_softc[unit].end_rbd = (rbd_t *)rbd_p;
 1931                 }
 1932         }
 1933         return (char *)pc_softc[unit].begin_fd;
 1934 }
 1935 
 1936 /*
 1937  * pc586rustrt:
 1938  *
 1939  *      This routine starts the receive unit running.  First checks if the
 1940  *      board is actually ready, then the board is instructed to receive
 1941  *      packets again.
 1942  *
 1943  */
 1944 pc586rustrt(unit)
 1945 int unit;
 1946 {
 1947         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1948         char            *strt;
 1949 
 1950         if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY)
 1951                 return;
 1952 
 1953         strt = pc586bldru(unit);
 1954         scb_p->scb_command = SCB_RU_STRT;
 1955         scb_p->scb_rfa_offset = ptr_to_ram(strt, unit);
 1956         pc586chatt(unit);
 1957         return;
 1958 }
 1959 
 1960 /*
 1961  * pc586diag:
 1962  *
 1963  *      This routine does a 586 op-code number 7, and obtains the
 1964  *      diagnose status for the pc586.
 1965  *
 1966  */
 1967 pc586diag(unit)
 1968 int unit;
 1969 {
 1970         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1971         volatile ac_t   *cb_p  = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
 1972         int             i;
 1973 
 1974         if (scb_p->scb_status & SCB_SW_INT) {
 1975                 printf("pc%d diag(): bad initial state %\n",
 1976                         unit, scb_p->scb_status);
 1977                 pc586ack(unit);
 1978         }
 1979         cb_p->ac_status = 0;
 1980         cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL);
 1981         scb_p->scb_command = SCB_CU_STRT;
 1982         pc586chatt(unit);
 1983 
 1984         for(i = 0; i < 0xffff; i++)
 1985                 if ((cb_p->ac_status & AC_SW_C))
 1986                         break;
 1987         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 1988                 printf("pc%d: diag failed; status = %x\n",
 1989                         unit, cb_p->ac_status);
 1990                 return(FALSE);
 1991         }
 1992 
 1993         if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) )  {
 1994                 printf("pc%d diag(): bad final state %x\n",
 1995                         unit, scb_p->scb_status);
 1996                 pc586ack(unit);
 1997         }
 1998         return(TRUE);
 1999 }
 2000 
 2001 /*
 2002  * pc586config:
 2003  *
 2004  *      This routine does a standard config of the pc586 board.
 2005  *
 2006  */
 2007 pc586config(unit)
 2008 int unit;
 2009 {
 2010         volatile scb_t  *scb_p  = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 2011         volatile ac_t   *cb_p   = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
 2012         int             i;
 2013 
 2014 
 2015 /*
 2016         if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) {
 2017                 printf("pc%d config(): unexpected initial state %x\n",
 2018                         unit, scb_p->scb_status);
 2019         }
 2020 */
 2021         pc586ack(unit);
 2022 
 2023         cb_p->ac_status = 0;
 2024         cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL);
 2025 
 2026         /*
 2027          * below is the default board configuration from p2-28 from 586 book
 2028          */
 2029         cb_p->cmd.configure.fifolim_bytecnt     = 0x080c;
 2030         cb_p->cmd.configure.addrlen_mode        = 0x2600;
 2031         cb_p->cmd.configure.linprio_interframe  = 0x6000;
 2032         cb_p->cmd.configure.slot_time           = 0xf200;
 2033         cb_p->cmd.configure.hardware            = 0x0000;
 2034         cb_p->cmd.configure.min_frame_len       = 0x0040;
 2035 
 2036         scb_p->scb_command = SCB_CU_STRT;
 2037         pc586chatt(unit);
 2038 
 2039         for(i = 0; i < 0xffff; i++)
 2040                 if ((cb_p->ac_status & AC_SW_C))
 2041                         break;
 2042         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 2043                 printf("pc%d: config-configure failed; status = %x\n",
 2044                         unit, cb_p->ac_status);
 2045                 return(FALSE);
 2046         }
 2047 /*
 2048         if (scb_p->scb_status & SCB_SW_INT) {
 2049                 printf("pc%d configure(): bad configure state %x\n",
 2050                         unit, scb_p->scb_status);
 2051                 pc586ack(unit);
 2052         }
 2053 */
 2054         cb_p->ac_status = 0;
 2055         cb_p->ac_command = (AC_IASETUP|AC_CW_EL);
 2056 
 2057         bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE);
 2058 
 2059         scb_p->scb_command = SCB_CU_STRT;
 2060         pc586chatt(unit);
 2061 
 2062         for (i = 0; i < 0xffff; i++)
 2063                 if ((cb_p->ac_status & AC_SW_C))
 2064                         break;
 2065         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 2066                 printf("pc%d: config-address failed; status = %x\n",
 2067                         unit, cb_p->ac_status);
 2068                 return(FALSE);
 2069         }
 2070 /*
 2071         if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) {
 2072                 printf("pc%d configure(): unexpected final state %x\n",
 2073                         unit, scb_p->scb_status);
 2074         }
 2075 */
 2076         pc586ack(unit);
 2077 
 2078         return(TRUE);
 2079 }
 2080 
 2081 /*
 2082  * pc586ack:
 2083  */
 2084 pc586ack(unit)
 2085 {
 2086         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 2087         int i;
 2088 
 2089         if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT))
 2090                 return;
 2091         CMD(CHANATT, 0x0001, unit);
 2092         for (i = 1000000; scb_p->scb_command && (i-- > 0); );
 2093         if (!i)
 2094                 printf("pc%d pc586ack(): board not accepting command.\n", unit);
 2095 }
 2096 
 2097 char *
 2098 ram_to_ptr(offset, unit)
 2099 int unit;
 2100 u_short offset;
 2101 {
 2102         if (offset == PC586NULL)
 2103                 return(NULL);
 2104         if (offset > 0x3fff) {
 2105                 printf("ram_to_ptr(%x, %d)\n", offset, unit);
 2106                 panic("range");
 2107                 return(NULL);
 2108         }
 2109         return(pc_softc[unit].sram + offset);
 2110 }
 2111 
 2112 #ifndef REQUEUE_DBG
 2113 bad_rbd_chain(offset, unit)
 2114 {
 2115         rbd_t   *rbdp;
 2116         char    *sram = pc_softc[unit].sram;
 2117 
 2118         for (;;) {
 2119                 if (offset == PC586NULL)
 2120                         return 0;
 2121                 if (offset > 0x3fff) {
 2122                         printf("pc%d: bad_rbd_chain offset = %x\n",
 2123                                 unit, offset);
 2124                         pc586_cntrs[unit].rcv.bad_chain++;
 2125                         return 1;
 2126                 }
 2127 
 2128                 rbdp = (rbd_t *)(sram + offset);
 2129                 offset = rbdp->next_rbd_offset;
 2130         }
 2131 }
 2132 #endif  REQUEUE_DBG
 2133 
 2134 u_short
 2135 ptr_to_ram(k_va, unit)
 2136 char    *k_va;
 2137 int unit;
 2138 {
 2139         return((u_short)(k_va - pc_softc[unit].sram));
 2140 }
 2141 
 2142 pc586scb(unit)
 2143 {
 2144         volatile scb_t  *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 2145         volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE);
 2146         u_short          i;
 2147 
 2148         i = scb->scb_status;
 2149         printf("stat: stat %x, cus %x, rus %x //",
 2150                 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
 2151         i = scb->scb_command;
 2152         printf(" cmd: ack %x, cuc %x, ruc %x\n",
 2153                 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
 2154 
 2155         printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n",
 2156                 scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc,
 2157                 scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame,
 2158                 scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs,
 2159                 scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs);
 2160 
 2161         printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset);
 2162         printf(" norm %x, ena %x, xfer %x //",
 2163                 cmd[0] & 1, cmd[3] & 1, cmd[4] & 1);
 2164         printf(" atn %x, reset %x, type %x, stat %x\n",
 2165                 cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1);
 2166 }
 2167 
 2168 pc586tbd(unit)
 2169 {
 2170         pc_softc_t      *is = &pc_softc[unit];
 2171         tbd_t           *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
 2172         int             i = 0;
 2173         int             sum = 0;
 2174 
 2175         do {
 2176                 sum += (tbd_p->act_count & ~TBD_SW_EOF);
 2177                 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
 2178                         i++, tbd_p->buffer_addr,
 2179                         (tbd_p->act_count & ~TBD_SW_EOF), sum,
 2180                         tbd_p->next_tbd_offset,
 2181                         tbd_p->buffer_base);
 2182                 if (tbd_p->act_count & TBD_SW_EOF)
 2183                         break;
 2184                 tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset);
 2185         } while (1);
 2186 }
 2187 
 2188 #ifndef MACH_KERNEL
 2189 pc586hdwsleaze(countp, mb_pp, tm_pp, unit)
 2190 struct mbuf **tm_pp;
 2191 u_char **mb_pp;
 2192 u_short *countp;
 2193 {
 2194         struct mbuf     *tm_p = *tm_pp;
 2195         u_char          *mb_p = *mb_pp;
 2196         u_short         count = 0;
 2197         u_char          *cp;
 2198         int             len;
 2199 
 2200         pc586_cntrs[unit].xmt.sleaze++;
 2201         /*
 2202          * can we get a run that will be coallesced or
 2203          * that terminates before breaking
 2204          */
 2205         do {
 2206                 count += tm_p->m_len;
 2207                 if (tm_p->m_len & 1)
 2208                         break;
 2209         } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
 2210         if ( (tm_p == (struct mbuf *)0) ||
 2211               count > HDW_THRESHOLD) {
 2212                 *countp = (*tm_pp)->m_len;
 2213                 *mb_pp = mtod((*tm_pp), u_char *);
 2214                 printf("\n");
 2215                 return;
 2216         }
 2217 
 2218         /* we need to copy */
 2219         pc586_cntrs[unit].xmt.intrinsic++;
 2220         tm_p = *tm_pp;
 2221         mb_p = *mb_pp;
 2222         count = 0;
 2223         cp = (u_char *) t_packet;
 2224         do {
 2225                 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2226                 count += len;
 2227                 if (count > HDW_THRESHOLD)
 2228                         break;
 2229                 cp += len;
 2230                 if (tm_p->m_next == (struct mbuf *)0)
 2231                         break;
 2232                 tm_p = tm_p->m_next;
 2233         } while (1);
 2234         pc586_cntrs[unit].xmt.intrinsic_count += count;
 2235         *countp = count;
 2236         *mb_pp = (u_char *) t_packet;
 2237         *tm_pp = tm_p;
 2238         return;
 2239 }
 2240 
 2241 pc586sftwsleaze(countp, mb_pp, tm_pp, unit)
 2242 struct mbuf **tm_pp;
 2243 u_char **mb_pp;
 2244 u_short *countp;
 2245 {
 2246         struct mbuf     *tm_p = *tm_pp;
 2247         u_char          *mb_p = *mb_pp;
 2248         u_short         count = 0;
 2249         u_char          *cp = (u_char *) t_packet;
 2250         int             len;
 2251 
 2252         pc586_cntrs[unit].xmt.chain++;
 2253         /* we need to copy */
 2254         do {
 2255                 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2256                 count += len;
 2257                 cp += len;
 2258                 if (tm_p->m_next == (struct mbuf *)0)
 2259                         break;
 2260                 tm_p = tm_p->m_next;
 2261         } while (1);
 2262 
 2263         *countp = count;
 2264         *mb_pp = (u_char *) t_packet;
 2265         *tm_pp = tm_p;
 2266         return;
 2267 }
 2268 #endif  MACH_KERNEL

Cache object: 4bfe9403221443532dd3f3c40a03278b


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