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