xref: /freebsd/stand/libofw/ofw_net.c (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
1 /*-
2  * Copyright (c) 2000-2001 Benno Rice
3  * 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  *
14  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/if_ether.h>
38 #include <netinet/ip.h>
39 
40 #include <stand.h>
41 #include <net.h>
42 #include <netif.h>
43 
44 #include "libofw.h"
45 #include "openfirm.h"
46 
47 static int	ofwn_probe(struct netif *, void *);
48 static int	ofwn_match(struct netif *, void *);
49 static void	ofwn_init(struct iodesc *, void *);
50 static ssize_t	ofwn_get(struct iodesc *, void **, time_t);
51 static ssize_t	ofwn_put(struct iodesc *, void *, size_t);
52 static void	ofwn_end(struct netif *);
53 
54 extern struct netif_stats	ofwn_stats[];
55 
56 struct netif_dif ofwn_ifs[] = {
57 	{
58 		.dif_unit=0,
59 		.dif_nsel=1,
60 		.dif_stats=&ofwn_stats[0],
61 		.dif_private=0,
62 	},
63 };
64 
65 struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
66 
67 struct netif_driver ofwnet = {
68 	.netif_bname="net",
69 	.netif_match=ofwn_match,
70 	.netif_probe=ofwn_probe,
71 	.netif_init=ofwn_init,
72 	.netif_get=ofwn_get,
73 	.netif_put=ofwn_put,
74 	.netif_end=ofwn_end,
75 	.netif_ifs=ofwn_ifs,
76 	.netif_nifs=nitems(ofwn_ifs)
77 };
78 
79 static ihandle_t	netinstance;
80 
81 static void		*dmabuf;
82 
83 static int
84 ofwn_match(struct netif *nif, void *machdep_hint)
85 {
86 	return 1;
87 }
88 
89 static int
90 ofwn_probe(struct netif *nif, void *machdep_hint)
91 {
92 	return 0;
93 }
94 
95 static ssize_t
96 ofwn_put(struct iodesc *desc, void *pkt, size_t len)
97 {
98 	size_t			sendlen;
99 	ssize_t			rv;
100 
101 #if defined(NETIF_DEBUG)
102 	struct ether_header	*eh;
103 	printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", desc, pkt, len);
104 	eh = pkt;
105 	printf("dst: %s ", ether_sprintf(eh->ether_dhost));
106 	printf("src: %s ", ether_sprintf(eh->ether_shost));
107 	printf("type: 0x%x\n", eh->ether_type & 0xffff);
108 #endif
109 
110 	sendlen = len;
111 	if (sendlen < 60) {
112 		sendlen = 60;
113 #if defined(NETIF_DEBUG)
114 		printf("netif_put: length padded to %d\n", sendlen);
115 #endif
116 	}
117 
118 	if (dmabuf) {
119 		bcopy(pkt, dmabuf, sendlen);
120 		pkt = dmabuf;
121 	}
122 
123 	rv = OF_write(netinstance, pkt, len);
124 
125 #if defined(NETIF_DEBUG)
126 	printf("netif_put: OF_write returned %d\n", rv);
127 #endif
128 
129 	return rv;
130 }
131 
132 static ssize_t
133 ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
134 {
135 	time_t	t;
136 	ssize_t	length;
137 	size_t	len;
138 	char	*buf, *ptr;
139 
140 #if defined(NETIF_DEBUG)
141 	printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
142 #endif
143 
144 	/*
145 	 * We should read the "max-frame-size" int property instead,
146 	 * but at this time the iodesc does not have mtu, so we will take
147 	 * a small shortcut here.
148 	 */
149 	len = ETHER_MAX_LEN;
150 	buf = malloc(len + ETHER_ALIGN);
151 	if (buf == NULL)
152 		return (-1);
153 	ptr = buf + ETHER_ALIGN;
154 
155 	t = getsecs();
156 	do {
157 		length = OF_read(netinstance, ptr, len);
158 	} while ((length == -2 || length == 0) &&
159 		(getsecs() - t < timeout));
160 
161 #if defined(NETIF_DEBUG)
162 	printf("netif_get: received length=%d (%x)\n", length, length);
163 #endif
164 
165 	if (length < 12) {
166 		free(buf);
167 		return (-1);
168 	}
169 
170 #if defined(NETIF_VERBOSE_DEBUG)
171 	{
172 		char *ch = ptr;
173 		int i;
174 
175 		for(i = 0; i < 96; i += 4) {
176 			printf("%02x%02x%02x%02x  ", ch[i], ch[i+1],
177 			    ch[i+2], ch[i+3]);
178 		}
179 		printf("\n");
180 	}
181 #endif
182 
183 #if defined(NETIF_DEBUG)
184 	{
185 		struct ether_header *eh = ptr;
186 
187 		printf("dst: %s ", ether_sprintf(eh->ether_dhost));
188 		printf("src: %s ", ether_sprintf(eh->ether_shost));
189 		printf("type: 0x%x\n", eh->ether_type & 0xffff);
190 	}
191 #endif
192 
193 	*pkt = buf;
194 	return (length);
195 }
196 
197 static void
198 ofwn_init(struct iodesc *desc, void *machdep_hint)
199 {
200 	phandle_t	netdev;
201 	char		path[64];
202 	char		*ch;
203 	int		pathlen;
204 
205 	pathlen = OF_getprop(chosen, "bootpath", path, 64);
206 	if ((ch = strchr(path, ':')) != NULL)
207 		*ch = '\0';
208 	netdev = OF_finddevice(path);
209 	if (OF_getprop(netdev, "local-mac-address", desc->myea, 6) == -1)
210 		goto punt;
211 
212 	printf("boot: ethernet address: %s\n", ether_sprintf(desc->myea));
213 
214 	if ((netinstance = OF_open(path)) == -1) {
215 		printf("Could not open network device.\n");
216 		goto punt;
217 	}
218 
219 #if defined(NETIF_DEBUG)
220 	printf("ofwn_init: Open Firmware instance handle: %08x\n", netinstance);
221 #endif
222 	dmabuf = NULL;
223 	if (OF_call_method("dma-alloc", netinstance, 1, 1, (64 * 1024), &dmabuf)
224 	    < 0) {
225 		printf("Failed to allocate DMA buffer (got %p).\n", dmabuf);
226 		goto punt;
227 	}
228 #if defined(NETIF_DEBUG)
229 	printf("ofwn_init: allocated DMA buffer: %p\n", dmabuf);
230 #endif
231 
232 	return;
233 
234 punt:
235 	printf("\n");
236 	printf("Could not boot from %s.\n", path);
237 	OF_enter();
238 }
239 
240 static void
241 ofwn_end(struct netif *nif)
242 {
243 #ifdef BROKEN
244 	/* dma-free freezes at least some Apple ethernet controllers */
245 	OF_call_method("dma-free", netinstance, 2, 0, dmabuf, MAXPHYS);
246 #endif
247 	OF_close(netinstance);
248 }
249 
250 #if 0
251 int
252 ofwn_getunit(const char *path)
253 {
254 	int		i;
255 	char		newpath[255];
256 
257 	OF_canon(path, newpath, 254);
258 
259 	for (i = 0; i < nofwninfo; i++) {
260 		printf(">>> test =\t%s\n", ofwninfo[i].ofwn_path);
261 		if (strcmp(path, ofwninfo[i].ofwn_path) == 0)
262 			return i;
263 
264 		if (strcmp(newpath, ofwninfo[i].ofwn_path) == 0)
265 			return i;
266 	}
267 
268 	return -1;
269 }
270 #endif
271 
272 /*
273  * To properly match network devices, we have to subclass the netdev device.
274  * It has a different devdesc than a normal network device (which is fine:
275  * it's a struct superset) and different matching criteria (since it has to
276  * look at the path, find a handle and see if that handle is a network node
277  * or not).
278  */
279 
280 static int ofwnd_init(void);
281 static int ofwnd_parsedev(struct devdesc **, const char *, const char **);
282 static bool ofwnd_match(struct devsw *, const char *);
283 static char *ofwnd_fmtdev(struct devdesc *);
284 
285 struct devsw ofw_netdev = {
286 	.dv_name = "network",
287 	.dv_type = DEVT_NET,
288 	.dv_init = ofwnd_init,
289 	.dv_match = ofwnd_match,
290 	.dv_fmtdev = ofwnd_fmtdev,
291 	.dv_parsedev = ofwnd_parsedev,
292 };
293 
294 static int ofwnd_init(void)
295 {
296 	netdev.dv_init();
297 	ofw_netdev.dv_strategy = netdev.dv_strategy;
298 	ofw_netdev.dv_open = netdev.dv_open;
299 	ofw_netdev.dv_close = netdev.dv_close;
300 	ofw_netdev.dv_ioctl = netdev.dv_ioctl;
301 	ofw_netdev.dv_print = netdev.dv_print;
302 	ofw_netdev.dv_fmtdev = netdev.dv_fmtdev;
303 	/* parsedev is unique to ofwnd */
304 	/* match is unique to ofwnd */
305 	return (0);
306 }
307 
308 static int
309 ofwnd_parsedev(struct devdesc **dev, const char *devspec, const char **path)
310 {
311 	return (ofw_common_parsedev(dev, devspec, path, ofw_netdev.dv_name));
312 }
313 
314 static bool
315 ofwnd_match(struct devsw *devsw, const char *devspec)
316 {
317 	const char *path;
318 
319 	return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1);
320 }
321 
322 static char *
323 ofwnd_fmtdev(struct devdesc *idev)
324 {
325 	struct ofw_devdesc *dev = (struct ofw_devdesc *)idev;
326 
327 	return (dev->d_path);
328 }
329