xref: /netbsd-src/sys/arch/vax/boot/boot/if_ze.c (revision 62cf489d8e50741c34bd70b1b71691c2aceec801)
1 /*	$NetBSD: if_ze.c,v 1.17 2009/10/26 19:16:58 cegger 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 #include <lib/libsa/net.h>
47 
48 #include "lib/libkern/libkern.h"
49 
50 #include <dev/ic/sgecreg.h>
51 
52 #include "arch/vax/include/sid.h"
53 #include "arch/vax/include/rpb.h"
54 
55 #include "vaxstand.h"
56 
57 static int ze_get(struct iodesc *, void *, size_t, saseconds_t);
58 static int ze_put(struct iodesc *, void *, size_t);
59 
60 
61 struct netif_driver ze_driver = {
62 	0, 0, 0, 0, ze_get, ze_put,
63 };
64 
65 #define NRCV 8				/* allocate 8 receive descriptors */
66 #define NXMT 4				/* and 4 transmit - must be >1 */
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)((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
zeopen(struct open_file * f,int adapt,int ctlr,int unit,int part)79 zeopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
80 {
81 	u_long nicsr0_work, *nisa_rom;
82 	struct ze_tdes *ze_setup_tdes_list;
83 	int i;
84 
85 	/* point to the device in memory */
86 	if (askname == 0) /* Override if autoboot */
87 		addr = (struct zedevice *)bootrpb.csrphy;
88 	else
89 		addr = (struct zedevice *)0x20008000;
90 
91 	/* reset the device and wait for completion */
92 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
93 	while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
94 		;
95 	if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
96 		printf("SGEC self-test failed...\n");
97 		return 1;
98 	}
99 
100 	/* Get our Ethernet address */
101 	if (vax_boardtype == VAX_BTYP_49) {
102 		nisa_rom = (u_long *)0x27800000;
103 		for (i=0; i<ETHER_ADDR_LEN; i++)
104 			ze_myaddr[i] = nisa_rom[i] & 0377;
105 	} else if (vax_boardtype == VAX_BTYP_VXT) {
106 		nisa_rom = (u_long *)0x200c4000;
107 		for (i=0; i<ETHER_ADDR_LEN; i++)
108 			ze_myaddr[i] = nisa_rom[i] & 0xff;
109 	} else {
110 		nisa_rom = (u_long *)0x20084000;
111 		for (i=0; i<ETHER_ADDR_LEN; i++)
112 			if (vax_boardtype == VAX_BTYP_660)
113 				ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
114 			else
115 				ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
116 	}
117 	printf("SGEC: Ethernet address %s\n", ether_sprintf(ze_myaddr));
118 
119 	/* initialize SGEC operating mode */
120 	/* disable interrupts here */
121 	nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
122 		(ZE_NICSR0_IV_MASK & 0x0108);
123 	while (addr->ze_nicsr0 != nicsr0_work)
124 		addr->ze_nicsr0 = nicsr0_work;
125 	if (addr->ze_nicsr5 & ZE_NICSR5_ME)
126 		addr->ze_nicsr5 |= ZE_NICSR5_ME;
127 	/* reenable interrupts here */
128 
129 	/* Allocate space for descriptor lists and buffers,
130 		then initialize them. Set up both lists as a ring. */
131 	ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
132 	ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
133 	for (i=0; i < NRCV; i++) {
134 		memset(ze_rdes_list+i, 0,sizeof(struct ze_rdes));
135 		ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
136 		ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
137 		ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
138 	}
139 	memset(ze_rdes_list+NRCV, 0,sizeof(struct ze_rdes));
140 	ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
141 	ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
142 	ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
143 	for (i=0; i < NXMT; i++) {
144 		memset(ze_tdes_list+i, 0,sizeof(struct ze_tdes));
145 		ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
146 		ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
147 		ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
148 	}
149 	memset(ze_tdes_list+NXMT, 0,sizeof(struct ze_tdes));
150 	ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
151 	ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
152 	ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
153 
154 	/* Build setup frame. We set the SGEC to do a
155 		perfect filter on our own address. */
156 	ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
157 	memset(ze_setup_tdes_list+0, 0,2*sizeof(struct ze_tdes));
158 	ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
159 	ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
160 	ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
161 	ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
162 	memset(ze_setup_tdes_list[0].ze_bufaddr, 0,SETUP_FRAME_LEN);
163 	for (i=0; i < 16; i++)
164 		memcpy(ze_setup_tdes_list[0].ze_bufaddr+(8*i), ze_myaddr,
165 			ETHER_ADDR_LEN);
166 	ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
167 	ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
168 
169 	/* Start the transmitter and initialize almost everything else. */
170 	addr->ze_nicsr4 = ze_setup_tdes_list;
171 	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
172 		ZE_NICSR6_DC | ZE_NICSR6_BL_4;
173 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
174 		;	/* wait for the frame to be processed */
175 
176 	/* Setup frame is done processing, initialize the receiver and
177 		point the transmitter to the real tdes list. */
178 	addr->ze_nicsr4 = ze_tdes_list;
179 	addr->ze_nicsr3 = ze_rdes_list;
180 	addr->ze_nicsr6 |= ZE_NICSR6_SR;
181 
182 	/* And away-y-y we go! */
183 
184 	net_devinit(f, &ze_driver, ze_myaddr);
185 	return 0;
186 }
187 
188 int
ze_get(struct iodesc * desc,void * pkt,size_t maxlen,saseconds_t timeout)189 ze_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_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
ze_put(struct iodesc * desc,void * pkt,size_t len)241 ze_put(struct iodesc *desc, void *pkt, size_t len)
242 {
243 	int timeout=100000;
244 
245 	/* The SGEC maintains its position in the transmit descriptor list
246 	for the next frame to transmit. Unfortunately, there's no way to tell
247 	from software just where that is. We're forced to reset the position
248 	whenever we send a frame, which requires waiting for the previous
249 	frame to be sent. Argh. */
250 	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
251 		;
252 
253 	/* Copy the packet to the buffer we allocated. */
254 	memcpy((void *)ze_tdes_list[0].ze_bufaddr, pkt, len);
255 
256 	/* Set the packet length in the descriptor, increasing it to the
257 		minimum size if needed. */
258 	ze_tdes_list[0].ze_bufsize = len;
259 	if (len < ETHER_MIN_LEN)
260 		ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
261 
262 	/* Give ownership of the descriptor to the SGEC and tell it to start
263 		transmitting. */
264 	ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
265 	addr->ze_nicsr4 = ze_tdes_list;
266 	addr->ze_nicsr1 = ZE_NICSR1_TXPD;
267 
268 	/* Wait for the frame to be sent, but not too long. */
269 	timeout = 100000;
270 	while (((addr->ze_nicsr5 & ZE_NICSR5_TI) == 0) && (--timeout>0))
271 		;
272 
273 	/* Reset the transmitter interrupt pending flag. */
274 	addr->ze_nicsr5 |= ZE_NICSR5_TI;
275 
276 	/* Return good if we didn't timeout, or error if we did. */
277 	if (timeout>0) return len;
278 	return -1;
279 }
280 
281 int
zeclose(struct open_file * f)282 zeclose(struct open_file *f)
283 {
284 	addr->ze_nicsr6 = ZE_NICSR6_RE;
285 
286 	return 0;
287 }
288