Home | History | Annotate | Line # | Download | only in boot
if_ze.c revision 1.7
      1 /*	$NetBSD: if_ze.c,v 1.7 2000/05/08 17:06:48 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/libkern/libkern.h>
     45 #include <lib/libsa/netif.h>
     46 #include <lib/libsa/stand.h>
     47 
     48 #include <dev/ic/sgecreg.h>
     49 
     50 #include "arch/vax/include/sid.h"
     51 
     52 int ze_probe(), ze_match(), ze_get(), ze_put();
     53 void ze_init(), ze_end();
     54 
     55 struct netif_stats ze_stats;
     56 
     57 struct netif_dif ze_ifs[] = {
     58 /*	dif_unit	dif_nsel	dif_stats	dif_private	*/
     59 {	0,		1,		&ze_stats,	},
     60 };
     61 
     62 struct netif_stats ze_stats;
     63 
     64 struct netif_driver ze_driver = {
     65 	"ze", ze_match, ze_probe, ze_init, ze_get, ze_put, ze_end, ze_ifs, 1,
     66 };
     67 
     68 #define NRCV 8				/* allocate 5 receive descriptors */
     69 #define NXMT 5				/* and 5 transmit - must be >1 */
     70 #define SETUP_FRAME_LEN 128		/* length of the setup frame */
     71 
     72 /* allocate a buffer on an octaword boundary */
     73 #define OW_ALLOC(x) ((void *)((int)(alloc((x) + 15) + 15) & ~15))
     74 
     75 static	volatile struct zedevice *addr;
     76 
     77 struct ze_tdes *ze_tdes_list;	/* transmit desc list */
     78 struct ze_rdes *ze_rdes_list;	/* and receive desc list */
     79 u_char ze_myaddr[ETHER_ADDR_LEN];	/* my Ethernet address */
     80 
     81 int
     82 ze_match(nif, machdep_hint)
     83 	struct netif *nif;
     84 	void *machdep_hint;
     85 {
     86 	return strcmp(machdep_hint, "ze") == 0;
     87 }
     88 
     89 int
     90 ze_probe(nif, machdep_hint)
     91 	struct netif *nif;
     92 	void *machdep_hint;
     93 {
     94 	return 0;
     95 }
     96 
     97 void
     98 ze_init(desc, machdep_hint)
     99 	struct iodesc *desc;
    100 	void *machdep_hint;
    101 {
    102 	u_long nicsr0_work, *nisa_rom;
    103 	int i;
    104 	u_char *saved_buf;
    105 	struct ze_tdes *ze_setup_tdes_list;
    106 
    107 	/* point to the device in memory */
    108 	addr = (struct zedevice *)0x20008000;
    109 
    110 	/* reset the device and wait for completion */
    111 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
    112 	while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
    113 		;
    114 	if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
    115 		printf("SGEC self-test failed...\n");
    116 	}
    117 
    118 	/* Get our Ethernet address */
    119 	if (vax_boardtype == VAX_BTYP_49) {
    120 		nisa_rom = (u_long *)0x27800000;
    121 		for (i=0; i<ETHER_ADDR_LEN; i++)
    122 			ze_myaddr[i] = nisa_rom[i] & 0377;
    123 	} else {
    124 		nisa_rom = (u_long *)0x20084000;
    125 		for (i=0; i<ETHER_ADDR_LEN; i++)
    126 			if (vax_boardtype == VAX_BTYP_660)
    127 				ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
    128 			else
    129 				ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
    130 	}
    131 	bcopy(ze_myaddr,desc->myea,ETHER_ADDR_LEN);
    132 
    133 	/* initialize SGEC operating mode */
    134 	/* disable interrupts here */
    135 	nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
    136 		(ZE_NICSR0_IV_MASK & 0x0108);
    137 	while (addr->ze_nicsr0 != nicsr0_work)
    138 		addr->ze_nicsr0 = nicsr0_work;
    139 	if (addr->ze_nicsr5 & ZE_NICSR5_ME)
    140 		addr->ze_nicsr5 |= ZE_NICSR5_ME;
    141 	/* reenable interrupts here */
    142 
    143 	/* Allocate space for descriptor lists and buffers,
    144 		then initialize them. Set up both lists as a ring. */
    145 	ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
    146 	ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
    147 	for (i=0; i < NRCV; i++) {
    148 		bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
    149 		ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
    150 		ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    151 		ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    152 	}
    153 	bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
    154 	ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
    155 	ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
    156 	ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
    157 	for (i=0; i < NXMT; i++) {
    158 		bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
    159 		ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
    160 		ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    161 		ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    162 	}
    163 	bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
    164 	ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
    165 	ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
    166 	ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
    167 
    168 	/* Build setup frame. We set the SGEC to do a
    169 		perfect filter on our own address. */
    170 	ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
    171 	bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
    172 	ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
    173 	ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
    174 	ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
    175 	ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
    176 	bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
    177 	for (i=0; i < 16; i++)
    178 		bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
    179 			ETHER_ADDR_LEN);
    180 	ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
    181 	ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
    182 
    183 	/* Start the transmitter and initialize almost everything else. */
    184 	addr->ze_nicsr4 = ze_setup_tdes_list;
    185 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
    186 		ZE_NICSR6_DC | ZE_NICSR6_BL_4;
    187 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
    188 		;	/* wait for the frame to be processed */
    189 
    190 	/* Setup frame is done processing, initialize the receiver and
    191 		point the transmitter to the real tdes list. */
    192 	addr->ze_nicsr4 = ze_tdes_list;
    193 	addr->ze_nicsr3 = ze_rdes_list;
    194 	addr->ze_nicsr6 |= ZE_NICSR6_SR;
    195 
    196 	/* And away-y-y we go! */
    197 }
    198 
    199 int
    200 ze_get(desc, pkt, maxlen, timeout)
    201 	struct iodesc *desc;
    202 	void *pkt;
    203 	int maxlen;
    204 	time_t timeout;
    205 {
    206 	int timeout_ctr=100000*timeout, len, rdes;
    207 
    208 	while (timeout_ctr-- > 0) {
    209 
    210 	/* If there's not a packet waiting for us, just decrement the
    211 		timeout counter. */
    212 		if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
    213 			continue;
    214 
    215 	/* Look through the receive descriptor list for the packet. */
    216 		for (rdes=0; rdes<NRCV; rdes++) {
    217 			if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
    218 				continue;
    219 
    220 	/* If the packet has an error, ignore it. */
    221 			if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
    222 				len = 0;
    223 
    224 	/* Copy the packet, up to the length supplied by the caller, to
    225 		the caller's buffer. */
    226 			else {
    227 				if ((len = (ze_rdes_list[rdes].ze_framelen &
    228 					(~ ZE_FRAMELEN_OW))) > maxlen)
    229 					len = maxlen;
    230 				bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
    231 					pkt,len);
    232 			}
    233 
    234 	/* Give ownership of this descriptor back to the SGEC. */
    235 			ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;
    236 
    237 	/* If we actually got a good packet, reset the error flags and
    238 		tell the SGEC to look for more before returning. */
    239 			if (len > 0) {
    240 				addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
    241 					ZE_NICSR5_IS;
    242 				addr->ze_nicsr2=ZE_NICSR2_RXPD;
    243 				return len;
    244 			}
    245 		}
    246 	}
    247 
    248 	/* If we're going to return an error indication, at least reset the
    249 		error flags and tell the SGEC to keep receiving first. */
    250 	addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
    251 	addr->ze_nicsr2=ZE_NICSR2_RXPD;
    252 	return 0;
    253 }
    254 
    255 int
    256 ze_put(desc, pkt, len)
    257 	struct iodesc *desc;
    258 	void *pkt;
    259 	int len;
    260 {
    261 	int timeout=100000;
    262 
    263 	/* The SGEC maintains its position in the transmit descriptor list
    264 	for the next frame to transmit. Unfortunately, there's no way to tell
    265 	from software just where that is. We're forced to reset the position
    266 	whenever we send a frame, which requires waiting for the previous
    267 	frame to be sent. Argh. */
    268 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
    269 		;
    270 
    271 	/* Copy the packet to the buffer we allocated. */
    272 	bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);
    273 
    274 	/* Set the packet length in the descriptor, increasing it to the
    275 		minimum size if needed. */
    276 	ze_tdes_list[0].ze_bufsize = len;
    277 	if (len < ETHER_MIN_LEN)
    278 		ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
    279 
    280 	/* Give ownership of the descriptor to the SGEC and tell it to start
    281 		transmitting. */
    282 	ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
    283 	addr->ze_nicsr4 = ze_tdes_list;
    284 	addr->ze_nicsr1 = ZE_NICSR1_TXPD;
    285 
    286 	/* Wait for the frame to be sent, but not too long. */
    287 	timeout = 100000;
    288 	while ((addr->ze_nicsr5 & ZE_NICSR5_TI == 0) && (--timeout>0))
    289 		;
    290 
    291 	/* Reset the transmitter interrupt pending flag. */
    292 	addr->ze_nicsr5 |= ZE_NICSR5_TI;
    293 
    294 	/* Return good if we didn't timeout, or error if we did. */
    295 	if (timeout>0) return len;
    296 	return -1;
    297 }
    298 
    299 void
    300 ze_end()
    301 {
    302 	addr->ze_nicsr6 = ZE_NICSR6_RE;
    303 }
    304