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