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