Home | History | Annotate | Line # | Download | only in boot
if_ze.c revision 1.6
      1 /*	$NetBSD: if_ze.c,v 1.6 2000/04/28 00:08:51 matt 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 			ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
    127 	}
    128 	bcopy(ze_myaddr,desc->myea,ETHER_ADDR_LEN);
    129 
    130 	/* initialize SGEC operating mode */
    131 	/* disable interrupts here */
    132 	nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
    133 		(ZE_NICSR0_IV_MASK & 0x0108);
    134 	while (addr->ze_nicsr0 != nicsr0_work)
    135 		addr->ze_nicsr0 = nicsr0_work;
    136 	if (addr->ze_nicsr5 & ZE_NICSR5_ME)
    137 		addr->ze_nicsr5 |= ZE_NICSR5_ME;
    138 	/* reenable interrupts here */
    139 
    140 	/* Allocate space for descriptor lists and buffers,
    141 		then initialize them. Set up both lists as a ring. */
    142 	ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
    143 	ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
    144 	for (i=0; i < NRCV; i++) {
    145 		bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
    146 		ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
    147 		ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    148 		ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    149 	}
    150 	bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
    151 	ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
    152 	ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
    153 	ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
    154 	for (i=0; i < NXMT; i++) {
    155 		bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
    156 		ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
    157 		ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
    158 		ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
    159 	}
    160 	bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
    161 	ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
    162 	ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
    163 	ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
    164 
    165 	/* Build setup frame. We set the SGEC to do a
    166 		perfect filter on our own address. */
    167 	ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
    168 	bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
    169 	ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
    170 	ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
    171 	ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
    172 	ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
    173 	bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
    174 	for (i=0; i < 16; i++)
    175 		bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
    176 			ETHER_ADDR_LEN);
    177 	ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
    178 	ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
    179 
    180 	/* Start the transmitter and initialize almost everything else. */
    181 	addr->ze_nicsr4 = ze_setup_tdes_list;
    182 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
    183 		ZE_NICSR6_DC | ZE_NICSR6_BL_4;
    184 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
    185 		;	/* wait for the frame to be processed */
    186 
    187 	/* Setup frame is done processing, initialize the receiver and
    188 		point the transmitter to the real tdes list. */
    189 	addr->ze_nicsr4 = ze_tdes_list;
    190 	addr->ze_nicsr3 = ze_rdes_list;
    191 	addr->ze_nicsr6 |= ZE_NICSR6_SR;
    192 
    193 	/* And away-y-y we go! */
    194 }
    195 
    196 int
    197 ze_get(desc, pkt, maxlen, timeout)
    198 	struct iodesc *desc;
    199 	void *pkt;
    200 	int maxlen;
    201 	time_t timeout;
    202 {
    203 	int timeout_ctr=100000*timeout, len, rdes;
    204 
    205 	while (timeout_ctr-- > 0) {
    206 
    207 	/* If there's not a packet waiting for us, just decrement the
    208 		timeout counter. */
    209 		if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
    210 			continue;
    211 
    212 	/* Look through the receive descriptor list for the packet. */
    213 		for (rdes=0; rdes<NRCV; rdes++) {
    214 			if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
    215 				continue;
    216 
    217 	/* If the packet has an error, ignore it. */
    218 			if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
    219 				len = 0;
    220 
    221 	/* Copy the packet, up to the length supplied by the caller, to
    222 		the caller's buffer. */
    223 			else {
    224 				if ((len = (ze_rdes_list[rdes].ze_framelen &
    225 					(~ ZE_FRAMELEN_OW))) > maxlen)
    226 					len = maxlen;
    227 				bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
    228 					pkt,len);
    229 			}
    230 
    231 	/* Give ownership of this descriptor back to the SGEC. */
    232 			ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;
    233 
    234 	/* If we actually got a good packet, reset the error flags and
    235 		tell the SGEC to look for more before returning. */
    236 			if (len > 0) {
    237 				addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
    238 					ZE_NICSR5_IS;
    239 				addr->ze_nicsr2=ZE_NICSR2_RXPD;
    240 				return len;
    241 			}
    242 		}
    243 	}
    244 
    245 	/* If we're going to return an error indication, at least reset the
    246 		error flags and tell the SGEC to keep receiving first. */
    247 	addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
    248 	addr->ze_nicsr2=ZE_NICSR2_RXPD;
    249 	return 0;
    250 }
    251 
    252 int
    253 ze_put(desc, pkt, len)
    254 	struct iodesc *desc;
    255 	void *pkt;
    256 	int len;
    257 {
    258 	int timeout=100000;
    259 
    260 	/* The SGEC maintains its position in the transmit descriptor list
    261 	for the next frame to transmit. Unfortunately, there's no way to tell
    262 	from software just where that is. We're forced to reset the position
    263 	whenever we send a frame, which requires waiting for the previous
    264 	frame to be sent. Argh. */
    265 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
    266 		;
    267 
    268 	/* Copy the packet to the buffer we allocated. */
    269 	bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);
    270 
    271 	/* Set the packet length in the descriptor, increasing it to the
    272 		minimum size if needed. */
    273 	ze_tdes_list[0].ze_bufsize = len;
    274 	if (len < ETHER_MIN_LEN)
    275 		ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
    276 
    277 	/* Give ownership of the descriptor to the SGEC and tell it to start
    278 		transmitting. */
    279 	ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
    280 	addr->ze_nicsr4 = ze_tdes_list;
    281 	addr->ze_nicsr1 = ZE_NICSR1_TXPD;
    282 
    283 	/* Wait for the frame to be sent, but not too long. */
    284 	timeout = 100000;
    285 	while ((addr->ze_nicsr5 & ZE_NICSR5_TI == 0) && (--timeout>0))
    286 		;
    287 
    288 	/* Reset the transmitter interrupt pending flag. */
    289 	addr->ze_nicsr5 |= ZE_NICSR5_TI;
    290 
    291 	/* Return good if we didn't timeout, or error if we did. */
    292 	if (timeout>0) return len;
    293 	return -1;
    294 }
    295 
    296 void
    297 ze_end()
    298 {
    299 	addr->ze_nicsr6 = ZE_NICSR6_RE;
    300 }
    301