xref: /freebsd/stand/libofw/ofw_net.c (revision 7c43148a)
1475008d6SBrandon Bergren /*-
2475008d6SBrandon Bergren  * Copyright (c) 2000-2001 Benno Rice
3475008d6SBrandon Bergren  * All rights reserved.
4475008d6SBrandon Bergren  *
5475008d6SBrandon Bergren  * Redistribution and use in source and binary forms, with or without
6475008d6SBrandon Bergren  * modification, are permitted provided that the following conditions
7475008d6SBrandon Bergren  * are met:
8475008d6SBrandon Bergren  * 1. Redistributions of source code must retain the above copyright
9475008d6SBrandon Bergren  *    notice, this list of conditions and the following disclaimer.
10475008d6SBrandon Bergren  * 2. Redistributions in binary form must reproduce the above copyright
11475008d6SBrandon Bergren  *    notice, this list of conditions and the following disclaimer in the
12475008d6SBrandon Bergren  *    documentation and/or other materials provided with the distribution.
13475008d6SBrandon Bergren  *
14475008d6SBrandon Bergren  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND
15475008d6SBrandon Bergren  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16475008d6SBrandon Bergren  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17475008d6SBrandon Bergren  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18475008d6SBrandon Bergren  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19475008d6SBrandon Bergren  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20475008d6SBrandon Bergren  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21475008d6SBrandon Bergren  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22475008d6SBrandon Bergren  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23475008d6SBrandon Bergren  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24475008d6SBrandon Bergren  * SUCH DAMAGE.
25475008d6SBrandon Bergren  */
26475008d6SBrandon Bergren 
27475008d6SBrandon Bergren #include <sys/param.h>
28475008d6SBrandon Bergren #include <sys/types.h>
29475008d6SBrandon Bergren #include <sys/socket.h>
30475008d6SBrandon Bergren 
31475008d6SBrandon Bergren #include <net/if.h>
32475008d6SBrandon Bergren #include <netinet/in.h>
33475008d6SBrandon Bergren #include <netinet/in_systm.h>
34475008d6SBrandon Bergren #include <netinet/if_ether.h>
35475008d6SBrandon Bergren #include <netinet/ip.h>
36475008d6SBrandon Bergren 
37475008d6SBrandon Bergren #include <stand.h>
38475008d6SBrandon Bergren #include <net.h>
39475008d6SBrandon Bergren #include <netif.h>
40475008d6SBrandon Bergren 
41b8ff248fSWarner Losh #include "libofw.h"
42475008d6SBrandon Bergren #include "openfirm.h"
43475008d6SBrandon Bergren 
44475008d6SBrandon Bergren static int	ofwn_probe(struct netif *, void *);
45475008d6SBrandon Bergren static int	ofwn_match(struct netif *, void *);
46475008d6SBrandon Bergren static void	ofwn_init(struct iodesc *, void *);
47475008d6SBrandon Bergren static ssize_t	ofwn_get(struct iodesc *, void **, time_t);
48475008d6SBrandon Bergren static ssize_t	ofwn_put(struct iodesc *, void *, size_t);
49475008d6SBrandon Bergren static void	ofwn_end(struct netif *);
50475008d6SBrandon Bergren 
51475008d6SBrandon Bergren extern struct netif_stats	ofwn_stats[];
52475008d6SBrandon Bergren 
53475008d6SBrandon Bergren struct netif_dif ofwn_ifs[] = {
544c4563e3SWarner Losh 	{
554c4563e3SWarner Losh 		.dif_unit=0,
564c4563e3SWarner Losh 		.dif_nsel=1,
574c4563e3SWarner Losh 		.dif_stats=&ofwn_stats[0],
584c4563e3SWarner Losh 		.dif_private=0,
594c4563e3SWarner Losh 	},
60475008d6SBrandon Bergren };
61475008d6SBrandon Bergren 
62475008d6SBrandon Bergren struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
63475008d6SBrandon Bergren 
64475008d6SBrandon Bergren struct netif_driver ofwnet = {
654c4563e3SWarner Losh 	.netif_bname="net",
664c4563e3SWarner Losh 	.netif_match=ofwn_match,
674c4563e3SWarner Losh 	.netif_probe=ofwn_probe,
684c4563e3SWarner Losh 	.netif_init=ofwn_init,
694c4563e3SWarner Losh 	.netif_get=ofwn_get,
704c4563e3SWarner Losh 	.netif_put=ofwn_put,
714c4563e3SWarner Losh 	.netif_end=ofwn_end,
724c4563e3SWarner Losh 	.netif_ifs=ofwn_ifs,
734c4563e3SWarner Losh 	.netif_nifs=nitems(ofwn_ifs)
74475008d6SBrandon Bergren };
75475008d6SBrandon Bergren 
76475008d6SBrandon Bergren static ihandle_t	netinstance;
77475008d6SBrandon Bergren 
78475008d6SBrandon Bergren static void		*dmabuf;
79475008d6SBrandon Bergren 
80475008d6SBrandon Bergren static int
ofwn_match(struct netif * nif,void * machdep_hint)81475008d6SBrandon Bergren ofwn_match(struct netif *nif, void *machdep_hint)
82475008d6SBrandon Bergren {
83475008d6SBrandon Bergren 	return 1;
84475008d6SBrandon Bergren }
85475008d6SBrandon Bergren 
86475008d6SBrandon Bergren static int
ofwn_probe(struct netif * nif,void * machdep_hint)87475008d6SBrandon Bergren ofwn_probe(struct netif *nif, void *machdep_hint)
88475008d6SBrandon Bergren {
89475008d6SBrandon Bergren 	return 0;
90475008d6SBrandon Bergren }
91475008d6SBrandon Bergren 
92475008d6SBrandon Bergren static ssize_t
ofwn_put(struct iodesc * desc,void * pkt,size_t len)93475008d6SBrandon Bergren ofwn_put(struct iodesc *desc, void *pkt, size_t len)
94475008d6SBrandon Bergren {
95475008d6SBrandon Bergren 	size_t			sendlen;
96475008d6SBrandon Bergren 	ssize_t			rv;
97475008d6SBrandon Bergren 
98475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
99475008d6SBrandon Bergren 	struct ether_header	*eh;
100475008d6SBrandon Bergren 	printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", desc, pkt, len);
101475008d6SBrandon Bergren 	eh = pkt;
102475008d6SBrandon Bergren 	printf("dst: %s ", ether_sprintf(eh->ether_dhost));
103475008d6SBrandon Bergren 	printf("src: %s ", ether_sprintf(eh->ether_shost));
104475008d6SBrandon Bergren 	printf("type: 0x%x\n", eh->ether_type & 0xffff);
105475008d6SBrandon Bergren #endif
106475008d6SBrandon Bergren 
107475008d6SBrandon Bergren 	sendlen = len;
108475008d6SBrandon Bergren 	if (sendlen < 60) {
109475008d6SBrandon Bergren 		sendlen = 60;
110475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
111475008d6SBrandon Bergren 		printf("netif_put: length padded to %d\n", sendlen);
112475008d6SBrandon Bergren #endif
113475008d6SBrandon Bergren 	}
114475008d6SBrandon Bergren 
115475008d6SBrandon Bergren 	if (dmabuf) {
116475008d6SBrandon Bergren 		bcopy(pkt, dmabuf, sendlen);
117475008d6SBrandon Bergren 		pkt = dmabuf;
118475008d6SBrandon Bergren 	}
119475008d6SBrandon Bergren 
120475008d6SBrandon Bergren 	rv = OF_write(netinstance, pkt, len);
121475008d6SBrandon Bergren 
122475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
123475008d6SBrandon Bergren 	printf("netif_put: OF_write returned %d\n", rv);
124475008d6SBrandon Bergren #endif
125475008d6SBrandon Bergren 
126475008d6SBrandon Bergren 	return rv;
127475008d6SBrandon Bergren }
128475008d6SBrandon Bergren 
129475008d6SBrandon Bergren static ssize_t
ofwn_get(struct iodesc * desc,void ** pkt,time_t timeout)130475008d6SBrandon Bergren ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
131475008d6SBrandon Bergren {
132475008d6SBrandon Bergren 	time_t	t;
133475008d6SBrandon Bergren 	ssize_t	length;
134475008d6SBrandon Bergren 	size_t	len;
135475008d6SBrandon Bergren 	char	*buf, *ptr;
136475008d6SBrandon Bergren 
137475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
138475008d6SBrandon Bergren 	printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
139475008d6SBrandon Bergren #endif
140475008d6SBrandon Bergren 
141475008d6SBrandon Bergren 	/*
142475008d6SBrandon Bergren 	 * We should read the "max-frame-size" int property instead,
143475008d6SBrandon Bergren 	 * but at this time the iodesc does not have mtu, so we will take
144475008d6SBrandon Bergren 	 * a small shortcut here.
145475008d6SBrandon Bergren 	 */
146475008d6SBrandon Bergren 	len = ETHER_MAX_LEN;
147aaeffe5bSToomas Soome 	buf = malloc(len + ETHER_ALIGN);
148475008d6SBrandon Bergren 	if (buf == NULL)
149475008d6SBrandon Bergren 		return (-1);
150475008d6SBrandon Bergren 	ptr = buf + ETHER_ALIGN;
151475008d6SBrandon Bergren 
152475008d6SBrandon Bergren 	t = getsecs();
153475008d6SBrandon Bergren 	do {
154475008d6SBrandon Bergren 		length = OF_read(netinstance, ptr, len);
155475008d6SBrandon Bergren 	} while ((length == -2 || length == 0) &&
156475008d6SBrandon Bergren 		(getsecs() - t < timeout));
157475008d6SBrandon Bergren 
158475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
159475008d6SBrandon Bergren 	printf("netif_get: received length=%d (%x)\n", length, length);
160475008d6SBrandon Bergren #endif
161475008d6SBrandon Bergren 
162475008d6SBrandon Bergren 	if (length < 12) {
163475008d6SBrandon Bergren 		free(buf);
164475008d6SBrandon Bergren 		return (-1);
165475008d6SBrandon Bergren 	}
166475008d6SBrandon Bergren 
167475008d6SBrandon Bergren #if defined(NETIF_VERBOSE_DEBUG)
168475008d6SBrandon Bergren 	{
169475008d6SBrandon Bergren 		char *ch = ptr;
170475008d6SBrandon Bergren 		int i;
171475008d6SBrandon Bergren 
172475008d6SBrandon Bergren 		for(i = 0; i < 96; i += 4) {
173475008d6SBrandon Bergren 			printf("%02x%02x%02x%02x  ", ch[i], ch[i+1],
174475008d6SBrandon Bergren 			    ch[i+2], ch[i+3]);
175475008d6SBrandon Bergren 		}
176475008d6SBrandon Bergren 		printf("\n");
177475008d6SBrandon Bergren 	}
178475008d6SBrandon Bergren #endif
179475008d6SBrandon Bergren 
180475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
181475008d6SBrandon Bergren 	{
182475008d6SBrandon Bergren 		struct ether_header *eh = ptr;
183475008d6SBrandon Bergren 
184475008d6SBrandon Bergren 		printf("dst: %s ", ether_sprintf(eh->ether_dhost));
185475008d6SBrandon Bergren 		printf("src: %s ", ether_sprintf(eh->ether_shost));
186475008d6SBrandon Bergren 		printf("type: 0x%x\n", eh->ether_type & 0xffff);
187475008d6SBrandon Bergren 	}
188475008d6SBrandon Bergren #endif
189475008d6SBrandon Bergren 
190475008d6SBrandon Bergren 	*pkt = buf;
191475008d6SBrandon Bergren 	return (length);
192475008d6SBrandon Bergren }
193475008d6SBrandon Bergren 
194475008d6SBrandon Bergren static void
ofwn_init(struct iodesc * desc,void * machdep_hint)195475008d6SBrandon Bergren ofwn_init(struct iodesc *desc, void *machdep_hint)
196475008d6SBrandon Bergren {
197475008d6SBrandon Bergren 	phandle_t	netdev;
198475008d6SBrandon Bergren 	char		path[64];
199475008d6SBrandon Bergren 	char		*ch;
200475008d6SBrandon Bergren 	int		pathlen;
201475008d6SBrandon Bergren 
202475008d6SBrandon Bergren 	pathlen = OF_getprop(chosen, "bootpath", path, 64);
203475008d6SBrandon Bergren 	if ((ch = strchr(path, ':')) != NULL)
204475008d6SBrandon Bergren 		*ch = '\0';
205475008d6SBrandon Bergren 	netdev = OF_finddevice(path);
206475008d6SBrandon Bergren 	if (OF_getprop(netdev, "local-mac-address", desc->myea, 6) == -1)
207475008d6SBrandon Bergren 		goto punt;
208475008d6SBrandon Bergren 
209475008d6SBrandon Bergren 	printf("boot: ethernet address: %s\n", ether_sprintf(desc->myea));
210475008d6SBrandon Bergren 
211475008d6SBrandon Bergren 	if ((netinstance = OF_open(path)) == -1) {
212475008d6SBrandon Bergren 		printf("Could not open network device.\n");
213475008d6SBrandon Bergren 		goto punt;
214475008d6SBrandon Bergren 	}
215475008d6SBrandon Bergren 
216475008d6SBrandon Bergren #if defined(NETIF_DEBUG)
217475008d6SBrandon Bergren 	printf("ofwn_init: Open Firmware instance handle: %08x\n", netinstance);
218475008d6SBrandon Bergren #endif
219272a882bSWarner Losh 	dmabuf = NULL;
220272a882bSWarner Losh 	if (OF_call_method("dma-alloc", netinstance, 1, 1, (64 * 1024), &dmabuf)
221272a882bSWarner Losh 	    < 0) {
222272a882bSWarner Losh 		printf("Failed to allocate DMA buffer (got %p).\n", dmabuf);
223272a882bSWarner Losh 		goto punt;
224272a882bSWarner Losh 	}
225272a882bSWarner Losh #if defined(NETIF_DEBUG)
226272a882bSWarner Losh 	printf("ofwn_init: allocated DMA buffer: %p\n", dmabuf);
227272a882bSWarner Losh #endif
228272a882bSWarner Losh 
229475008d6SBrandon Bergren 	return;
230475008d6SBrandon Bergren 
231475008d6SBrandon Bergren punt:
232475008d6SBrandon Bergren 	printf("\n");
233475008d6SBrandon Bergren 	printf("Could not boot from %s.\n", path);
234475008d6SBrandon Bergren 	OF_enter();
235475008d6SBrandon Bergren }
236475008d6SBrandon Bergren 
237475008d6SBrandon Bergren static void
ofwn_end(struct netif * nif)238475008d6SBrandon Bergren ofwn_end(struct netif *nif)
239475008d6SBrandon Bergren {
240475008d6SBrandon Bergren #ifdef BROKEN
241475008d6SBrandon Bergren 	/* dma-free freezes at least some Apple ethernet controllers */
242475008d6SBrandon Bergren 	OF_call_method("dma-free", netinstance, 2, 0, dmabuf, MAXPHYS);
243475008d6SBrandon Bergren #endif
244475008d6SBrandon Bergren 	OF_close(netinstance);
245475008d6SBrandon Bergren }
246475008d6SBrandon Bergren 
247475008d6SBrandon Bergren #if 0
248475008d6SBrandon Bergren int
249475008d6SBrandon Bergren ofwn_getunit(const char *path)
250475008d6SBrandon Bergren {
251475008d6SBrandon Bergren 	int		i;
252475008d6SBrandon Bergren 	char		newpath[255];
253475008d6SBrandon Bergren 
254475008d6SBrandon Bergren 	OF_canon(path, newpath, 254);
255475008d6SBrandon Bergren 
256475008d6SBrandon Bergren 	for (i = 0; i < nofwninfo; i++) {
257475008d6SBrandon Bergren 		printf(">>> test =\t%s\n", ofwninfo[i].ofwn_path);
258475008d6SBrandon Bergren 		if (strcmp(path, ofwninfo[i].ofwn_path) == 0)
259475008d6SBrandon Bergren 			return i;
260475008d6SBrandon Bergren 
261475008d6SBrandon Bergren 		if (strcmp(newpath, ofwninfo[i].ofwn_path) == 0)
262475008d6SBrandon Bergren 			return i;
263475008d6SBrandon Bergren 	}
264475008d6SBrandon Bergren 
265475008d6SBrandon Bergren 	return -1;
266475008d6SBrandon Bergren }
267475008d6SBrandon Bergren #endif
268b8ff248fSWarner Losh 
269b8ff248fSWarner Losh /*
270b8ff248fSWarner Losh  * To properly match network devices, we have to subclass the netdev device.
271b8ff248fSWarner Losh  * It has a different devdesc than a normal network device (which is fine:
272b8ff248fSWarner Losh  * it's a struct superset) and different matching criteria (since it has to
273b8ff248fSWarner Losh  * look at the path, find a handle and see if that handle is a network node
274b8ff248fSWarner Losh  * or not).
275b8ff248fSWarner Losh  */
276b8ff248fSWarner Losh 
277b8ff248fSWarner Losh static int ofwnd_init(void);
278b8ff248fSWarner Losh static int ofwnd_parsedev(struct devdesc **, const char *, const char **);
279b8ff248fSWarner Losh static bool ofwnd_match(struct devsw *, const char *);
280b8ff248fSWarner Losh static char *ofwnd_fmtdev(struct devdesc *);
281b8ff248fSWarner Losh 
282b8ff248fSWarner Losh struct devsw ofw_netdev = {
283b8ff248fSWarner Losh 	.dv_name = "network",
284b8ff248fSWarner Losh 	.dv_type = DEVT_NET,
285b8ff248fSWarner Losh 	.dv_init = ofwnd_init,
286b8ff248fSWarner Losh 	.dv_match = ofwnd_match,
287b8ff248fSWarner Losh 	.dv_fmtdev = ofwnd_fmtdev,
288b8ff248fSWarner Losh 	.dv_parsedev = ofwnd_parsedev,
289b8ff248fSWarner Losh };
290b8ff248fSWarner Losh 
ofwnd_init(void)291b8ff248fSWarner Losh static int ofwnd_init(void)
292b8ff248fSWarner Losh {
293b8ff248fSWarner Losh 	netdev.dv_init();
294b8ff248fSWarner Losh 	ofw_netdev.dv_strategy = netdev.dv_strategy;
295b8ff248fSWarner Losh 	ofw_netdev.dv_open = netdev.dv_open;
296b8ff248fSWarner Losh 	ofw_netdev.dv_close = netdev.dv_close;
297b8ff248fSWarner Losh 	ofw_netdev.dv_ioctl = netdev.dv_ioctl;
298b8ff248fSWarner Losh 	ofw_netdev.dv_print = netdev.dv_print;
299b8ff248fSWarner Losh 	ofw_netdev.dv_fmtdev = netdev.dv_fmtdev;
300b8ff248fSWarner Losh 	/* parsedev is unique to ofwnd */
301b8ff248fSWarner Losh 	/* match is unique to ofwnd */
302b8ff248fSWarner Losh 	return (0);
303b8ff248fSWarner Losh }
304b8ff248fSWarner Losh 
305b8ff248fSWarner Losh static int
ofwnd_parsedev(struct devdesc ** dev,const char * devspec,const char ** path)306b8ff248fSWarner Losh ofwnd_parsedev(struct devdesc **dev, const char *devspec, const char **path)
307b8ff248fSWarner Losh {
308f9ce8da8SWarner Losh 	return (ofw_common_parsedev(dev, devspec, path, ofw_netdev.dv_name));
309b8ff248fSWarner Losh }
310b8ff248fSWarner Losh 
311b8ff248fSWarner Losh static bool
ofwnd_match(struct devsw * devsw,const char * devspec)312b8ff248fSWarner Losh ofwnd_match(struct devsw *devsw, const char *devspec)
313b8ff248fSWarner Losh {
314b8ff248fSWarner Losh 	const char *path;
315b8ff248fSWarner Losh 
316b8ff248fSWarner Losh 	return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1);
317b8ff248fSWarner Losh }
318b8ff248fSWarner Losh 
319b8ff248fSWarner Losh static char *
ofwnd_fmtdev(struct devdesc * idev)320b8ff248fSWarner Losh ofwnd_fmtdev(struct devdesc *idev)
321b8ff248fSWarner Losh {
322b8ff248fSWarner Losh 	struct ofw_devdesc *dev = (struct ofw_devdesc *)idev;
323b8ff248fSWarner Losh 
324b8ff248fSWarner Losh 	return (dev->d_path);
325b8ff248fSWarner Losh }
326