1 /* $NetBSD: ofnet.c,v 1.47 2009/05/12 13:17:37 cegger Exp $ */
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ofnet.c,v 1.47 2009/05/12 13:17:37 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/callout.h>
44 #include <sys/device.h>
46 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #include <sys/syslog.h>
52 #include <net/if_ether.h>
55 #include <netinet/in.h>
56 #include <netinet/if_inarp.h>
61 #include <net/bpfdesc.h>
64 #include <dev/ofw/openfirm.h>
67 #include <ipkdb/ipkdb.h>
68 #include <machine/ipkdb.h>
70 CFATTACH_DECL(ipkdb_ofn
, 0,
71 ipkdb_probe
, ipkdb_attach
, NULL
, NULL
);
73 static struct ipkdb_if
*kifp
;
74 static struct ofnet_softc
*ipkdb_of
;
76 static int ipkdbprobe (cfdata_t
, void *);
83 struct ethercom sc_ethercom
;
84 struct callout sc_callout
;
87 static int ofnet_match (device_t
, cfdata_t
, void *);
88 static void ofnet_attach (device_t
, device_t
, void *);
90 CFATTACH_DECL(ofnet
, sizeof(struct ofnet_softc
),
91 ofnet_match
, ofnet_attach
, NULL
, NULL
);
93 static void ofnet_read (struct ofnet_softc
*);
94 static void ofnet_timer (void *);
95 static void ofnet_init (struct ofnet_softc
*);
96 static void ofnet_stop (struct ofnet_softc
*);
98 static void ofnet_start (struct ifnet
*);
99 static int ofnet_ioctl (struct ifnet
*, u_long
, void *);
100 static void ofnet_watchdog (struct ifnet
*);
103 ofnet_match(device_t parent
, cfdata_t match
, void *aux
)
105 struct ofbus_attach_args
*oba
= aux
;
111 return ipkdbprobe(match
, aux
);
113 if (strcmp(oba
->oba_busname
, "ofw"))
115 if ((l
= OF_getprop(oba
->oba_phandle
, "device_type", type
,
116 sizeof type
- 1)) < 0)
118 if (l
>= sizeof type
)
121 if (strcmp(type
, "network"))
127 ofnet_attach(device_t parent
, device_t self
, void *aux
)
129 struct ofnet_softc
*of
= device_private(self
);
130 struct ifnet
*ifp
= &of
->sc_ethercom
.ec_if
;
131 struct ofbus_attach_args
*oba
= aux
;
134 u_int8_t myaddr
[ETHER_ADDR_LEN
];
136 of
->sc_phandle
= oba
->oba_phandle
;
139 kifp
->unit
- 1 == device_unit(&of
->sc_dev
) &&
140 OF_instance_to_package(kifp
->port
) == oba
->oba_phandle
) {
142 of
->sc_ihandle
= kifp
->port
;
145 if ((l
= OF_package_to_path(oba
->oba_phandle
, path
,
146 sizeof path
- 1)) < 0 ||
148 (path
[l
] = 0, !(of
->sc_ihandle
= OF_open(path
))))
149 panic("ofnet_attach: unable to open");
150 if (OF_getprop(oba
->oba_phandle
, "mac-address", myaddr
,
152 panic("ofnet_attach: no mac-address");
153 printf(": address %s\n", ether_sprintf(myaddr
));
155 callout_init(&of
->sc_callout
, 0);
157 strlcpy(ifp
->if_xname
, device_xname(&of
->sc_dev
), IFNAMSIZ
);
159 ifp
->if_start
= ofnet_start
;
160 ifp
->if_ioctl
= ofnet_ioctl
;
161 ifp
->if_watchdog
= ofnet_watchdog
;
162 ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_NOTRAILERS
;
163 IFQ_SET_READY(&ifp
->if_snd
);
166 ether_ifattach(ifp
, myaddr
);
169 static char buf
[ETHER_MAX_LEN
];
172 ofnet_read(struct ofnet_softc
*of
)
174 struct ifnet
*ifp
= &of
->sc_ethercom
.ec_if
;
175 struct mbuf
*m
, **mp
, *head
;
181 ipkdbrint(kifp
, ifp
);
184 len
= OF_read(of
->sc_ihandle
, buf
, sizeof buf
);
185 if (len
== -2 || len
== 0)
187 if (len
< sizeof(struct ether_header
)) {
194 * We don't know if the interface included the FCS
195 * or not. For now, assume that it did if we got
196 * a packet length that looks like it could include
201 if (len
> ETHER_MAX_LEN
- ETHER_CRC_LEN
)
202 len
= ETHER_MAX_LEN
- ETHER_CRC_LEN
;
204 /* Allocate a header mbuf */
205 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
210 m
->m_pkthdr
.rcvif
= ifp
;
211 m
->m_pkthdr
.len
= len
;
219 MGET(m
, M_DONTWAIT
, MT_DATA
);
228 if (len
>= MINCLSIZE
) {
229 MCLGET(m
, M_DONTWAIT
);
230 if ((m
->m_flags
& M_EXT
) == 0) {
241 * Make sure the data after the Ethernet header
244 * XXX Assumes the device is an ethernet, but
245 * XXX then so does other code in this driver.
248 char *newdata
= (char *)ALIGN(m
->m_data
+
249 sizeof(struct ether_header
)) -
250 sizeof(struct ether_header
);
251 l
-= newdata
- m
->m_data
;
255 m
->m_len
= l
= min(len
, l
);
256 memcpy(mtod(m
, char *), bufp
, l
);
267 bpf_mtap(ifp
->if_bpf
, m
);
270 (*ifp
->if_input
)(ifp
, head
);
276 ofnet_timer(void *arg
)
278 struct ofnet_softc
*of
= arg
;
281 callout_reset(&of
->sc_callout
, 1, ofnet_timer
, of
);
285 ofnet_init(struct ofnet_softc
*of
)
287 struct ifnet
*ifp
= &of
->sc_ethercom
.ec_if
;
289 if (ifp
->if_flags
& IFF_RUNNING
)
292 ifp
->if_flags
|= IFF_RUNNING
;
293 /* Start reading from interface */
295 /* Attempt to start output */
300 ofnet_stop(struct ofnet_softc
*of
)
302 callout_stop(&of
->sc_callout
);
303 of
->sc_ethercom
.ec_if
.if_flags
&= ~IFF_RUNNING
;
307 ofnet_start(struct ifnet
*ifp
)
309 struct ofnet_softc
*of
= ifp
->if_softc
;
314 if (!(ifp
->if_flags
& IFF_RUNNING
))
318 /* First try reading any packets */
321 /* Now get the first packet on the queue */
322 IFQ_DEQUEUE(&ifp
->if_snd
, m0
);
326 if (!(m0
->m_flags
& M_PKTHDR
))
327 panic("ofnet_start: no header mbuf");
328 len
= m0
->m_pkthdr
.len
;
332 bpf_mtap(ifp
->if_bpf
, m0
);
335 if (len
> ETHERMTU
+ sizeof(struct ether_header
)) {
336 /* packet too large, toss it */
342 for (bufp
= buf
; (m
= m0
) != NULL
;) {
343 memcpy(bufp
, mtod(m
, char *), m
->m_len
);
349 * We don't know if the interface will auto-pad for
350 * us, so make sure it's at least as large as a
351 * minimum size Ethernet packet.
354 if (len
< (ETHER_MIN_LEN
- ETHER_CRC_LEN
)) {
355 memset(bufp
, 0, ETHER_MIN_LEN
- ETHER_CRC_LEN
- len
);
356 bufp
+= ETHER_MIN_LEN
- ETHER_CRC_LEN
- len
;
360 if (OF_write(of
->sc_ihandle
, buf
, len
) != len
)
368 ofnet_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
370 struct ofnet_softc
*of
= ifp
->if_softc
;
371 struct ifaddr
*ifa
= (struct ifaddr
*)data
;
372 /* struct ifreq *ifr = (struct ifreq *)data; */
377 ifp
->if_flags
|= IFF_UP
;
379 switch (ifa
->ifa_addr
->sa_family
) {
382 arp_ifinit(ifp
, ifa
);
391 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != 0)
393 /* XXX re-use ether_ioctl() */
394 switch (ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) {
396 /* If interface is down, but running, stop it. */
400 /* If interface is up, but not running, start it. */
404 /* Other flags are ignored. */
409 error
= ether_ioctl(ifp
, cmd
, data
);
416 ofnet_watchdog(struct ifnet
*ifp
)
418 struct ofnet_softc
*of
= ifp
->if_softc
;
420 log(LOG_ERR
, "%s: device timeout\n", device_xname(&of
->sc_dev
));
428 ipkdbofstart(struct ipkdb_if
*kip
)
430 int unit
= kip
->unit
- 1;
433 ipkdbattach(kip
, &ipkdb_of
->sc_ethercom
);
437 ipkdbofleave(struct ipkdb_if
*kip
)
442 ipkdbofrcv(struct ipkdb_if
*kip
, u_char
*buf
, int poll
)
447 l
= OF_read(kip
->port
, buf
, ETHERMTU
);
450 } while (!poll
&& !l
);
455 ipkdbofsend(struct ipkdb_if
*kip
, u_char
*buf
, int l
)
457 OF_write(kip
->port
, buf
, l
);
461 ipkdbprobe(cfdata_t match
, void *aux
)
463 struct ipkdb_if
*kip
= aux
;
464 static char name
[256];
468 kip
->unit
= match
->cf_unit
+ 1;
470 if (!(kip
->port
= OF_open("net")))
472 if ((len
= OF_instance_to_path(kip
->port
, name
, sizeof name
- 1)) < 0 ||
476 if ((phandle
= OF_instance_to_package(kip
->port
)) == -1)
478 if (OF_getprop(phandle
, "mac-address", kip
->myenetaddr
,
479 sizeof kip
->myenetaddr
) < 0)
482 kip
->flags
|= IPKDB_MYHW
;
484 kip
->start
= ipkdbofstart
;
485 kip
->leave
= ipkdbofleave
;
486 kip
->receive
= ipkdbofrcv
;
487 kip
->send
= ipkdbofsend
;