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