enic.c revision 1.2 1 /* $NetBSD: enic.c,v 1.2 2014/02/24 08:00:52 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was written by Alessandro Forin and Neil Pittman
8 * at Microsoft Research and contributed to The NetBSD Foundation
9 * by Microsoft Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* --------------------------------------------------------------------------
34 *
35 * Module:
36 *
37 * enic.c
38 *
39 * Purpose:
40 *
41 * Driver for the Microsoft eNIC (eMIPS system) Ethernet
42 *
43 * Author:
44 * A. Forin (sandrof)
45 *
46 * References:
47 * Internal Microsoft specifications, file eNIC_Design.docx titled
48 * "eNIC: a simple Ethernet" Revision 4/30/99
49 *
50 * Giano simulation module, file Peripherals\enic.cpp
51 *
52 * Various other drivers I wrote for said hardware
53 * --------------------------------------------------------------------------
54 */
55
56 #include <sys/param.h>
57 #include <sys/types.h>
58
59 #include <net/if_ether.h>
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63
64 #include <lib/libsa/stand.h>
65 #include <lib/libsa/net.h>
66 #include <lib/libsa/netif.h>
67 #include <lib/libkern/libkern.h>
68
69 #include "start.h"
70
71 #include <machine/emipsreg.h>
72 #define the_enic ((struct _Enic *)ETHERNET_DEFAULT_ADDRESS)
73
74 /* forward declarations */
75 static int enicprobe (struct netif *, void *);
76 static int enicmatch (struct netif *, void *);
77 static void enicinit (struct iodesc *, void *);
78 static int enicget (struct iodesc *, void *, size_t, saseconds_t);
79 static int enicput (struct iodesc *, void *, size_t);
80 static void enicend (struct netif *);
81 int enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo);
82 int enic_present(int unit);
83
84 #ifdef NET_DEBUG
85 static void dump_packet(void *, int);
86 #endif
87
88 /* BUGBUG do we have this? */
89 #define kvtophys(_v_) ((paddr_t)(_v_) & ~0x80000000)
90
91 #define rpostone(_r_,_p_,_s_) \
92 (_r_)->SizeAndFlags = ES_F_RECV | (_s_); \
93 (_r_)->BufferAddressHi32 = 0; \
94 (_r_)->BufferAddressLo32 = _p_;
95 #define tpostone(_r_,_p_,_s_) \
96 (_r_)->SizeAndFlags = ES_F_XMIT | (_s_); \
97 (_r_)->BufferAddressHi32 = 0; \
98 (_r_)->BufferAddressLo32 = _p_;
99
100
101 /* Send a packet
102 */
103 static int enic_putpkt(struct _Enic *regs, void *buf, int bytes)
104 {
105 paddr_t phys = kvtophys(buf);
106
107 tpostone(regs,phys,bytes);
108
109 /* poll till done? */
110 //printf("\tenic: sent %d at %x\n",bytes,phys);
111 return bytes;
112 }
113
114 /* Get a packet
115 */
116 int enic_getpkt(struct _Enic *regs, void *buf, int bytes, int timeo)
117 {
118 paddr_t phys;
119 unsigned int isr, saf, hi, lo, fl;
120
121 phys = kvtophys(buf);
122 rpostone(regs,phys,bytes);
123
124 //printf("\tenic: recv %d at %x\n",bytes,phys);
125
126 /* poll till we get some */
127 timeo += getsecs();
128
129 for (;;) {
130
131 /* anything there? */
132 isr = regs->Control;
133
134 if (isr & EC_ERROR) {
135 printf("enic: internal error %x\n", isr);
136 regs->Control = EC_RESET;
137 break;
138 }
139
140 //printf("isr %x ",isr);
141
142 if ((isr & (EC_DONE|EC_OF_EMPTY)) == EC_DONE) {
143
144 /* beware, order matters */
145 saf = regs->SizeAndFlags;
146 hi = regs->BufferAddressHi32; /* BUGBUG 64bit */
147 lo = regs->BufferAddressLo32; /* this pops the fifo */
148
149 fl = saf & (ES_F_MASK &~ ES_F_DONE);
150
151 if (fl == ES_F_RECV)
152 {
153 /* and we are done? */
154 if (phys == lo)
155 return saf & ES_S_MASK;
156 } else if (fl == ES_F_XMIT)
157 {
158 ;/* nothing */
159 } else if (fl != ES_F_CMD)
160 {
161 printf("enic: invalid saf=x%x (lo=%x, hi=%x)\n", saf, lo, hi);
162 }
163 }
164
165 if (getsecs() >= timeo) {
166 //printf("enic: timeout\n");
167 regs->Control = EC_RESET;
168 break;
169 }
170 }
171
172 return 0;
173 }
174
175 /*
176 */
177 static int enic_getmac(struct _Enic *regs, uint8_t *mac)
178 {
179 uint8_t buffer[8];
180 paddr_t phys = kvtophys(&buffer[0]);
181 int i;
182
183 regs->Control = EC_RESET;
184 Delay(1);
185 regs->Control = regs->Control & (~EC_RXDIS);
186
187 buffer[0] = ENIC_CMD_GET_ADDRESS;
188
189 //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
190
191 regs->SizeAndFlags = (sizeof buffer) | ES_F_CMD;
192 regs->BufferAddressHi32 = 0;
193 regs->BufferAddressLo32 = phys; /* go! */
194
195 for (i = 0; i < 100; i++) {
196 Delay(100);
197 if (0 == (regs->Control & EC_OF_EMPTY))
198 break;
199 }
200 if (i == 100)
201 return 0;
202
203 //printf("%x:%x:%x:%x:%x:%x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
204
205 memcpy(mac,buffer,6);
206 return 1;
207 }
208
209 /* Exported interface
210 */
211 int enic_present(int unit)
212 {
213 if ((unit != 0) || (the_enic->Tag != PMTTAG_ETHERNET))
214 return 0;
215
216 return 1;
217 }
218
219 extern int try_bootp;
220
221 extern struct netif_stats enicstats[];
222 struct netif_dif enicifs[] = {
223 /* dif_unit dif_nsel dif_stats dif_private */
224 { 0, 1, &enicstats[0], the_enic, },
225 };
226 #define NENICIFS (sizeof(enicifs) / sizeof(enicifs[0]))
227 struct netif_stats enicstats[NENICIFS];
228
229 struct netif_driver enic_netif_driver = {
230 "enic", /* netif_bname */
231 enicmatch, /* netif_match */
232 enicprobe, /* netif_probe */
233 enicinit, /* netif_init */
234 enicget, /* netif_get */
235 enicput, /* netif_put */
236 enicend, /* netif_end */
237 enicifs, /* netif_ifs */
238 NENICIFS /* netif_nifs */
239 };
240
241 static int
242 enicmatch(struct netif *nif, void *machdep_hint)
243 {
244 return (1);
245 }
246
247 /* NB: We refuse anything but unit==0
248 */
249 static int
250 enicprobe(struct netif *nif, void *machdep_hint)
251 {
252 int unit = nif->nif_unit;
253 #ifdef NET_DEBUG
254 printf("enic%d: probe\n", unit);
255 #endif
256 return (enic_present(unit) ? 0 : 1);
257 }
258
259 static void
260 enicinit(struct iodesc *desc, void *machdep_hint)
261 {
262 #ifdef NET_DEBUG
263 struct netif *nif = (struct netif *)desc->io_netif;
264 int unit = nif->nif_driver->netif_ifs->dif_unit;
265 printf("enic%d: init %s\n", unit, machdep_hint);
266 #endif
267
268 /*
269 * Yes we wan tDHCP adn this is our MAC
270 */
271 try_bootp = 1;
272 enic_getmac(the_enic,desc->myea);
273 desc->xid = 0xfe63d095;
274 }
275
276
277 static int
278 enicput(struct iodesc *desc, void *pkt, size_t len)
279 {
280 #ifdef NET_DEBUG
281 if (debug)
282 dump_packet(pkt,len);
283 #endif
284
285 return enic_putpkt(the_enic,pkt,len);
286 }
287
288
289 int
290 enicget(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
291 {
292 #ifdef NET_DEBUG
293 printf("enicget: %lx %lx\n",len,timeout);
294 #endif
295 return enic_getpkt(the_enic,pkt,len,timeout);
296 }
297
298
299 static void
300 enicend(struct netif *nif)
301 {
302 /* BUGBUG stop it in reset? */
303 }
304
305 #ifdef NET_DEBUG
306 static void dump_packet(void *pkt, int len)
307 {
308 struct ether_header *eh = (struct ether_header *)pkt;
309 struct ip *ih = (struct ip *)(eh + 1);
310
311 printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
312 printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
313 printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
314
315 if (ntohs(eh->ether_type) == 0x0800) {
316 printf("ip packet version %d\n", ih->ip_v);
317 printf("source ip: 0x%x\n", ih->ip_src.s_addr);
318 printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
319
320 }
321 }
322 #endif
323