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