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