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