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