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