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) 1993-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.23  93/11/17  16:48:26  dbg
   30  *      Removed non-MACH_KERNEL code.  Converted HZ to hz.
   31  *      [93/05/21            dbg]
   32  * 
   33  * Revision 2.22  93/05/10  21:19:37  rvb
   34  *      Lint.
   35  *      [93/05/08  11:21:38  af]
   36  * 
   37  * Revision 2.21  93/01/24  13:17:39  danner
   38  *      Found a pc586 with octets 0:0:1c
   39  *      [93/01/15            rvb]
   40  * 
   41  * Revision 2.20  93/01/14  17:30:55  danner
   42  *      Proper spl typing.
   43  *      [92/11/30            af]
   44  * 
   45  * Revision 2.19  92/07/09  22:54:30  rvb
   46  *      Check for pc586 signature, rather than just for writable memory.
   47  *      [92/05/18            rvb]
   48  * 
   49  * Revision 2.18  91/11/12  11:09:47  rvb
   50  *      Undo 2.16.1.1
   51  *      [91/10/25            rvb]
   52  *      Typo in transcribing the 2.5 changes missed ! before pc586read().
   53  *      Funny thing is that we did have this fixed in a branch once.
   54  *      [91/10/16            rvb]
   55  * 
   56  * Revision 2.17  91/10/07  17:25:48  af
   57  *      Add a lot of fixes/improvements from 2.5.
   58  *      [91/09/04            rvb]
   59  * 
   60  * Revision 2.16.1.1  91/09/03  17:27:39  af
   61  *      Be strict on matching the port and the device in the probe routine.
   62  *
   63  * Revision 2.16  91/08/24  11:58:12  af
   64  *      New MI autoconf.
   65  *      [91/08/02  02:54:27  af]
   66  * 
   67  * Revision 2.15  91/05/14  16:25:37  mrt
   68  *      Correcting copyright
   69  * 
   70  * Revision 2.14  91/05/13  06:02:51  af
   71  *      Made code under CMUCS standard.
   72  *      [91/05/12  15:50:10  af]
   73  * 
   74  * Revision 2.13  91/03/16  14:46:38  rpd
   75  *      Updated for new kmem_alloc interface.
   76  *      [91/03/03            rpd]
   77  *      Changed net_filter to net_packet.
   78  *      [91/01/15            rpd]
   79  * 
   80  * Revision 2.12  91/02/14  14:43:03  mrt
   81  *      You must check RBD_SW_EOF for rbd chain termination, a link of 0xffff
   82  *      does not work.  Also we've just seen a status of 0xffff in rcv() with
   83  *      a bad fd_p->link_offset; we'll now reset.
   84  *      [91/01/17            rvb]
   85  * 
   86  * Revision 2.11  91/02/05  17:18:19  mrt
   87  *      Changed to new Mach copyright
   88  *      [91/02/01  17:44:30  mrt]
   89  * 
   90  * Revision 2.10  91/01/08  15:11:45  rpd
   91  *      Changed NET_KMSG_GET, NET_KMSG_FREE to net_kmsg_get, net_kmsg_put.
   92  *      [91/01/05            rpd]
   93  * 
   94  * Revision 1.8.1.11  90/12/07  22:53:44  rvb
   95  *      Fix a few problems if your hardware goes haywire.
   96  *      Noted by Ali.
   97  *      [90/12/11            rvb]
   98  * 
   99  * Revision 2.9  90/12/20  16:38:09  jeffreyh
  100  *      Changes for __STDC__
  101  *      [90/12/07            jeffreyh]
  102  * 
  103  * Revision 1.8.1.12  91/01/06  22:11:54  rvb
  104  *      Try try again to get the ram_to_ptr problem in requeue.
  105  *      [90/11/29            rvb]
  106  * 
  107  * Revision 2.8  90/11/26  14:49:59  rvb
  108  *      jsb bet me to XMK34, sigh ...
  109  *      [90/11/26            rvb]
  110  *      Synched 2.5 & 3.0 at I386q (r1.8.1.10) & XMK35 (r2.8)
  111  *      [90/11/15            rvb]
  112  * 
  113  * Revision 2.7  90/11/05  14:28:11  rpd
  114  *      Convert for pure kernel
  115  *      [90/11/02            rvb]
  116  * 
  117  *      Init scb and reset as per spec.  Use bcopy16 vs pc586copy as per spec.
  118  *      Accumulate counters at hwrst.  Add counters everywhere.
  119  *      Editing and style and consistency cleanup.
  120  *      Flush NOP's: this required major mods to hwrst and everything it
  121  *      called -- testing OK is not correct if the command is not COMPLETE.
  122  *      Lot's of code clean up in xmt, rcv, reqfd.
  123  *      Flush pc_softc_t "address" and pc586ehcpy.
  124  *      Handle loopback of our ownbroadcast.
  125  *      The rcv and xmt loops have been rewriten not copy sram
  126  *      to the t_packet buffer.  This yields a teriffic thruput
  127  *      improvement.
  128  *      Add Notes and sram map.
  129  *      [90/09/28            rvb]
  130  * 
  131  * Revision 1.8.1.9  90/09/18  08:39:03  rvb
  132  *      Debugging printout to find shutdown reason.
  133  *      [90/09/14            rvb]
  134  * 
  135  * Revision 1.8.1.8  90/08/25  15:44:14  rvb
  136  *      Use take_<>_irq() vs direct manipulations of ivect and friends.
  137  *      [90/08/20            rvb]
  138  * 
  139  *      Fix DSF_RUNNING.  Some more cleanup.
  140  *      [90/08/14            rvb]
  141  * 
  142  * Revision 1.8.1.7  90/07/27  11:26:06  rvb
  143  *      Fix Intel Copyright as per B. Davies authorization.
  144  *      [90/07/27            rvb]
  145  * 
  146  * Revision 1.8.1.6  90/07/10  11:43:44  rvb
  147  *      New style probe/attach.
  148  *      [90/06/15            rvb]
  149  * 
  150  * Revision 2.4  90/06/02  14:49:13  rpd
  151  *      Converted to new IPC.
  152  *      [90/06/01            rpd]
  153  * 
  154  * Revision 2.3  90/05/29  18:48:51  rwd
  155  *      Test for next_rbd_offset NULL instead of RBD_SW_EOF in
  156  *      pc586reqfd.  I don't know why this is needed on the pure kernel
  157  *      but not in the mainline - our slower device interface triggers a
  158  *      race?
  159  *      [90/05/25            dbg]
  160  * 
  161  * Revision 2.2  90/05/03  15:44:10  dbg
  162  *      Check whether device exists on open.
  163  *      [90/05/02            dbg]
  164  *      MACH_KERNEL conversion.
  165  *      [90/04/23            dbg]
  166  * 
  167  * Revision 1.8.1.5  90/03/16  18:15:26  rvb
  168  *      Clean up the i386_dev/i386_ctlr confusion.
  169  *      [90/03/15            rvb]
  170  * 
  171  * Revision 1.8.1.4  90/02/28  15:49:46  rvb
  172  *      Fix numerous typo's in Olivetti disclaimer.
  173  *      Revision 1.10  90/02/07  11:29:37  [eugene]
  174  *      expanded NOP's and loops to allow for faster machines
  175  * 
  176  * Revision 1.8.1.3  90/01/08  13:31:17  rvb
  177  *      Add Intel copyright.
  178  *      Add Olivetti copyright.
  179  *      [90/01/08            rvb]
  180  * 
  181  * Revision 1.8.1.2  89/11/10  09:52:15  rvb
  182  *      Revision 1.7  89/10/31  16:05:45  eugene
  183  *      added changes for new include files
  184  * 
  185  * Revision 1.7  89/10/31  16:05:45  eugene
  186  * added changes for new include files
  187  * 
  188  * Revision 1.6  89/10/02  10:32:04  eugene
  189  * got the previous change correct
  190  * 
  191  * Revision 1.8  89/09/20  17:28:33  rvb
  192  *      Revision 1.3  89/08/01  11:17:32  eugene
  193  *      Fixed ethernet driver hang on 25Mhz machines
  194  * 
  195  * Revision 1.7  89/08/08  21:46:46  jsb
  196  *      Just count overruns and do not print anything.
  197  *      [89/08/03            rvb]
  198  * 
  199  * Revision 1.6  89/07/17  10:40:38  rvb
  200  *      Olivetti Changes to X79 upto 5/12/89:
  201  *              & Fixed reseting when RNR is detected.
  202  *      [89/07/11            rvb]
  203  * 
  204  * Revision 1.5  89/04/05  13:00:53  rvb
  205  *      Moved "softc" structure from .h to here and some cleanup
  206  *      [89/03/07            rvb]
  207  * 
  208  *      made ac_t and scb_t volatile pointers for gcc.
  209  *      [89/03/07            rvb]
  210  * 
  211  *      collapse pack_u_long_t for gcc.
  212  *      [89/03/06            rvb]
  213  * 
  214  * Revision 1.4  89/03/09  20:06:01  rpd
  215  *      More cleanup.
  216  * 
  217  * Revision 1.3  89/02/26  12:42:12  gm0w
  218  *      Changes for cleanup.
  219  * 
  220  */
  221 
  222 /* 
  223  *      Olivetti PC586 Mach Ethernet driver v1.0
  224  *      Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
  225  *      All rights reserved.
  226  *
  227  */ 
  228 
  229 /*
  230   Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
  231 Cupertino, California.
  232 
  233                 All Rights Reserved
  234 
  235   Permission to use, copy, modify, and distribute this software and
  236 its documentation for any purpose and without fee is hereby
  237 granted, provided that the above copyright notice appears in all
  238 copies and that both the copyright notice and this permission notice
  239 appear in supporting documentation, and that the name of Olivetti
  240 not be used in advertising or publicity pertaining to distribution
  241 of the software without specific, written prior permission.
  242 
  243   OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  244 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  245 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  246 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  247 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  248 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
  249 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  250 */
  251 
  252 /*
  253   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
  254 
  255                 All Rights Reserved
  256 
  257 Permission to use, copy, modify, and distribute this software and
  258 its documentation for any purpose and without fee is hereby
  259 granted, provided that the above copyright notice appears in all
  260 copies and that both the copyright notice and this permission notice
  261 appear in supporting documentation, and that the name of Intel
  262 not be used in advertising or publicity pertaining to distribution
  263 of the software without specific, written prior permission.
  264 
  265 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  266 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  267 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  268 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  269 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  270 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  271 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  272 */
  273 
  274 /*
  275  * NOTE:
  276  *              by rvb:
  277  *  1.  The best book on the 82586 is:
  278  *              LAN Components User's Manual by Intel
  279  *      The copy I found was dated 1984.  This really tells you
  280  *      what the state machines are doing
  281  *  2.  In the current design, we only do one write at a time,
  282  *      though the hardware is capable of chaining and possibly
  283  *      even batching.  The problem is that we only make one
  284  *      transmit buffer available in sram space.
  285  *  3.  
  286  *  n.  Board Memory Map
  287         RFA/FD  0   -   227     0x228 bytes
  288                  226 = 0x19 * 0x16 bytes
  289         RBD      228 - 3813     0x35ec bytes
  290                 35e8 = 0x19 *   0x228 bytes
  291                                 == 0x0a bytes (bd) + 2 bytes + 21c bytes
  292         CU      3814 - 3913     0x100 bytes
  293         TBD     3914 - 39a3     0x90 bytes 
  294                   90 = No 18 * 0x08 bytes 
  295         TBUF    39a4 - 3fdd     0x63a bytes (= 1594(10))
  296         SCB     3fde - 3fed     0x10 bytes
  297         ISCP    3fee - 3ff5     0x08 bytes
  298         SCP     3ff6 - 3fff     0x0a bytes
  299  *              
  300  */
  301 
  302 /*
  303  * NOTE:
  304  *
  305  *      Currently this driver doesn't support trailer protocols for
  306  *      packets.  Once that is added, please remove this comment.
  307  *
  308  *      Also, some lacking material includes the DLI code.  If you
  309  *      are compiling this driver with DLI set, lookout, that code
  310  *      has not been looked at.
  311  *
  312  */
  313 
  314 #define DEBUG
  315 #define IF_CNTRS        MACH
  316 #define NDLI    0
  317 
  318 #include        <pc586.h>
  319 
  320 #include        <kern/kern_io.h>
  321 #include        <kern/time_out.h>
  322 #include        <device/device_types.h>
  323 #include        <device/errno.h>
  324 #include        <device/io_req.h>
  325 #include        <device/if_hdr.h>
  326 #include        <device/if_ether.h>
  327 #include        <device/net_status.h>
  328 #include        <device/net_io.h>
  329 
  330 #include        <i386/ipl.h>
  331 #include        <mach/vm_param.h>
  332 #include        <vm/vm_kern.h>
  333 #include        <chips/busses.h>
  334 #include        <i386at/if_pc586.h>
  335 
  336 #define SPLNET  spl6
  337 #if     __STDC__
  338 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y)
  339 #else   __STDC__
  340 #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y)
  341 #endif  __STDC__
  342 
  343 #define pc586chatt(unit)  CMD(CHANATT, 0x0001, unit)
  344 #define pc586inton(unit)  CMD(INTENAB, CMD_1,  unit)
  345 #define pc586intoff(unit) CMD(INTENAB, CMD_0,  unit)
  346 
  347 int     pc586probe();
  348 void    pc586attach();
  349 int     pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset();
  350 void    pc586watch();
  351 int     pc586rcv(), pc586xmt(), pc586bldcu();
  352 int     pc586diag(), pc586config();
  353 char    *pc586bldru();
  354 char    *ram_to_ptr();
  355 u_short ptr_to_ram();
  356 void pc586start(
  357         int     unit);
  358 
  359 static vm_offset_t pc586_std[NPC586] = { 0 };
  360 static struct bus_device *pc586_info[NPC586];
  361 struct  bus_driver      pcdriver = 
  362         {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0};
  363 
  364 char    t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
  365 int     xmt_watch = 0;
  366 
  367 typedef struct { 
  368         struct  ifnet   ds_if;          /* generic interface header */
  369         u_char  ds_addr[6];             /* Ethernet hardware address */
  370         int     flags;
  371         int     seated;
  372         int     timer;
  373         int     open;
  374         fd_t    *begin_fd;
  375         fd_t    *end_fd;
  376         rbd_t   *end_rbd;
  377         char    *prom;
  378         char    *sram;
  379         int     tbusy;
  380         short   mode;
  381 } pc_softc_t;
  382 pc_softc_t      pc_softc[NPC586];
  383 
  384 struct pc586_cntrs {
  385         struct {
  386                 u_int xmt, xmti;
  387                 u_int defer;
  388                 u_int busy;
  389                 u_int sleaze, intrinsic, intrinsic_count;
  390                 u_int chain;
  391         } xmt; 
  392         struct {
  393                 u_int rcv;
  394                 u_int ovw;
  395                 u_int crc;
  396                 u_int frame;
  397                 u_int rscerrs, ovrnerrs;
  398                 u_int partial, bad_chain, fill;
  399         } rcv;
  400         u_int watch;
  401 } pc586_cntrs[NPC586];
  402 
  403 
  404 #ifdef  IF_CNTRS
  405 int pc586_narp = 1, pc586_arp = 0;
  406 int pc586_ein[32], pc586_eout[32]; 
  407 int pc586_lin[128/8], pc586_lout[128/8]; 
  408 static
  409 log_2(no)
  410 unsigned long no;
  411 {
  412         return ({ unsigned long _temp__;
  413                 asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" :
  414                     "=r" (_temp__) : "a" (no));
  415                 _temp__;});
  416 }
  417 #endif  IF_CNTRS
  418 
  419 /*
  420  * pc586probe:
  421  *
  422  *      This function "probes" or checks for the pc586 board on the bus to see
  423  *      if it is there.  As far as I can tell, the best break between this
  424  *      routine and the attach code is to simply determine whether the board
  425  *      is configured in properly.  Currently my approach to this is to write
  426  *      and read a word from the SRAM on the board being probed.  If the word
  427  *      comes back properly then we assume the board is there.  The config
  428  *      code expects to see a successful return from the probe routine before
  429  *      attach will be called.
  430  *
  431  * input        : address device is mapped to, and unit # being checked
  432  * output       : a '1' is returned if the board exists, and a 0 otherwise
  433  *
  434  */
  435 pc586probe(port, dev)
  436 struct bus_device       *dev;
  437 {
  438         caddr_t         addr = (caddr_t)dev->address;
  439         int             unit = dev->unit;
  440         int             len = round_page(0x4000);
  441         int             sram_len = round_page(0x4000);
  442         extern          vm_size_t mem_size;
  443         volatile char   *b_prom;
  444         volatile char   *b_sram;
  445         volatile u_short*t_ps;
  446 
  447         if ((unit < 0) || (unit > NPC586)) {
  448                 printf("pc%d: board out of range [0..%d]\n",
  449                         unit, NPC586);
  450                 return(0);
  451         }
  452         if (addr < (caddr_t)mem_size && addr > (caddr_t)0x100000)
  453                 return 0;
  454 
  455         if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len)
  456                                                         != KERN_SUCCESS) {
  457                 printf("pc%d: can not allocate memory for prom.\n", unit);
  458                 return 0;
  459         }
  460         if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len)
  461                                                         != KERN_SUCCESS) {
  462                 printf("pc%d: can not allocate memory for sram.\n", unit);
  463                 return 0;
  464         }
  465         (void)pmap_map(b_prom, (vm_offset_t)addr, 
  466                         (vm_offset_t)addr+len, 
  467                         VM_PROT_READ | VM_PROT_WRITE);
  468         if ((int)addr > 0x100000)                       /* stupid hardware */
  469                 addr += EXTENDED_ADDR;
  470         addr += 0x4000;                                 /* sram space */
  471         (void)pmap_map(b_sram, (vm_offset_t)addr, 
  472                         (vm_offset_t)addr+sram_len, 
  473                         VM_PROT_READ | VM_PROT_WRITE);
  474 
  475         *(b_prom + OFFSET_RESET) = 1;
  476         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
  477         *(b_prom + OFFSET_RESET) = 0;
  478         t_ps = (u_short *)(b_sram + OFFSET_SCB);
  479         *(t_ps) = (u_short)0x5a5a;
  480         if (*(t_ps) != (u_short)0x5a5a) {
  481                 kmem_free(kernel_map, (vm_offset_t) b_prom, len);
  482                 kmem_free(kernel_map, (vm_offset_t) b_sram, sram_len);
  483                 return(0);
  484         }
  485         t_ps = (u_short *)(b_prom +  + OFFSET_PROM);
  486 #define ETHER0 0x00
  487 #define ETHER1 0xaa
  488 #define ETHER2 0x00
  489         if ((t_ps[0]&0xff) == ETHER0 &&
  490             (t_ps[1]&0xff) == ETHER1 &&
  491             (t_ps[2]&0xff) == ETHER2)
  492                 pc_softc[unit].seated = TRUE;
  493 #undef  ETHER0
  494 #undef  ETHER1
  495 #undef  ETHER2
  496 #define ETHER0 0x00
  497 #define ETHER1 0x00
  498 #define ETHER2 0x1c
  499         if ((t_ps[0]&0xff) == ETHER0 ||
  500             (t_ps[1]&0xff) == ETHER1 ||
  501             (t_ps[2]&0xff) == ETHER2)
  502                 pc_softc[unit].seated = TRUE;
  503 #undef  ETHER0
  504 #undef  ETHER1
  505 #undef  ETHER2
  506         if (pc_softc[unit].seated != TRUE) {
  507                 kmem_free(kernel_map, (vm_offset_t) b_prom, len);
  508                 kmem_free(kernel_map, (vm_offset_t) b_sram, sram_len);
  509                 return(0);
  510         }
  511         (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom;
  512         (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram;
  513         return(1);
  514 }
  515 
  516 /*
  517  * pc586attach:
  518  *
  519  *      This function attaches a PC586 board to the "system".  The rest of
  520  *      runtime structures are initialized here (this routine is called after
  521  *      a successful probe of the board).  Once the ethernet address is read
  522  *      and stored, the board's ifnet structure is attached and readied.
  523  *
  524  * input        : bus_device structure setup in autoconfig
  525  * output       : board structs and ifnet is setup
  526  *
  527  */
  528 void pc586attach(dev)
  529         struct bus_device       *dev;
  530 {
  531         struct  ifnet   *ifp;
  532         u_char          *addr_p;
  533         u_short         *b_addr;
  534         u_char          unit = (u_char)dev->unit;       
  535         pc_softc_t      *sp = &pc_softc[unit];
  536         volatile scb_t  *scb_p;
  537 
  538         take_dev_irq(dev);
  539         printf(", port = %x, spl = %d, pic = %d. ",
  540                 dev->address, dev->sysdep, dev->sysdep1);
  541 
  542         sp->timer = -1;
  543         sp->flags = 0;
  544         sp->mode = 0;
  545         sp->open = 0;
  546         CMD(RESET, CMD_1, unit);
  547         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
  548         CMD(RESET, CMD_0, unit);
  549         b_addr = (u_short *)(sp->prom + OFFSET_PROM);
  550         addr_p = (u_char *)sp->ds_addr;
  551         addr_p[0] = b_addr[0];
  552         addr_p[1] = b_addr[1];
  553         addr_p[2] = b_addr[2];
  554         addr_p[3] = b_addr[3];
  555         addr_p[4] = b_addr[4];
  556         addr_p[5] = b_addr[5];
  557         printf("ethernet id [%x:%x:%x:%x:%x:%x]",
  558                 addr_p[0], addr_p[1], addr_p[2],
  559                 addr_p[3], addr_p[4], addr_p[5]);
  560 
  561         scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB);
  562         scb_p->scb_crcerrs = 0;                 /* initialize counters */
  563         scb_p->scb_alnerrs = 0;
  564         scb_p->scb_rscerrs = 0;
  565         scb_p->scb_ovrnerrs = 0;
  566 
  567         ifp = &(sp->ds_if);
  568         ifp->if_unit = unit;
  569         ifp->if_mtu = ETHERMTU;
  570         ifp->if_flags = IFF_BROADCAST;
  571         ifp->if_header_size = sizeof(struct ether_header);
  572         ifp->if_header_format = HDR_ETHERNET;
  573         ifp->if_address_size = 6;
  574         ifp->if_address = (char *)&sp->ds_addr[0];
  575         if_init_queues(ifp);
  576 }
  577 
  578 /*
  579  * pc586reset:
  580  *
  581  *      This routine is in part an entry point for the "if" code.  Since most 
  582  *      of the actual initialization has already (we hope already) been done
  583  *      by calling pc586attach().
  584  *
  585  * input        : unit number or board number to reset
  586  * output       : board is reset
  587  *
  588  */
  589 pc586reset(unit)
  590 int     unit;
  591 {
  592         pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
  593         pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING);
  594         return(pc586init(unit));
  595 
  596 }
  597 
  598 /*
  599  * pc586init:
  600  *
  601  *      Another routine that interfaces the "if" layer to this driver.  
  602  *      Simply resets the structures that are used by "upper layers".  
  603  *      As well as calling pc586hwrst that does reset the pc586 board.
  604  *
  605  * input        : board number
  606  * output       : structures (if structs) and board are reset
  607  *
  608  */     
  609 pc586init(unit)
  610 int     unit;
  611 {
  612         struct  ifnet   *ifp;
  613         int             stat;
  614         spl_t           oldpri;
  615 
  616         ifp = &(pc_softc[unit].ds_if);
  617         oldpri = SPLNET();
  618         if ((stat = pc586hwrst(unit)) == TRUE) {
  619                 timeout(pc586watch, &(ifp->if_unit), 5*hz);
  620                 pc_softc[unit].timer = 5;
  621 
  622                 pc_softc[unit].ds_if.if_flags |= IFF_RUNNING;
  623                 pc_softc[unit].flags |= DSF_RUNNING;
  624                 pc_softc[unit].tbusy = 0;
  625                 pc586start(unit);
  626 #if     DLI
  627                 dli_init();
  628 #endif  DLI
  629         } else
  630                 printf("pc%d init(): trouble resetting board.\n", unit);
  631         splx(oldpri);
  632         return(stat);
  633 }
  634 
  635 /*ARGSUSED*/
  636 io_return_t
  637 pc586open(
  638         int     unit,
  639         int     flag)
  640 {
  641         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  642             return ENXIO;
  643 
  644         pc_softc[unit].ds_if.if_flags |= IFF_UP;
  645         pc586init(unit);
  646         return 0;
  647 }
  648 
  649 /*
  650  * pc586start:
  651  *
  652  *      This is yet another interface routine that simply tries to output a
  653  *      in an mbuf after a reset.
  654  *
  655  * input        : board number
  656  * output       : stuff sent to board if any there
  657  *
  658  */
  659 void pc586start(
  660         int     unit)
  661 {
  662         io_req_t        m;
  663         struct  ifnet           *ifp;
  664         register pc_softc_t     *is = &pc_softc[unit];
  665         volatile scb_t          *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
  666 
  667         if (is->tbusy) {
  668                 if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */
  669                         is->tbusy = 0;
  670                         pc586_cntrs[unit].xmt.busy++;
  671                         /*
  672                          * This is probably just a race.  The xmt'r is just
  673                          * became idle but WE have masked interrupts so ...
  674                          */
  675                         if (xmt_watch) printf("!!");
  676                 } else
  677                         return;
  678         }
  679 
  680         ifp = &(pc_softc[unit].ds_if);
  681         IF_DEQUEUE(&ifp->if_snd, m);
  682         if (m != 0)
  683         {
  684                 is->tbusy++;
  685                 pc586_cntrs[unit].xmt.xmt++;
  686                 pc586xmt(unit, m);
  687         }
  688         return;
  689 }
  690 
  691 /*
  692  * pc586read:
  693  *
  694  *      This routine does the actual copy of data (including ethernet header
  695  *      structure) from the pc586 to an mbuf chain that will be passed up
  696  *      to the "if" (network interface) layer.  NOTE:  we currently
  697  *      don't handle trailer protocols, so if that is needed, it will
  698  *      (at least in part) be added here.  For simplicities sake, this
  699  *      routine copies the receive buffers from the board into a local (stack)
  700  *      buffer until the frame has been copied from the board.  Once in
  701  *      the local buffer, the contents are copied to an mbuf chain that
  702  *      is then enqueued onto the appropriate "if" queue.
  703  *
  704  * input        : board number, and an frame descriptor pointer
  705  * output       : the packet is put into an mbuf chain, and passed up
  706  * assumes      : if any errors occur, packet is "dropped on the floor"
  707  *
  708  */
  709 pc586read(unit, fd_p)
  710 int     unit;
  711 fd_t    *fd_p;
  712 {
  713         register pc_softc_t     *is = &pc_softc[unit];
  714         register struct ifnet   *ifp = &is->ds_if;
  715         ipc_kmsg_t      new_kmsg;
  716         struct ether_header *ehp;
  717         struct packet_header *pkt;
  718         char    *dp;
  719         rbd_t                   *rbd_p;
  720         u_char                  *buffer_p;
  721         u_short                 len;
  722         u_short                 bytes_in_msg;
  723 
  724         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  725                 printf("pc%d read(): board is not running.\n", ifp->if_unit);
  726                 pc586intoff(ifp->if_unit);
  727         }
  728         pc586_cntrs[unit].rcv.rcv++;
  729         new_kmsg = net_kmsg_get();
  730         if (new_kmsg == IKM_NULL) {
  731             /*
  732              * Drop the received packet.
  733              */
  734             is->ds_if.if_rcvdrops++;
  735 
  736             /*
  737              * not only do we want to return, we need to drop the packet on
  738              * the floor to clear the interrupt.
  739              */
  740             return 1;
  741         }
  742         ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
  743         pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]);
  744 
  745         /*
  746          * Get ether header.
  747          */
  748         ehp->ether_type = fd_p->length;
  749         len = sizeof(struct ether_header);
  750         bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE);
  751         bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE);
  752 
  753         /*
  754          * Get packet body.
  755          */
  756         dp = (char *)(pkt + 1);
  757 
  758         rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
  759         if (rbd_p == 0) {
  760             printf("pc%d read(): Invalid buffer\n", unit);
  761             if (pc586hwrst(unit) != TRUE) {
  762                 printf("pc%d read(): hwrst trouble.\n", unit);
  763             }
  764             net_kmsg_put(new_kmsg);
  765             return 0;
  766         }
  767 
  768         do {
  769             buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
  770             bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
  771             bcopy16((u_short *)buffer_p,
  772                        (u_short *)dp,
  773                        (bytes_in_msg + 1) & ~1);        /* but we know it's even */
  774             len += bytes_in_msg;
  775             dp += bytes_in_msg;
  776             if (rbd_p->status & RBD_SW_EOF)
  777                 break;
  778             rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit);
  779         } while ((int) rbd_p);
  780 
  781         pkt->type = ehp->ether_type;
  782         pkt->length =
  783                 len - sizeof(struct ether_header)
  784                     + sizeof(struct packet_header);
  785 
  786         /*
  787          * Send the packet to the network module.
  788          */
  789         net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg));
  790         return 1;
  791 }
  792 
  793 pc586output(dev, ior)
  794         dev_t   dev;
  795         io_req_t ior;
  796 {
  797         register int    unit;
  798 
  799         unit = minor(dev);      /* XXX */
  800         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  801             return ENXIO;
  802 
  803         return net_write(&pc_softc[unit].ds_if, pc586start, ior);
  804 }
  805 
  806 pc586setinput(dev, receive_port, priority, filter, filter_count)
  807         dev_t           dev;
  808         mach_port_t     receive_port;
  809         int             priority;
  810         filter_t        filter[];
  811         unsigned int    filter_count;
  812 {
  813         register int unit = minor(dev);
  814         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  815             return (ENXIO);
  816 
  817         return (net_set_filter(&pc_softc[unit].ds_if,
  818                         receive_port, priority,
  819                         filter, filter_count));
  820 }
  821 
  822 pc586getstat(dev, flavor, status, count)
  823         dev_t   dev;
  824         int     flavor;
  825         dev_status_t    status;         /* pointer to OUT array */
  826         unsigned int    *count;         /* out */
  827 {
  828         register int    unit = minor(dev);
  829         register pc_softc_t     *sp;
  830 
  831         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  832             return (ENXIO);
  833 
  834         sp = &pc_softc[unit];
  835         return (net_getstat(&sp->ds_if, flavor, status, count));
  836 }
  837 
  838 pc586setstat(dev, flavor, status, count)
  839         dev_t   dev;
  840         int     flavor;
  841         dev_status_t    status;
  842         unsigned int    count;
  843 {
  844         register int    unit = minor(dev);
  845         register pc_softc_t     *sp;
  846 
  847         if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
  848             return (ENXIO);
  849 
  850         sp = &pc_softc[unit];
  851 
  852         switch (flavor) {
  853             case NET_STATUS:
  854             {
  855                 /*
  856                  * All we can change are flags, and not many of those.
  857                  */
  858                 register struct net_status *ns = (struct net_status *)status;
  859                 int     mode = 0;
  860 
  861                 if (count < NET_STATUS_COUNT)
  862                     return (D_INVALID_OPERATION);
  863 
  864                 if (ns->flags & IFF_ALLMULTI)
  865                     mode |= MOD_ENAL;
  866                 if (ns->flags & IFF_PROMISC)
  867                     mode |= MOD_PROM;
  868 
  869                 /*
  870                  * Force a complete reset if the receive mode changes
  871                  * so that these take effect immediately.
  872                  */
  873                 if (sp->mode != mode) {
  874                     sp->mode = mode;
  875                     if (sp->flags & DSF_RUNNING) {
  876                         sp->flags &= ~(DSF_LOCK|DSF_RUNNING);
  877                         pc586init(unit);
  878                     }
  879                 }
  880                 break;
  881             }
  882 
  883             default:
  884                 return (D_INVALID_OPERATION);
  885         }
  886         return (D_SUCCESS);
  887 
  888 }
  889 
  890 /*
  891  * pc586hwrst:
  892  *
  893  *      This routine resets the pc586 board that corresponds to the 
  894  *      board number passed in.
  895  *
  896  * input        : board number to do a hardware reset
  897  * output       : board is reset
  898  *
  899  */
  900 pc586hwrst(unit)
  901 int unit;
  902 {
  903         CMD(CHANATT, CMD_0, unit);
  904         CMD(RESET, CMD_1, unit);
  905         { int i; for (i = 0; i < 1000; i++);    /* 4 clocks at 6Mhz */}
  906         CMD(RESET,CMD_0, unit);
  907 
  908 /*
  909  *      for (i = 0; i < 1000000; i++); 
  910  *      with this loop above and with the reset toggle also looping to
  911  *      1000000.  We don't see the reset behaving as advertised.  DOES
  912  *      IT HAPPEN AT ALL.  In particular, NORMODE, ENABLE, and XFER
  913  *      should all be zero and they have not changed at all.
  914  */
  915         CMD(INTENAB, CMD_0, unit);
  916         CMD(NORMMODE, CMD_0, unit);
  917         CMD(XFERMODE, CMD_1, unit);
  918 
  919         pc586bldcu(unit);
  920 
  921         if (pc586diag(unit) == FALSE)
  922                 return(FALSE);
  923 
  924         if (pc586config(unit) == FALSE)
  925                 return(FALSE);
  926         /* 
  927          * insert code for loopback test here
  928          *
  929          */
  930         pc586rustrt(unit);
  931 
  932         pc586inton(unit);
  933         CMD(NORMMODE, CMD_1, unit);
  934         return(TRUE);
  935 }
  936 
  937 /*
  938  * pc586watch():
  939  *
  940  *      This routine is the watchdog timer routine for the pc586 chip.  If
  941  *      chip wedges, this routine will fire and cause a board reset and
  942  *      begin again.
  943  *
  944  * input        : which board is timing out
  945  * output       : potential board reset if wedged
  946  *
  947  */
  948 int watch_dead = 0;
  949 void pc586watch(b_ptr)
  950 caddr_t b_ptr;
  951 {
  952         spl_t   opri;
  953         int     unit = *b_ptr;
  954 
  955         if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0)  {
  956                 return;
  957         }
  958         if (pc_softc[unit].timer == -1) {
  959                 timeout(pc586watch, b_ptr, 5*hz);
  960                 return;
  961         }
  962         if (--pc_softc[unit].timer != -1) {
  963                 timeout(pc586watch, b_ptr, 1*hz);
  964                 return;
  965         }
  966 
  967         opri = SPLNET();
  968 #ifdef  notdef
  969         printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead);
  970 #endif  notdef
  971         pc586_cntrs[unit].watch++;
  972         if (pc586hwrst(unit) != TRUE) {
  973                 printf("pc%d watch(): hwrst trouble.\n", unit);
  974                 pc_softc[unit].timer = 0;
  975         } else {
  976                 timeout(pc586watch, b_ptr, 1*hz);
  977                 pc_softc[unit].timer = 5;
  978         }
  979         splx(opri);
  980 }
  981 
  982 /*
  983  * pc586intr:
  984  *
  985  *      This function is the interrupt handler for the pc586 ethernet
  986  *      board.  This routine will be called whenever either a packet
  987  *      is received, or a packet has successfully been transfered and
  988  *      the unit is ready to transmit another packet.
  989  *
  990  * input        : board number that interrupted
  991  * output       : either a packet is received, or a packet is transfered
  992  *
  993  */
  994 pc586intr(unit)
  995 int unit;
  996 {
  997         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
  998         volatile ac_t   *cb_p  = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
  999         u_short         int_type;
 1000 
 1001         if (pc_softc[unit].seated == FALSE) { 
 1002                 printf("pc%d intr(): board not seated\n", unit);
 1003                 return(-1);
 1004         }
 1005 
 1006         while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) {
 1007                 pc586ack(unit);
 1008                 if (int_type & SCB_SW_FR) {
 1009                         pc586rcv(unit);
 1010                         watch_dead=0;
 1011                 }
 1012                 if (int_type & SCB_SW_RNR) {
 1013                         pc586_cntrs[unit].rcv.ovw++;
 1014 #ifdef  notdef
 1015                         printf("pc%d intr(): receiver overrun! begin_fd = %x\n",
 1016                                 unit, pc_softc[unit].begin_fd);
 1017 #endif  notdef
 1018                         pc586rustrt(unit);
 1019                 }
 1020                 if (int_type & SCB_SW_CNA) {
 1021                         /*
 1022                          * At present, we don't care about CNA's.  We
 1023                          * believe they are a side effect of XMT.
 1024                          */
 1025                 }
 1026                 if (int_type & SCB_SW_CX) {
 1027                         /*
 1028                          * At present, we only request Interrupt for
 1029                          * XMT.
 1030                          */
 1031                         if ((!(cb_p->ac_status & AC_SW_OK)) ||
 1032                             (cb_p->ac_status & (0xfff^TC_SQE))) {
 1033                                 if (cb_p->ac_status & TC_DEFER) {
 1034                                         if (xmt_watch) printf("DF");
 1035                                         pc586_cntrs[unit].xmt.defer++;
 1036                                 } else if (cb_p->ac_status & (TC_COLLISION|0xf)) {
 1037                                         if (xmt_watch) printf("%x",cb_p->ac_status & 0xf);
 1038                                 } else if (xmt_watch) 
 1039                                         printf("pc%d XMT: %x %x\n",
 1040                                                 unit, cb_p->ac_status, cb_p->ac_command);
 1041                         }
 1042                         pc586_cntrs[unit].xmt.xmti++;
 1043                         pc_softc[unit].tbusy = 0;
 1044                         pc586start(unit);
 1045                 }
 1046                 pc_softc[unit].timer = 5;
 1047         }
 1048         return(0);
 1049 }
 1050 
 1051 /*
 1052  * pc586rcv:
 1053  *
 1054  *      This routine is called by the interrupt handler to initiate a
 1055  *      packet transfer from the board to the "if" layer above this
 1056  *      driver.  This routine checks if a buffer has been successfully
 1057  *      received by the pc586.  If so, the routine pc586read is called
 1058  *      to do the actual transfer of the board data (including the
 1059  *      ethernet header) into a packet (consisting of an mbuf chain).
 1060  *
 1061  * input        : number of the board to check
 1062  * output       : if a packet is available, it is "sent up"
 1063  *
 1064  */
 1065 pc586rcv(unit)
 1066 int     unit;
 1067 {
 1068         fd_t    *fd_p;
 1069 
 1070         for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL;
 1071              fd_p = pc_softc[unit].begin_fd) {
 1072                 if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) {
 1073                         if (pc586hwrst(unit) != TRUE)
 1074                                 printf("pc%d rcv(): hwrst ffff trouble.\n",
 1075                                         unit);
 1076                         return;
 1077                 } else if (fd_p->status & AC_SW_C) {
 1078                         fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit);
 1079 
 1080                         if (fd_p->status == (RFD_DONE|RFD_RSC)) {
 1081                                         /* lost one */;
 1082 #ifdef  notdef
 1083                                 printf("pc%d RCV: RSC %x\n",
 1084                                         unit, fd_p->status);
 1085 #endif  notdef
 1086                                 pc586_cntrs[unit].rcv.partial++;
 1087                         } else if (!(fd_p->status & RFD_OK))
 1088                                 printf("pc%d RCV: !OK %x\n",
 1089                                         unit, fd_p->status);
 1090                         else if (fd_p->status & 0xfff)
 1091                                 printf("pc%d RCV: ERRs %x\n",
 1092                                         unit, fd_p->status);
 1093                         else
 1094                                 if (!pc586read(unit, fd_p))
 1095                                         return;
 1096                         if (!pc586requeue(unit, fd_p)) {        /* abort on chain error */
 1097                                 if (pc586hwrst(unit) != TRUE)
 1098                                         printf("pc%d rcv(): hwrst trouble.\n", unit);
 1099                                 return;
 1100                         }
 1101                         pc_softc[unit].begin_fd = bfd;
 1102                 } else
 1103                         break;
 1104         }
 1105         return;
 1106 }
 1107 
 1108 /*
 1109  * pc586requeue:
 1110  *
 1111  *      This routine puts rbd's used in the last receive back onto the
 1112  *      free list for the next receive.
 1113  *
 1114  */
 1115 pc586requeue(unit, fd_p)
 1116 int     unit;
 1117 fd_t    *fd_p;
 1118 {
 1119         rbd_t   *l_rbdp;
 1120         rbd_t   *f_rbdp;
 1121 
 1122 #ifndef REQUEUE_DBG
 1123         if (bad_rbd_chain(fd_p->rbd_offset, unit))
 1124                 return 0;
 1125 #endif  REQUEUE_DBG
 1126         f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
 1127         if (f_rbdp != NULL) {
 1128                 l_rbdp = f_rbdp;
 1129                 while ( (!(l_rbdp->status & RBD_SW_EOF)) && 
 1130                         (l_rbdp->next_rbd_offset != 0xffff)) 
 1131                 {
 1132                         l_rbdp->status = 0;
 1133                         l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset,
 1134                                                      unit);
 1135                 }
 1136                 l_rbdp->next_rbd_offset = PC586NULL;
 1137                 l_rbdp->status = 0;
 1138                 l_rbdp->size |= AC_CW_EL;
 1139                 pc_softc[unit].end_rbd->next_rbd_offset = 
 1140                         ptr_to_ram((char *)f_rbdp, unit);
 1141                 pc_softc[unit].end_rbd->size &= ~AC_CW_EL;
 1142                 pc_softc[unit].end_rbd= l_rbdp;
 1143         }
 1144 
 1145         fd_p->status = 0;
 1146         fd_p->command = AC_CW_EL;
 1147         fd_p->link_offset = PC586NULL;
 1148         fd_p->rbd_offset = PC586NULL;
 1149 
 1150         pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit);
 1151         pc_softc[unit].end_fd->command = 0;
 1152         pc_softc[unit].end_fd = fd_p;
 1153 
 1154         return 1;
 1155 }
 1156 
 1157 /*
 1158  * pc586xmt:
 1159  *
 1160  *      This routine fills in the appropriate registers and memory
 1161  *      locations on the PC586 board and starts the board off on
 1162  *      the transmit.
 1163  *
 1164  * input        : board number of interest, and a pointer to the mbuf
 1165  * output       : board memory and registers are set for xfer and attention
 1166  *
 1167  */
 1168 #ifdef  DEBUG
 1169 int xmt_debug = 0;
 1170 #endif  DEBUG
 1171 pc586xmt(unit, m)
 1172 int     unit;
 1173 io_req_t        m;
 1174 {
 1175         pc_softc_t                      *is = &pc_softc[unit];
 1176         register u_char                 *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF);
 1177         register u_short                *xmtshort_p;
 1178         register struct ether_header    *eh_p = (struct ether_header *)m->io_data;
 1179         volatile scb_t                  *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB);
 1180         volatile ac_t                   *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU);
 1181         tbd_t                           *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
 1182         u_short                         clen = 0;
 1183 
 1184         cb_p->ac_status = 0;
 1185         cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
 1186         cb_p->ac_link_offset = PC586NULL;
 1187         cb_p->cmd.transmit.tbd_offset = OFFSET_TBD;
 1188 
 1189         bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE);
 1190         cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type);
 1191 
 1192         tbd_p->act_count = 0;
 1193         tbd_p->buffer_base = 0;
 1194         tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
 1195         { int Rlen, Llen;
 1196             clen = m->io_count - sizeof(struct ether_header);
 1197             Llen = clen & 1;
 1198             Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1;
 1199 
 1200             bcopy16(m->io_data + sizeof(struct ether_header) - Rlen,
 1201                     xmtdata_p,
 1202                     clen + (Rlen + Llen) );
 1203             xmtdata_p += clen + Llen;
 1204             tbd_p->act_count = clen;
 1205             tbd_p->buffer_addr += Rlen;
 1206         }
 1207 #ifdef  DEBUG
 1208         if (xmt_debug)
 1209                 printf("CLEN = %d\n", clen);
 1210 #endif  DEBUG
 1211         if (clen < ETHERMIN) {
 1212                 tbd_p->act_count += ETHERMIN - clen;
 1213                 for (xmtshort_p = (u_short *)xmtdata_p;
 1214                      clen < ETHERMIN;
 1215                      clen += 2) *xmtshort_p++ = 0;
 1216         }
 1217         tbd_p->act_count |= TBD_SW_EOF;
 1218         tbd_p->next_tbd_offset = PC586NULL;
 1219 #ifdef  IF_CNTRS
 1220         clen += sizeof (struct ether_header) + 4 /* crc */;
 1221         pc586_eout[log_2(clen)]++;
 1222         if (clen < 128)  pc586_lout[clen>>3]++;
 1223 #endif  IF_CNTRS
 1224 #ifdef  DEBUG
 1225         if (xmt_debug) {
 1226                 pc586tbd(unit);
 1227                 printf("\n");
 1228         }
 1229 #endif  DEBUG
 1230 
 1231         while (scb_p->scb_command) ;
 1232         scb_p->scb_command = SCB_CU_STRT;
 1233         pc586chatt(unit);
 1234 
 1235         iodone(m);
 1236         return;
 1237 }
 1238 
 1239 /*
 1240  * pc586bldcu:
 1241  *
 1242  *      This function builds up the command unit structures.  It inits
 1243  *      the scp, iscp, scb, cb, tbd, and tbuf.
 1244  *
 1245  */
 1246 pc586bldcu(unit)
 1247 {
 1248         char            *sram = pc_softc[unit].sram;
 1249         scp_t           *scp_p = (scp_t *)(sram + OFFSET_SCP);
 1250         iscp_t          *iscp_p = (iscp_t *)(sram + OFFSET_ISCP);
 1251         volatile scb_t  *scb_p = (volatile scb_t *)(sram + OFFSET_SCB);
 1252         volatile ac_t   *cb_p = (volatile ac_t *)(sram + OFFSET_CU);
 1253         tbd_t           *tbd_p = (tbd_t *)(sram + OFFSET_TBD);
 1254         int             i;
 1255 
 1256         scp_p->scp_sysbus = 0;
 1257         scp_p->scp_iscp = OFFSET_ISCP;
 1258         scp_p->scp_iscp_base = 0;
 1259 
 1260         iscp_p->iscp_busy = 1;
 1261         iscp_p->iscp_scb_offset = OFFSET_SCB;
 1262         iscp_p->iscp_scb = 0;
 1263         iscp_p->iscp_scb_base = 0;
 1264 
 1265         pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs;
 1266         pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs;
 1267         pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs;
 1268         pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs;
 1269         scb_p->scb_status = 0;
 1270         scb_p->scb_command = 0;
 1271         scb_p->scb_cbl_offset = OFFSET_CU;
 1272         scb_p->scb_rfa_offset = OFFSET_RU;
 1273         scb_p->scb_crcerrs = 0;
 1274         scb_p->scb_alnerrs = 0;
 1275         scb_p->scb_rscerrs = 0;
 1276         scb_p->scb_ovrnerrs = 0;
 1277 
 1278         scb_p->scb_command = SCB_RESET;
 1279         pc586chatt(unit);
 1280         for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); );
 1281         if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit);
 1282         for (i = STATUS_TRIES; i-- > 0; ) {
 1283                 if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA)) 
 1284                         break;
 1285         }
 1286         if (!i)
 1287                 printf("pc%d bldcu(): not ready after reset.\n", unit);
 1288         pc586ack(unit);
 1289 
 1290         cb_p->ac_status = 0;
 1291         cb_p->ac_command = AC_CW_EL;
 1292         cb_p->ac_link_offset = OFFSET_CU;
 1293 
 1294         tbd_p->act_count = 0;
 1295         tbd_p->next_tbd_offset = PC586NULL;
 1296         tbd_p->buffer_addr = 0;
 1297         tbd_p->buffer_base = 0;
 1298         return;
 1299 }
 1300 
 1301 /*
 1302  * pc586bldru:
 1303  *
 1304  *      This function builds the linear linked lists of fd's and
 1305  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
 1306  *
 1307  */
 1308 char *
 1309 pc586bldru(unit)
 1310 int unit;
 1311 {
 1312         fd_t    *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
 1313         ru_t    *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD);
 1314         int     i;
 1315 
 1316         pc_softc[unit].begin_fd = fd_p;
 1317         for(i = 0; i < N_FD; i++, fd_p++) {
 1318                 fd_p->status = 0;
 1319                 fd_p->command   = 0;
 1320                 fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit);
 1321                 fd_p->rbd_offset = PC586NULL;
 1322         }
 1323         pc_softc[unit].end_fd = --fd_p;
 1324         fd_p->link_offset = PC586NULL;
 1325         fd_p->command = AC_CW_EL;
 1326         fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
 1327 
 1328         fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit);
 1329         for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) {
 1330                 rbd_p->r.status = 0;
 1331                 rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer),
 1332                                                    unit);
 1333                 rbd_p->r.buffer_base = 0;
 1334                 rbd_p->r.size = RCVBUFSIZE;
 1335                 if (i != N_RBD-1) {
 1336                         rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]),
 1337                                                             unit);
 1338                 } else {
 1339                         rbd_p->r.next_rbd_offset = PC586NULL;
 1340                         rbd_p->r.size |= AC_CW_EL;
 1341                         pc_softc[unit].end_rbd = (rbd_t *)rbd_p;
 1342                 }
 1343         }
 1344         return (char *)pc_softc[unit].begin_fd;
 1345 }
 1346 
 1347 /*
 1348  * pc586rustrt:
 1349  *
 1350  *      This routine starts the receive unit running.  First checks if the
 1351  *      board is actually ready, then the board is instructed to receive
 1352  *      packets again.
 1353  *
 1354  */
 1355 pc586rustrt(unit)
 1356 int unit;
 1357 {
 1358         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1359         char            *strt;
 1360 
 1361         if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY)
 1362                 return;
 1363 
 1364         strt = pc586bldru(unit);
 1365         scb_p->scb_command = SCB_RU_STRT;
 1366         scb_p->scb_rfa_offset = ptr_to_ram(strt, unit);
 1367         pc586chatt(unit);
 1368         return;
 1369 }
 1370 
 1371 /*
 1372  * pc586diag:
 1373  *
 1374  *      This routine does a 586 op-code number 7, and obtains the
 1375  *      diagnose status for the pc586.
 1376  *
 1377  */
 1378 pc586diag(unit)
 1379 int unit;
 1380 {
 1381         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1382         volatile ac_t   *cb_p  = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
 1383         int             i;
 1384 
 1385         if (scb_p->scb_status & SCB_SW_INT) {
 1386                 printf("pc%d diag(): bad initial state %#x\n",
 1387                         unit, scb_p->scb_status);
 1388                 pc586ack(unit);
 1389         }
 1390         cb_p->ac_status = 0;
 1391         cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL);
 1392         scb_p->scb_command = SCB_CU_STRT;
 1393         pc586chatt(unit);
 1394 
 1395         for(i = 0; i < 0xffff; i++)
 1396                 if ((cb_p->ac_status & AC_SW_C))
 1397                         break;
 1398         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 1399                 printf("pc%d: diag failed; status = %x\n",
 1400                         unit, cb_p->ac_status);
 1401                 return(FALSE);
 1402         }
 1403 
 1404         if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) )  {
 1405                 printf("pc%d diag(): bad final state %x\n",
 1406                         unit, scb_p->scb_status);
 1407                 pc586ack(unit);
 1408         }
 1409         return(TRUE);
 1410 }
 1411 
 1412 /*
 1413  * pc586config:
 1414  *
 1415  *      This routine does a standard config of the pc586 board.
 1416  *
 1417  */
 1418 pc586config(unit)
 1419 int unit;
 1420 {
 1421         volatile scb_t  *scb_p  = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1422         volatile ac_t   *cb_p   = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
 1423         int             i;
 1424 
 1425 
 1426 /*
 1427         if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) {
 1428                 printf("pc%d config(): unexpected initial state %x\n",
 1429                         unit, scb_p->scb_status);
 1430         }
 1431 */
 1432         pc586ack(unit);
 1433 
 1434         cb_p->ac_status = 0;
 1435         cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL);
 1436 
 1437         /*
 1438          * below is the default board configuration from p2-28 from 586 book
 1439          */
 1440         cb_p->cmd.configure.fifolim_bytecnt     = 0x080c;
 1441         cb_p->cmd.configure.addrlen_mode        = 0x2600;
 1442         cb_p->cmd.configure.linprio_interframe  = 0x6000;
 1443         cb_p->cmd.configure.slot_time           = 0xf200;
 1444         cb_p->cmd.configure.hardware            = 0x0000;
 1445         cb_p->cmd.configure.min_frame_len       = 0x0040;
 1446 
 1447         scb_p->scb_command = SCB_CU_STRT;
 1448         pc586chatt(unit);
 1449 
 1450         for(i = 0; i < 0xffff; i++)
 1451                 if ((cb_p->ac_status & AC_SW_C))
 1452                         break;
 1453         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 1454                 printf("pc%d: config-configure failed; status = %x\n",
 1455                         unit, cb_p->ac_status);
 1456                 return(FALSE);
 1457         }
 1458 /*
 1459         if (scb_p->scb_status & SCB_SW_INT) {
 1460                 printf("pc%d configure(): bad configure state %x\n",
 1461                         unit, scb_p->scb_status);
 1462                 pc586ack(unit);
 1463         }
 1464 */
 1465         cb_p->ac_status = 0;
 1466         cb_p->ac_command = (AC_IASETUP|AC_CW_EL);
 1467 
 1468         bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE);
 1469 
 1470         scb_p->scb_command = SCB_CU_STRT;
 1471         pc586chatt(unit);
 1472 
 1473         for (i = 0; i < 0xffff; i++)
 1474                 if ((cb_p->ac_status & AC_SW_C))
 1475                         break;
 1476         if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
 1477                 printf("pc%d: config-address failed; status = %x\n",
 1478                         unit, cb_p->ac_status);
 1479                 return(FALSE);
 1480         }
 1481 /*
 1482         if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) {
 1483                 printf("pc%d configure(): unexpected final state %x\n",
 1484                         unit, scb_p->scb_status);
 1485         }
 1486 */
 1487         pc586ack(unit);
 1488 
 1489         return(TRUE);
 1490 }
 1491 
 1492 /*
 1493  * pc586ack:
 1494  */
 1495 pc586ack(unit)
 1496 {
 1497         volatile scb_t  *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1498         int i;
 1499 
 1500         if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT))
 1501                 return;
 1502         CMD(CHANATT, 0x0001, unit);
 1503         for (i = 1000000; scb_p->scb_command && (i-- > 0); );
 1504         if (!i)
 1505                 printf("pc%d pc586ack(): board not accepting command.\n", unit);
 1506 }
 1507 
 1508 char *
 1509 ram_to_ptr(offset, unit)
 1510 int unit;
 1511 u_short offset;
 1512 {
 1513         if (offset == PC586NULL)
 1514                 return(NULL);
 1515         if (offset > 0x3fff) {
 1516                 printf("ram_to_ptr(%x, %d)\n", offset, unit);
 1517                 panic("range");
 1518                 return(NULL);
 1519         }
 1520         return(pc_softc[unit].sram + offset);
 1521 }
 1522 
 1523 #ifndef REQUEUE_DBG
 1524 bad_rbd_chain(offset, unit)
 1525 {
 1526         rbd_t   *rbdp;
 1527         char    *sram = pc_softc[unit].sram;
 1528 
 1529         for (;;) {
 1530                 if (offset == PC586NULL)
 1531                         return 0;
 1532                 if (offset > 0x3fff) {
 1533                         printf("pc%d: bad_rbd_chain offset = %x\n",
 1534                                 unit, offset);
 1535                         pc586_cntrs[unit].rcv.bad_chain++;
 1536                         return 1;
 1537                 }
 1538 
 1539                 rbdp = (rbd_t *)(sram + offset);
 1540                 offset = rbdp->next_rbd_offset;
 1541         }
 1542 }
 1543 #endif  REQUEUE_DBG
 1544 
 1545 u_short
 1546 ptr_to_ram(k_va, unit)
 1547 char    *k_va;
 1548 int unit;
 1549 {
 1550         return((u_short)(k_va - pc_softc[unit].sram));
 1551 }
 1552 
 1553 pc586scb(unit)
 1554 {
 1555         volatile scb_t  *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
 1556         volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE);
 1557         u_short          i;
 1558 
 1559         i = scb->scb_status;
 1560         printf("stat: stat %x, cus %x, rus %x //",
 1561                 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
 1562         i = scb->scb_command;
 1563         printf(" cmd: ack %x, cuc %x, ruc %x\n",
 1564                 (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
 1565 
 1566         printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n",
 1567                 scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc,
 1568                 scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame,
 1569                 scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs,
 1570                 scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs);
 1571 
 1572         printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset);
 1573         printf(" norm %x, ena %x, xfer %x //",
 1574                 cmd[0] & 1, cmd[3] & 1, cmd[4] & 1);
 1575         printf(" atn %x, reset %x, type %x, stat %x\n",
 1576                 cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1);
 1577 }
 1578 
 1579 pc586tbd(unit)
 1580 {
 1581         pc_softc_t      *is = &pc_softc[unit];
 1582         tbd_t           *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
 1583         int             i = 0;
 1584         int             sum = 0;
 1585 
 1586         do {
 1587                 sum += (tbd_p->act_count & ~TBD_SW_EOF);
 1588                 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
 1589                         i++, tbd_p->buffer_addr,
 1590                         (tbd_p->act_count & ~TBD_SW_EOF), sum,
 1591                         tbd_p->next_tbd_offset,
 1592                         tbd_p->buffer_base);
 1593                 if (tbd_p->act_count & TBD_SW_EOF)
 1594                         break;
 1595                 tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset);
 1596         } while (1);
 1597 }
 1598 

Cache object: 332f95c5300bcf76846f116169735fd3


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