if_fwe.c revision 108712
1/* 2 * Copyright (C) 2002 3 * Hidetoshi Shimokawa. 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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * 16 * This product includes software developed by Hidetoshi Shimokawa. 17 * 18 * 4. Neither the name of the author nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $FreeBSD: head/sys/dev/firewire/if_fwe.c 108712 2003-01-05 14:58:45Z simokawa $ 35 */ 36 37#include "opt_inet.h" 38 39#include <sys/param.h> 40#include <sys/conf.h> 41#include <sys/kernel.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/socket.h> 45#include <sys/sockio.h> 46#include <sys/sysctl.h> 47#include <sys/systm.h> 48#include <sys/module.h> 49#include <sys/bus.h> 50 51#include <net/bpf.h> 52#include <net/ethernet.h> 53#include <net/if.h> 54#include <net/if_arp.h> 55#include <net/if_vlan_var.h> 56#include <net/route.h> 57 58#include <netinet/in.h> 59 60#include <dev/firewire/firewire.h> 61#include <dev/firewire/firewirereg.h> 62#include <dev/firewire/if_fwevar.h> 63 64#define FWEDEBUG if (fwedebug) printf 65#define MAX_QUEUED IFQ_MAXLEN /* 50 */ 66 67/* network interface */ 68static void fwe_start __P((struct ifnet *)); 69static int fwe_ioctl __P((struct ifnet *, u_long, caddr_t)); 70static void fwe_init __P((void *)); 71 72static void fwe_as_output __P((struct fwe_softc *, struct ifnet *)); 73static void fwe_as_input __P((struct fw_xferq *)); 74 75static int fwedebug = 0; 76static int stream_ch = 1; 77 78MALLOC_DECLARE(M_FWE); 79MALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface"); 80SYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, ""); 81SYSCTL_DECL(_hw_firewire); 82SYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0, 83 "Ethernet Emulation Subsystem"); 84SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0, 85 "Stream channel to use"); 86 87#ifdef DEVICE_POLLING 88#define FWE_POLL_REGISTER(func, fwe, ifp) \ 89 if (ether_poll_register(func, ifp)) { \ 90 struct firewire_comm *fc = (fwe)->fd.fc; \ 91 fc->set_intr(fc, 0); \ 92 } 93 94#define FWE_POLL_DEREGISTER(fwe, ifp) \ 95 do { \ 96 struct firewire_comm *fc = (fwe)->fd.fc; \ 97 ether_poll_deregister(ifp); \ 98 fc->set_intr(fc, 1); \ 99 } while(0) \ 100 101static poll_handler_t fwe_poll; 102 103static void 104fwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 105{ 106 struct fwe_softc *fwe; 107 struct firewire_comm *fc; 108 109 fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 110 fc = fwe->fd.fc; 111 if (cmd == POLL_DEREGISTER) { 112 /* enable interrupts */ 113 fc->set_intr(fc, 1); 114 return; 115 } 116 fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); 117} 118#else 119#define FWE_POLL_REGISTER(func, fwe, ifp) 120#define FWE_POLL_DEREGISTER(fwe, ifp) 121#endif 122static void 123fwe_identify(driver_t *driver, device_t parent) 124{ 125 BUS_ADD_CHILD(parent, 0, "if_fwe", device_get_unit(parent)); 126} 127 128static int 129fwe_probe(device_t dev) 130{ 131 device_t pa; 132 133 pa = device_get_parent(dev); 134 if(device_get_unit(dev) != device_get_unit(pa)){ 135 return(ENXIO); 136 } 137 138 device_set_desc(dev, "Ethernet over FireWire"); 139 return (0); 140} 141 142static int 143fwe_attach(device_t dev) 144{ 145 struct fwe_softc *fwe; 146 struct ifnet *ifp; 147 int unit, s; 148 u_char *eaddr; 149 150 fwe = ((struct fwe_softc *)device_get_softc(dev)); 151 unit = device_get_unit(dev); 152 153 bzero(fwe, sizeof(struct fwe_softc)); 154 /* XXX */ 155 fwe->stream_ch = stream_ch; 156 fwe->dma_ch = -1; 157 158 fwe->fd.fc = device_get_ivars(dev); 159 fwe->fd.dev = dev; 160 fwe->fd.post_explore = NULL; 161 fwe->eth_softc.fwe = fwe; 162 163 fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM; 164 fwe->pkt_hdr.mode.stream.sy = 0; 165 fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 166 167 /* generate fake MAC address: first and last 3bytes from eui64 */ 168#define LOCAL (0x02) 169#define GROUP (0x01) 170 eaddr = &fwe->eth_softc.arpcom.ac_enaddr[0]; 171 eaddr[0] = (fwe->fd.fc->eui[0] | LOCAL) & ~GROUP; 172 eaddr[1] = fwe->fd.fc->eui[1]; 173 eaddr[2] = fwe->fd.fc->eui[2]; 174 eaddr[3] = fwe->fd.fc->eui[5]; 175 eaddr[4] = fwe->fd.fc->eui[6]; 176 eaddr[5] = fwe->fd.fc->eui[7]; 177 printf("if_fwe%d: Fake Ethernet address: " 178 "%02x:%02x:%02x:%02x:%02x:%02x\n", unit, 179 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 180 181 /* fill the rest and attach interface */ 182 ifp = &fwe->fwe_if; 183 ifp->if_softc = &fwe->eth_softc; 184 185 ifp->if_unit = unit; 186 ifp->if_name = "fwe"; 187 ifp->if_init = fwe_init; 188 ifp->if_output = ether_output; 189 ifp->if_start = fwe_start; 190 ifp->if_ioctl = fwe_ioctl; 191 ifp->if_mtu = ETHERMTU; 192 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 193 ifp->if_snd.ifq_maxlen = FWMAXQUEUE - 1; 194 195 s = splimp(); 196#if __FreeBSD_version >= 500000 197 ether_ifattach(ifp, eaddr); 198#else 199 ether_ifattach(ifp, 1); 200#endif 201 splx(s); 202 203 /* Tell the upper layer(s) we support long frames. */ 204 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 205#if __FreeBSD_version >= 500000 206 ifp->if_capabilities |= IFCAP_VLAN_MTU; 207#endif 208 209 ifp->if_snd.ifq_maxlen = MAX_QUEUED - 1; 210 211 FWEDEBUG("interface %s%d created.\n", ifp->if_name, ifp->if_unit); 212 return 0; 213} 214 215static void 216fwe_stop(struct fwe_softc *fwe) 217{ 218 struct firewire_comm *fc; 219 struct fw_xferq *xferq; 220 struct ifnet *ifp = &fwe->fwe_if; 221 222 fc = fwe->fd.fc; 223 224 FWE_POLL_DEREGISTER(fwe, ifp); 225 226 if (fwe->dma_ch >= 0) { 227 xferq = fc->ir[fwe->dma_ch]; 228 229 if (xferq->flag & FWXFERQ_RUNNING) 230 fc->irx_disable(fc, fwe->dma_ch); 231 xferq->flag &= 232 ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_HANDLER); 233 /* XXX dequeue xferq->q */ 234 fwe->dma_ch = -1; 235 } 236 237 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 238} 239 240static int 241fwe_detach(device_t dev) 242{ 243 struct fwe_softc *fwe; 244 int s; 245 246 fwe = (struct fwe_softc *)device_get_softc(dev); 247 s = splimp(); 248 249 fwe_stop(fwe); 250#if __FreeBSD_version >= 500000 251 ether_ifdetach(&fwe->fwe_if); 252#else 253 ether_ifdetach(&fwe->fwe_if, 1); 254#endif 255 256 splx(s); 257 return 0; 258} 259 260 261static void 262fwe_init(void *arg) 263{ 264 struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe; 265 struct firewire_comm *fc; 266 struct ifnet *ifp = &fwe->fwe_if; 267 struct fw_xferq *xferq; 268 int i; 269 270 FWEDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 271 272 /* XXX keep promiscoud mode */ 273 ifp->if_flags |= IFF_PROMISC; 274 275 fc = fwe->fd.fc; 276#define START 0 277 if (fwe->dma_ch < 0) { 278 xferq = NULL; 279 for (i = START; i < fc->nisodma; i ++) { 280 xferq = fc->ir[i]; 281 if ((xferq->flag & FWXFERQ_OPEN) == 0) 282 break; 283 } 284 285 if (xferq == NULL) { 286 printf("no free dma channel\n"); 287 return; 288 } 289 fwe->dma_ch = i; 290 fwe->stream_ch = stream_ch; 291 fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 292 /* allocate DMA channel and init packet mode */ 293 xferq->flag |= FWXFERQ_OPEN | FWXFERQ_PACKET; 294 xferq->flag |= fwe->stream_ch & 0xff; 295 /* register fwe_input handler */ 296 xferq->sc = (caddr_t) fwe; 297 xferq->hand = fwe_as_input; 298 xferq->flag |= FWXFERQ_HANDLER; 299 } else 300 xferq = fc->ir[fwe->dma_ch]; 301 302 303 /* start dma */ 304 if ((xferq->flag & FWXFERQ_RUNNING) == 0) 305 fc->irx_enable(fc, fwe->dma_ch); 306 307 ifp->if_flags |= IFF_RUNNING; 308 ifp->if_flags &= ~IFF_OACTIVE; 309 310 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); 311#if 0 312 /* attempt to start output */ 313 fwe_start(ifp); 314#endif 315} 316 317 318static int 319fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 320{ 321 struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 322 struct ifstat *ifs = NULL; 323 int s, error, len; 324 325 switch (cmd) { 326 case SIOCSIFFLAGS: 327 s = splimp(); 328 if (ifp->if_flags & IFF_UP) { 329 if (!(ifp->if_flags & IFF_RUNNING)) 330 fwe_init(&fwe->eth_softc); 331 } else { 332 if (ifp->if_flags & IFF_RUNNING) 333 fwe_stop(fwe); 334 } 335 /* XXX keep promiscoud mode */ 336 ifp->if_flags |= IFF_PROMISC; 337 splx(s); 338 break; 339 case SIOCADDMULTI: 340 case SIOCDELMULTI: 341 break; 342 343 case SIOCGIFSTATUS: 344 s = splimp(); 345 ifs = (struct ifstat *)data; 346 len = strlen(ifs->ascii); 347 if (len < sizeof(ifs->ascii)) 348 snprintf(ifs->ascii + len, 349 sizeof(ifs->ascii) - len, 350 "\tch %d dma %d\n", 351 fwe->stream_ch, fwe->dma_ch); 352 splx(s); 353 break; 354#if __FreeBSD_version >= 500000 355 default: 356#else 357 case SIOCSIFADDR: 358 case SIOCGIFADDR: 359 case SIOCSIFMTU: 360#endif 361 s = splimp(); 362 error = ether_ioctl(ifp, cmd, data); 363 splx(s); 364 return (error); 365#if __FreeBSD_version < 500000 366 default: 367 return (EINVAL); 368#endif 369 } 370 371 return (0); 372} 373 374static void 375fwe_start(struct ifnet *ifp) 376{ 377 struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 378 int s; 379 380#if 1 381 FWEDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 382 383 if (fwe->dma_ch < 0) { 384 struct mbuf *m = NULL; 385 386 FWEDEBUG("%s%d not ready.\n", ifp->if_name, ifp->if_unit); 387 388 s = splimp(); 389 do { 390 IF_DEQUEUE(&ifp->if_snd, m); 391 if (m != NULL) 392 m_freem(m); 393 ifp->if_oerrors ++; 394 } while (m != NULL); 395 splx(s); 396 397 return; 398 } 399 400#endif 401 s = splimp(); 402 ifp->if_flags |= IFF_OACTIVE; 403 404 if (ifp->if_snd.ifq_len != 0) 405 fwe_as_output(fwe, ifp); 406 407 ifp->if_flags &= ~IFF_OACTIVE; 408 splx(s); 409} 410 411 412static void 413fwe_output_callback(struct fw_xfer *xfer) 414{ 415 struct fwe_softc *fwe; 416 struct ifnet *ifp; 417 418 fwe = (struct fwe_softc *)xfer->sc; 419 /* XXX error check */ 420 FWEDEBUG("resp = %d\n", xfer->resp); 421 m_freem(xfer->mbuf); 422 xfer->send.buf = NULL; 423 fw_xfer_free(xfer); 424#if 1 425 /* XXX for queue full */ 426 ifp = &fwe->fwe_if; 427 if (ifp->if_snd.ifq_head != NULL) 428 fwe_start(ifp); 429#endif 430} 431 432#define HDR_LEN 4 433#define ALIGN_PAD 2 434/* Async. stream output */ 435static void 436fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp) 437{ 438 struct mbuf *m; 439 struct fw_xfer *xfer; 440 struct fw_xferq *xferq; 441 struct fw_pkt *fp; 442 int i = 0; 443 444 xfer = NULL; 445 xferq = fwe->fd.fc->atq; 446 while (xferq->queued < xferq->maxq) { 447 IF_DEQUEUE(&ifp->if_snd, m); 448 if (m == NULL) 449 break; 450 xfer = fw_xfer_alloc(); 451 if (xfer == NULL) { 452 return; 453 } 454#if __FreeBSD_version >= 500000 455 BPF_MTAP(ifp, m); 456#else 457 if (ifp->if_bpf != NULL) 458 bpf_mtap(ifp, m); 459#endif 460 461 xfer->send.off = 0; 462 xfer->spd = 2; 463 xfer->fc = fwe->fd.fc; 464 xfer->retry_req = fw_asybusy; 465 xfer->sc = (caddr_t)fwe; 466 xfer->act.hand = fwe_output_callback; 467 468 /* keep ip packet alignment for alpha */ 469 M_PREPEND(m, ALIGN_PAD, M_DONTWAIT); 470 fp = (struct fw_pkt *)&xfer->dst; /* XXX */ 471 xfer->dst = *((int32_t *)&fwe->pkt_hdr); 472 fp->mode.stream.len = htons(m->m_pkthdr.len); 473 xfer->send.buf = (caddr_t) fp; 474 xfer->mbuf = m; 475 xfer->send.len = m->m_pkthdr.len + HDR_LEN; 476 477 i++; 478 if (fw_asyreq(xfer->fc, -1, xfer) != 0) { 479 /* error */ 480 ifp->if_oerrors ++; 481 /* XXX set error code */ 482 fwe_output_callback(xfer); 483 } else { 484 ifp->if_opackets ++; 485 } 486 } 487#if 0 488 if (i > 1) 489 printf("%d queued\n", i); 490#endif 491 if (xfer != NULL) 492 xferq->start(xfer->fc); 493} 494 495#if __FreeBSD_version >= 500000 496static void 497fwe_free(void *buf, void *args) 498{ 499 FWEDEBUG("fwe_free:\n"); 500 free(buf, M_DEVBUF); 501} 502 503#else 504static void 505fwe_free(caddr_t buf, u_int size) 506{ 507 int *p; 508 FWEDEBUG("fwe_free:\n"); 509 p = (int *)buf; 510 (*p) --; 511 if (*p < 1) 512 free(buf, M_DEVBUF); 513} 514 515static void 516fwe_ref(caddr_t buf, u_int size) 517{ 518 int *p; 519 520 FWEDEBUG("fwe_ref: called\n"); 521 p = (int *)buf; 522 (*p) ++; 523} 524#endif 525 526/* Async. stream output */ 527static void 528fwe_as_input(struct fw_xferq *xferq) 529{ 530 struct mbuf *m; 531 struct ether_header *eh; 532 struct ifnet *ifp; 533 struct fw_xfer *xfer; 534 struct fwe_softc *fwe; 535 u_char *c; 536 int len; 537 caddr_t p; 538 539 fwe = (struct fwe_softc *)xferq->sc; 540 ifp = &fwe->fwe_if; 541#if 0 542 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); 543#endif 544 while ((xfer = STAILQ_FIRST(&xferq->q)) != NULL) { 545 STAILQ_REMOVE_HEAD(&xferq->q, link); 546 xferq->queued --; 547 MGETHDR(m, M_DONTWAIT, MT_DATA); 548 if (m == NULL) { 549 printf("MGETHDR failed\n"); 550 fw_xfer_free(xfer); 551 return; 552 } 553 len = xfer->recv.off + xfer->recv.len; 554 FWEDEBUG("fwe_as_input len=%d\n", len); 555#if __FreeBSD_version >= 500000 556 MEXTADD(m, xfer->recv.buf, len, fwe_free, NULL, 0, EXT_NET_DRV); 557#else 558 m->m_flags |= M_EXT; 559 m->m_ext.ext_buf = xfer->recv.buf; 560 m->m_ext.ext_size = len; 561 m->m_ext.ext_free = fwe_free; 562 m->m_ext.ext_ref = fwe_ref; 563 *((int *)m->m_ext.ext_buf) = 1; /* XXX refcount */ 564#endif 565 p = xfer->recv.buf + xfer->recv.off + HDR_LEN + ALIGN_PAD; 566 eh = (struct ether_header *)p; 567#if __FreeBSD_version >= 500000 568 len -= xfer->recv.off + HDR_LEN + ALIGN_PAD; 569#else 570 p += sizeof(struct ether_header); 571 len -= xfer->recv.off + HDR_LEN + ALIGN_PAD 572 + sizeof(struct ether_header); 573#endif 574 m->m_data = p; 575 m->m_len = m->m_pkthdr.len = len; 576 m->m_pkthdr.rcvif = ifp; 577 c = (char *)eh; 578#if 0 579 FWEDEBUG("%02x %02x %02x %02x %02x %02x\n" 580 "%02x %02x %02x %02x %02x %02x\n" 581 "%02x %02x %02x %02x\n" 582 "%02x %02x %02x %02x\n" 583 "%02x %02x %02x %02x\n" 584 "%02x %02x %02x %02x\n", 585 c[0], c[1], c[2], c[3], c[4], c[5], 586 c[6], c[7], c[8], c[9], c[10], c[11], 587 c[12], c[13], c[14], c[15], 588 c[16], c[17], c[18], c[19], 589 c[20], c[21], c[22], c[23], 590 c[20], c[21], c[22], c[23] 591 ); 592#endif 593#if __FreeBSD_version >= 500000 594 (*ifp->if_input)(ifp, m); 595#else 596 ether_input(ifp, eh, m); 597#endif 598 ifp->if_ipackets ++; 599 600 xfer->recv.buf = NULL; 601 fw_xfer_free(xfer); 602 } 603} 604 605 606static devclass_t fwe_devclass; 607 608static device_method_t fwe_methods[] = { 609 /* device interface */ 610 DEVMETHOD(device_identify, fwe_identify), 611 DEVMETHOD(device_probe, fwe_probe), 612 DEVMETHOD(device_attach, fwe_attach), 613 DEVMETHOD(device_detach, fwe_detach), 614 { 0, 0 } 615}; 616 617static driver_t fwe_driver = { 618 "if_fwe", 619 fwe_methods, 620 sizeof(struct fwe_softc), 621}; 622 623 624DRIVER_MODULE(if_fwe, firewire, fwe_driver, fwe_devclass, 0, 0); 625MODULE_VERSION(if_fwe, 1); 626MODULE_DEPEND(if_fwe, firewire, 1, 1, 1); 627