Home | History | Annotate | Line # | Download | only in boot
if_ze.c revision 1.10
      1 /*	$NetBSD: if_ze.c,v 1.10 2000/05/20 13:30:03 ragge Exp $	*/
      2 /*
      3  * Copyright (c) 1998 James R. Maynard III.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by James R. Maynard III.
     16  * 4. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  *
     30  *	Standalone routine for the SGEC Ethernet controller.
     31  */
     32 
     33 #include <sys/param.h>
     34 #include <sys/types.h>
     35 #include <sys/socket.h>
     36 #include <sys/queue.h>
     37 
     38 #include <net/if.h>
     39 #include <net/if_ether.h>
     40 
     41 #include <netinet/in.h>
     42 #include <netinet/in_systm.h>
     43 
     44 #include <lib/libsa/netif.h>
     45 #include <lib/libsa/stand.h>
     46 
     47 #include "lib/libkern/libkern.h"
     48 
     49 #include <dev/ic/sgecreg.h>
     50 
     51 #include "arch/vax/include/sid.h"
     52 #include "arch/vax/include/rpb.h"
     53 
     54 #include "vaxstand.h"
     55 
     56 static int ze_get(struct iodesc *, void *, size_t, time_t);
     57 static int ze_put(struct iodesc *, void *, size_t);
     58 
     59 
     60 struct netif_driver ze_driver = {
     61 	0, 0, 0, 0, ze_get, ze_put,
     62 };
     63 
     64 #define NRCV 8				/* allocate 8 receive descriptors */
     65 #define NXMT 4				/* and 4 transmit - must be >1 */
     66 #define SETUP_FRAME_LEN 128		/* length of the setup frame */
     67 
     68 /* allocate a buffer on an octaword boundary */
     69 #define OW_ALLOC(x) ((void *)((int)((int)alloc((x) + 15) + 15) & ~15))
     70 
     71 static	volatile struct zedevice *addr;
     72 
     73 struct ze_tdes *ze_tdes_list;	/* transmit desc list */
     74 struct ze_rdes *ze_rdes_list;	/* and receive desc list */
     75 u_char ze_myaddr[ETHER_ADDR_LEN];	/* my Ethernet address */
     76 
     77 int
     78 zeopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
     79 {
     80 	u_long nicsr0_work, *nisa_rom;
     81 	struct ze_tdes *ze_setup_tdes_list;
     82 	int i;
     83 
     84 	/* point to the device in memory */
     85 	if (askname == 0) /* Override if autoboot */
     86 		addr = (struct zedevice *)bootrpb.csrphy;
     87 	else
     88 		addr = (struct zedevice *)0x20008000;
     89 
     90 	/* reset the device and wait for completion */
     91 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
     92 	while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
     93 		;
     94 	if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
     95 		printf("SGEC self-test failed...\n");
     96 		return 1;
     97 	}
     98 
     99 	/* Get our Ethernet address */
    100 	if (vax_boardtype == VAX_BTYP_49) {
    101 		nisa_rom = (u_long *)0x27800000;
    102 		for (i=0; i<ETHER_ADDR_LEN; i++)
    103 			ze_myaddr[i] = nisa_rom[i] & 0377;
    104 	} else {
    105 		nisa_rom = (u_long *)0x20084000;
    106 		for (i=0; i<ETHER_ADDR_LEN; i++)
    107 			if (vax_boardtype == VAX_BTYP_660)
    108 				ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
    109 			else
    110 				ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
    111 	}
    112 
    113 	/* initialize SGEC operating mode */
    114 	/* disable interrupts here */
    115 	nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
    116 		(ZE_NICSR0_IV_MASK & 0x0108);
    117 	while (addr->ze_nicsr0 != nicsr0_work)
    118 		addr->ze_nicsr0 = nicsr0_work;
    119 	if (addr->ze_nicsr5 & ZE_NICSR5_ME)
    120 		addr->ze_nicsr5 |= ZE_NICSR5_ME;
    121 	/* reenable interrupts here */
    122 
    123 	/* Allocate space for descriptor lists and buffers,
    124 		then initialize them. Set up both lists as a ring. */
    125 	ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
    126 	ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
    127 	for (i=0; i < NRCV; i++) {
    128 		bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
    129 		ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
    130 		ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    131 		ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    132 	}
    133 	bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
    134 	ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
    135 	ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
    136 	ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
    137 	for (i=0; i < NXMT; i++) {
    138 		bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
    139 		ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
    140 		ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    141 		ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    142 	}
    143 	bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
    144 	ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
    145 	ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
    146 	ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
    147 
    148 	/* Build setup frame. We set the SGEC to do a
    149 		perfect filter on our own address. */
    150 	ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
    151 	bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
    152 	ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
    153 	ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
    154 	ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
    155 	ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
    156 	bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
    157 	for (i=0; i < 16; i++)
    158 		bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
    159 			ETHER_ADDR_LEN);
    160 	ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
    161 	ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
    162 
    163 	/* Start the transmitter and initialize almost everything else. */
    164 	addr->ze_nicsr4 = ze_setup_tdes_list;
    165 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
    166 		ZE_NICSR6_DC | ZE_NICSR6_BL_4;
    167 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
    168 		;	/* wait for the frame to be processed */
    169 
    170 	/* Setup frame is done processing, initialize the receiver and
    171 		point the transmitter to the real tdes list. */
    172 	addr->ze_nicsr4 = ze_tdes_list;
    173 	addr->ze_nicsr3 = ze_rdes_list;
    174 	addr->ze_nicsr6 |= ZE_NICSR6_SR;
    175 
    176 	/* And away-y-y we go! */
    177 
    178 	net_devinit(f, &ze_driver, ze_myaddr);
    179 	return 0;
    180 }
    181 
    182 int
    183 ze_get(desc, pkt, maxlen, timeout)
    184 	struct iodesc *desc;
    185 	void *pkt;
    186 	size_t maxlen;
    187 	time_t timeout;
    188 {
    189 	int timeout_ctr=100000*timeout, len, rdes;
    190 
    191 	while (timeout_ctr-- > 0) {
    192 
    193 	/* If there's not a packet waiting for us, just decrement the
    194 		timeout counter. */
    195 		if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
    196 			continue;
    197 
    198 	/* Look through the receive descriptor list for the packet. */
    199 		for (rdes=0; rdes<NRCV; rdes++) {
    200 			if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
    201 				continue;
    202 
    203 	/* If the packet has an error, ignore it. */
    204 			if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
    205 				len = 0;
    206 
    207 	/* Copy the packet, up to the length supplied by the caller, to
    208 		the caller's buffer. */
    209 			else {
    210 				if ((len = (ze_rdes_list[rdes].ze_framelen &
    211 					(~ ZE_FRAMELEN_OW))) > maxlen)
    212 					len = maxlen;
    213 				bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
    214 					pkt,len);
    215 			}
    216 
    217 	/* Give ownership of this descriptor back to the SGEC. */
    218 			ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;
    219 
    220 	/* If we actually got a good packet, reset the error flags and
    221 		tell the SGEC to look for more before returning. */
    222 			if (len > 0) {
    223 				addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
    224 					ZE_NICSR5_IS;
    225 				addr->ze_nicsr2=ZE_NICSR2_RXPD;
    226 				return len;
    227 			}
    228 		}
    229 	}
    230 
    231 	/* If we're going to return an error indication, at least reset the
    232 		error flags and tell the SGEC to keep receiving first. */
    233 	addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
    234 	addr->ze_nicsr2=ZE_NICSR2_RXPD;
    235 	return 0;
    236 }
    237 
    238 int
    239 ze_put(desc, pkt, len)
    240 	struct iodesc *desc;
    241 	void *pkt;
    242 	size_t len;
    243 {
    244 	int timeout=100000;
    245 
    246 	/* The SGEC maintains its position in the transmit descriptor list
    247 	for the next frame to transmit. Unfortunately, there's no way to tell
    248 	from software just where that is. We're forced to reset the position
    249 	whenever we send a frame, which requires waiting for the previous
    250 	frame to be sent. Argh. */
    251 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
    252 		;
    253 
    254 	/* Copy the packet to the buffer we allocated. */
    255 	bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);
    256 
    257 	/* Set the packet length in the descriptor, increasing it to the
    258 		minimum size if needed. */
    259 	ze_tdes_list[0].ze_bufsize = len;
    260 	if (len < ETHER_MIN_LEN)
    261 		ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
    262 
    263 	/* Give ownership of the descriptor to the SGEC and tell it to start
    264 		transmitting. */
    265 	ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
    266 	addr->ze_nicsr4 = ze_tdes_list;
    267 	addr->ze_nicsr1 = ZE_NICSR1_TXPD;
    268 
    269 	/* Wait for the frame to be sent, but not too long. */
    270 	timeout = 100000;
    271 	while (((addr->ze_nicsr5 & ZE_NICSR5_TI) == 0) && (--timeout>0))
    272 		;
    273 
    274 	/* Reset the transmitter interrupt pending flag. */
    275 	addr->ze_nicsr5 |= ZE_NICSR5_TI;
    276 
    277 	/* Return good if we didn't timeout, or error if we did. */
    278 	if (timeout>0) return len;
    279 	return -1;
    280 }
    281 
    282 int
    283 zeclose(struct open_file *f)
    284 {
    285 	addr->ze_nicsr6 = ZE_NICSR6_RE;
    286 
    287 	return 0;
    288 }
    289