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