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