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