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