if_ze.c revision 1.2 1 /* $NetBSD: if_ze.c,v 1.2 1999/03/25 23:16:37 thorpej 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
36 #include <netinet/in.h>
37 #include <netinet/in_systm.h>
38
39 #include <lib/libkern/libkern.h>
40 #include <lib/libsa/netif.h>
41 #include <lib/libsa/stand.h>
42
43 #include <if/if_zereg.h>
44
45
46 int ze_probe(), ze_match(), ze_get(), ze_put();
47 void ze_init();
48
49 struct netif_stats ze_stats;
50
51 struct netif_dif ze_ifs[] = {
52 /* dif_unit dif_nsel dif_stats dif_private */
53 { 0, 1, &ze_stats, },
54 };
55
56 struct netif_stats ze_stats;
57
58 struct netif_driver ze_driver = {
59 "ze", ze_match, ze_probe, ze_init, ze_get, ze_put, 0, ze_ifs, 1,
60 };
61
62 #define NRCV 5 /* allocate 5 receive descriptors */
63 #define NXMT 5 /* and 5 transmit - must be >1 */
64 #define SETUP_FRAME_LEN 128 /* length of the setup frame */
65
66 /* allocate a buffer on an octaword boundary */
67 #define OW_ALLOC(x) ((void *)((int)(alloc((x) + 15) + 15) & ~15))
68
69 static volatile struct zedevice *addr;
70
71 struct ze_tdes *ze_tdes_list; /* transmit desc list */
72 struct ze_rdes *ze_rdes_list; /* and receive desc list */
73 u_char ze_myaddr[ETHER_ADDR_LEN]; /* my Ethernet address */
74
75 int
76 ze_match(nif, machdep_hint)
77 struct netif *nif;
78 void *machdep_hint;
79 {
80 return strcmp(machdep_hint, "ze") == 0;
81 }
82
83 int
84 ze_probe(nif, machdep_hint)
85 struct netif *nif;
86 void *machdep_hint;
87 {
88 return 0;
89 }
90
91 void
92 ze_init(desc, machdep_hint)
93 struct iodesc *desc;
94 void *machdep_hint;
95 {
96 u_long nicsr0_work, *nisa_rom;
97 int i;
98 u_char *saved_buf;
99 struct ze_tdes *ze_setup_tdes_list;
100
101 /* point to the device in memory */
102 addr = (struct zedevice *)0x20008000;
103
104 /* reset the device and wait for completion */
105 addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
106 while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
107 ;
108 if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
109 printf("SGEC self-test failed...\n");
110 }
111
112 /* Get our Ethernet address */
113 nisa_rom = (u_long *)0x20084000;
114 for (i=0; i<ETHER_ADDR_LEN; i++)
115 ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
116 bcopy(ze_myaddr,desc->myea,ETHER_ADDR_LEN);
117
118 /* initialize SGEC operating mode */
119 /* disable interrupts here */
120 nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
121 (ZE_NICSR0_IV_MASK & 0x0108);
122 while (addr->ze_nicsr0 != nicsr0_work)
123 addr->ze_nicsr0 = nicsr0_work;
124 if (addr->ze_nicsr5 & ZE_NICSR5_ME)
125 addr->ze_nicsr5 |= ZE_NICSR5_ME;
126 /* reenable interrupts here */
127
128 /* Allocate space for descriptor lists and buffers,
129 then initialize them. Set up both lists as a ring. */
130 ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
131 ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
132 for (i=0; i < NRCV; i++) {
133 bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
134 ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
135 ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
136 ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
137 }
138 bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
139 ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
140 ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
141 ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
142 for (i=0; i < NXMT; i++) {
143 bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
144 ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
145 ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
146 ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
147 }
148 bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
149 ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
150 ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
151 ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;
152
153 /* Build setup frame. We set the SGEC to do a
154 perfect filter on our own address. */
155 ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
156 bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
157 ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
158 ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
159 ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
160 ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
161 bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
162 for (i=0; i < 16; i++)
163 bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
164 ETHER_ADDR_LEN);
165 ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
166 ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;
167
168 /* Start the transmitter and initialize almost everything else. */
169 addr->ze_nicsr4 = ze_setup_tdes_list;
170 addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
171 ZE_NICSR6_DC | ZE_NICSR6_BL_4;
172 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
173 ; /* wait for the frame to be processed */
174
175 /* Setup frame is done processing, initialize the receiver and
176 point the transmitter to the real tdes list. */
177 addr->ze_nicsr4 = ze_tdes_list;
178 addr->ze_nicsr3 = ze_rdes_list;
179 addr->ze_nicsr6 |= ZE_NICSR6_SR;
180
181 /* And away-y-y we go! */
182 }
183
184 int
185 ze_get(desc, pkt, maxlen, timeout)
186 struct iodesc *desc;
187 void *pkt;
188 int maxlen;
189 time_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
241 ze_put(desc, pkt, len)
242 struct iodesc *desc;
243 void *pkt;
244 int len;
245 {
246 int timeout=100000;
247
248 /* The SGEC maintains its position in the transmit descriptor list
249 for the next frame to transmit. Unfortunately, there's no way to tell
250 from software just where that is. We're forced to reset the position
251 whenever we send a frame, which requires waiting for the previous
252 frame to be sent. Argh. */
253 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
254 ;
255
256 /* Copy the packet to the buffer we allocated. */
257 bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);
258
259 /* Set the packet length in the descriptor, increasing it to the
260 minimum size if needed. */
261 ze_tdes_list[0].ze_bufsize = len;
262 if (len < ETHER_MIN_LEN)
263 ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;
264
265 /* Give ownership of the descriptor to the SGEC and tell it to start
266 transmitting. */
267 ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
268 addr->ze_nicsr4 = ze_tdes_list;
269 addr->ze_nicsr1 = ZE_NICSR1_TXPD;
270
271 /* Wait for the frame to be sent, but not too long. */
272 timeout = 100000;
273 while ((addr->ze_nicsr5 & ZE_NICSR5_TI == 0) && (--timeout>0))
274 ;
275
276 /* Reset the transmitter interrupt pending flag. */
277 addr->ze_nicsr5 |= ZE_NICSR5_TI;
278
279 /* Return good if we didn't timeout, or error if we did. */
280 if (timeout>0) return len;
281 return -1;
282 }
283