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