if_ze.c revision 1.7 1 /* $NetBSD: if_ze.c,v 1.7 2000/05/08 17:06:48 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
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 if (vax_boardtype == VAX_BTYP_660)
127 ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
128 else
129 ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
130 }
131 bcopy(ze_myaddr,desc->myea,ETHER_ADDR_LEN);
132
133 /* initialize SGEC operating mode */
134 /* disable interrupts here */
135 nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
136 (ZE_NICSR0_IV_MASK & 0x0108);
137 while (addr->ze_nicsr0 != nicsr0_work)
138 addr->ze_nicsr0 = nicsr0_work;
139 if (addr->ze_nicsr5 & ZE_NICSR5_ME)
140 addr->ze_nicsr5 |= ZE_NICSR5_ME;
141 /* reenable interrupts here */
142
143 /* Allocate space for descriptor lists and buffers,
144 then initialize them. Set up both lists as a ring. */
145 ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
146 ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
147 for (i=0; i < NRCV; i++) {
148 bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
149 ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
150 ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
151 ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
152 }
153 bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
154 ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
155 ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
156 ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
157 for (i=0; i < NXMT; i++) {
158 bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
159 ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
160 ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
161 ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
162 }
163 bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
164 ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
165 ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
166 ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
167
168 /* Build setup frame. We set the SGEC to do a
169 perfect filter on our own address. */
170 ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
171 bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
172 ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
173 ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
174 ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
175 ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
176 bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
177 for (i=0; i < 16; i++)
178 bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
179 ETHER_ADDR_LEN);
180 ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
181 ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
182
183 /* Start the transmitter and initialize almost everything else. */
184 addr->ze_nicsr4 = ze_setup_tdes_list;
185 addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
186 ZE_NICSR6_DC | ZE_NICSR6_BL_4;
187 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
188 ; /* wait for the frame to be processed */
189
190 /* Setup frame is done processing, initialize the receiver and
191 point the transmitter to the real tdes list. */
192 addr->ze_nicsr4 = ze_tdes_list;
193 addr->ze_nicsr3 = ze_rdes_list;
194 addr->ze_nicsr6 |= ZE_NICSR6_SR;
195
196 /* And away-y-y we go! */
197 }
198
199 int
200 ze_get(desc, pkt, maxlen, timeout)
201 struct iodesc *desc;
202 void *pkt;
203 int maxlen;
204 time_t timeout;
205 {
206 int timeout_ctr=100000*timeout, len, rdes;
207
208 while (timeout_ctr-- > 0) {
209
210 /* If there's not a packet waiting for us, just decrement the
211 timeout counter. */
212 if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
213 continue;
214
215 /* Look through the receive descriptor list for the packet. */
216 for (rdes=0; rdes<NRCV; rdes++) {
217 if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
218 continue;
219
220 /* If the packet has an error, ignore it. */
221 if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
222 len = 0;
223
224 /* Copy the packet, up to the length supplied by the caller, to
225 the caller's buffer. */
226 else {
227 if ((len = (ze_rdes_list[rdes].ze_framelen &
228 (~ ZE_FRAMELEN_OW))) > maxlen)
229 len = maxlen;
230 bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
231 pkt,len);
232 }
233
234 /* Give ownership of this descriptor back to the SGEC. */
235 ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;
236
237 /* If we actually got a good packet, reset the error flags and
238 tell the SGEC to look for more before returning. */
239 if (len > 0) {
240 addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
241 ZE_NICSR5_IS;
242 addr->ze_nicsr2=ZE_NICSR2_RXPD;
243 return len;
244 }
245 }
246 }
247
248 /* If we're going to return an error indication, at least reset the
249 error flags and tell the SGEC to keep receiving first. */
250 addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
251 addr->ze_nicsr2=ZE_NICSR2_RXPD;
252 return 0;
253 }
254
255 int
256 ze_put(desc, pkt, len)
257 struct iodesc *desc;
258 void *pkt;
259 int len;
260 {
261 int timeout=100000;
262
263 /* The SGEC maintains its position in the transmit descriptor list
264 for the next frame to transmit. Unfortunately, there's no way to tell
265 from software just where that is. We're forced to reset the position
266 whenever we send a frame, which requires waiting for the previous
267 frame to be sent. Argh. */
268 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
269 ;
270
271 /* Copy the packet to the buffer we allocated. */
272 bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);
273
274 /* Set the packet length in the descriptor, increasing it to the
275 minimum size if needed. */
276 ze_tdes_list[0].ze_bufsize = len;
277 if (len < ETHER_MIN_LEN)
278 ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
279
280 /* Give ownership of the descriptor to the SGEC and tell it to start
281 transmitting. */
282 ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
283 addr->ze_nicsr4 = ze_tdes_list;
284 addr->ze_nicsr1 = ZE_NICSR1_TXPD;
285
286 /* Wait for the frame to be sent, but not too long. */
287 timeout = 100000;
288 while ((addr->ze_nicsr5 & ZE_NICSR5_TI == 0) && (--timeout>0))
289 ;
290
291 /* Reset the transmitter interrupt pending flag. */
292 addr->ze_nicsr5 |= ZE_NICSR5_TI;
293
294 /* Return good if we didn't timeout, or error if we did. */
295 if (timeout>0) return len;
296 return -1;
297 }
298
299 void
300 ze_end()
301 {
302 addr->ze_nicsr6 = ZE_NICSR6_RE;
303 }
304