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