if_fwe.c revision 151229
1103285Sikob/*- 2113584Ssimokawa * Copyright (c) 2002-2003 3103285Sikob * Hidetoshi Shimokawa. All rights reserved. 4103285Sikob * 5103285Sikob * Redistribution and use in source and binary forms, with or without 6103285Sikob * modification, are permitted provided that the following conditions 7103285Sikob * are met: 8103285Sikob * 1. Redistributions of source code must retain the above copyright 9103285Sikob * notice, this list of conditions and the following disclaimer. 10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer in the 12103285Sikob * documentation and/or other materials provided with the distribution. 13103285Sikob * 3. All advertising materials mentioning features or use of this software 14103285Sikob * must display the following acknowledgement: 15103285Sikob * 16103285Sikob * This product includes software developed by Hidetoshi Shimokawa. 17103285Sikob * 18103285Sikob * 4. Neither the name of the author nor the names of its contributors 19103285Sikob * may be used to endorse or promote products derived from this software 20103285Sikob * without specific prior written permission. 21103285Sikob * 22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32103285Sikob * SUCH DAMAGE. 33103285Sikob * 34103285Sikob * $FreeBSD: head/sys/dev/firewire/if_fwe.c 151229 2005-10-11 07:30:06Z glebius $ 35103285Sikob */ 36103285Sikob 37103285Sikob#ifdef HAVE_KERNEL_OPTION_HEADERS 38103285Sikob#include "opt_device_polling.h" 39103285Sikob#include "opt_inet.h" 40103285Sikob#endif 41103285Sikob 42103285Sikob#include <sys/param.h> 43103285Sikob#include <sys/kernel.h> 44103285Sikob#include <sys/malloc.h> 45103285Sikob#include <sys/mbuf.h> 46103285Sikob#include <sys/socket.h> 47103285Sikob#include <sys/sockio.h> 48103285Sikob#include <sys/sysctl.h> 49113584Ssimokawa#include <sys/systm.h> 50103285Sikob#include <sys/module.h> 51103285Sikob#include <sys/bus.h> 52103285Sikob#include <machine/bus.h> 53103285Sikob 54103285Sikob#include <net/bpf.h> 55103285Sikob#include <net/ethernet.h> 56103285Sikob#include <net/if.h> 57103285Sikob#include <net/if_arp.h> 58103285Sikob#include <net/if_types.h> 59103285Sikob#ifdef __DragonFly__ 60103285Sikob#include <net/vlan/if_vlan_var.h> 61103285Sikob#include <bus/firewire/firewire.h> 62111942Ssimokawa#include <bus/firewire/firewirereg.h> 63111942Ssimokawa#include "if_fwevar.h" 64103285Sikob#else 65103285Sikob#include <net/if_vlan_var.h> 66103285Sikob 67103285Sikob#include <dev/firewire/firewire.h> 68103285Sikob#include <dev/firewire/firewirereg.h> 69103285Sikob#include <dev/firewire/if_fwevar.h> 70111942Ssimokawa#endif 71103285Sikob 72103285Sikob#define FWEDEBUG if (fwedebug) if_printf 73103285Sikob#define TX_MAX_QUEUE (FWMAXQUEUE - 1) 74103285Sikob 75103285Sikob/* network interface */ 76116139Ssimokawastatic void fwe_start (struct ifnet *); 77103285Sikobstatic int fwe_ioctl (struct ifnet *, u_long, caddr_t); 78108281Ssimokawastatic void fwe_init (void *); 79103285Sikob 80103285Sikobstatic void fwe_output_callback (struct fw_xfer *); 81103285Sikobstatic void fwe_as_output (struct fwe_softc *, struct ifnet *); 82103285Sikobstatic void fwe_as_input (struct fw_xferq *); 83103285Sikob 84103285Sikobstatic int fwedebug = 0; 85116139Ssimokawastatic int stream_ch = 1; 86116139Ssimokawastatic int tx_speed = 2; 87103285Sikobstatic int rx_queue_len = FWMAXQUEUE; 88103285Sikob 89103285SikobMALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface"); 90103285SikobSYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, ""); 91103285SikobSYSCTL_DECL(_hw_firewire); 92103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0, 93103285Sikob "Ethernet emulation subsystem"); 94103285SikobSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0, 95103285Sikob "Stream channel to use"); 96103285SikobSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RW, &tx_speed, 0, 97103285Sikob "Transmission speed"); 98103285SikobSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len, 99103285Sikob 0, "Length of the receive queue"); 100103285Sikob 101103285SikobTUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch); 102103285SikobTUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed); 103103285SikobTUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len); 104103285Sikob 105103285Sikob#ifdef DEVICE_POLLING 106103285Sikobstatic poll_handler_t fwe_poll; 107103285Sikob 108103285Sikobstatic void 109103285Sikobfwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 110103285Sikob{ 111103285Sikob struct fwe_softc *fwe; 112103285Sikob struct firewire_comm *fc; 113103285Sikob 114103285Sikob if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 115103285Sikob return; 116103285Sikob 117103285Sikob fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 118103285Sikob fc = fwe->fd.fc; 119103285Sikob fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); 120103285Sikob} 121103285Sikob#endif /* DEVICE_POLLING */ 122103285Sikob 123103285Sikobstatic void 124103285Sikobfwe_identify(driver_t *driver, device_t parent) 125103285Sikob{ 126103285Sikob BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent)); 127103285Sikob} 128103285Sikob 129103285Sikobstatic int 130103285Sikobfwe_probe(device_t dev) 131103285Sikob{ 132103285Sikob device_t pa; 133103285Sikob 134103285Sikob pa = device_get_parent(dev); 135103285Sikob if(device_get_unit(dev) != device_get_unit(pa)){ 136103285Sikob return(ENXIO); 137103285Sikob } 138103285Sikob 139108281Ssimokawa device_set_desc(dev, "Ethernet over FireWire"); 140103285Sikob return (0); 141103285Sikob} 142103285Sikob 143103285Sikobstatic int 144103285Sikobfwe_attach(device_t dev) 145103285Sikob{ 146103285Sikob struct fwe_softc *fwe; 147103285Sikob struct ifnet *ifp; 148103285Sikob int unit, s; 149103285Sikob#if defined(__DragonFly__) || __FreeBSD_version < 500000 150109814Ssimokawa u_char *eaddr; 151103285Sikob#else 152103285Sikob u_char eaddr[6]; 153103285Sikob#endif 154103285Sikob struct fw_eui64 *eui; 155103285Sikob 156103285Sikob fwe = ((struct fwe_softc *)device_get_softc(dev)); 157103285Sikob unit = device_get_unit(dev); 158103285Sikob 159103285Sikob bzero(fwe, sizeof(struct fwe_softc)); 160103285Sikob /* XXX */ 161103285Sikob fwe->stream_ch = stream_ch; 162103285Sikob fwe->dma_ch = -1; 163103285Sikob 164103285Sikob fwe->fd.fc = device_get_ivars(dev); 165103285Sikob if (tx_speed < 0) 166103285Sikob tx_speed = fwe->fd.fc->speed; 167103285Sikob 168103285Sikob fwe->fd.dev = dev; 169103285Sikob fwe->fd.post_explore = NULL; 170103285Sikob fwe->eth_softc.fwe = fwe; 171103285Sikob 172103285Sikob fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM; 173109814Ssimokawa fwe->pkt_hdr.mode.stream.sy = 0; 174109814Ssimokawa fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 175109814Ssimokawa 176109814Ssimokawa /* generate fake MAC address: first and last 3bytes from eui64 */ 177109814Ssimokawa#define LOCAL (0x02) 178109814Ssimokawa#define GROUP (0x01) 179109814Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 180109814Ssimokawa eaddr = &IFP2ENADDR(fwe->eth_softc.ifp)[0]; 181107653Ssimokawa#endif 182107653Ssimokawa 183103285Sikob 184103285Sikob eui = &fwe->fd.fc->eui; 185103285Sikob eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP; 186103285Sikob eaddr[1] = FW_EUI64_BYTE(eui, 1); 187103285Sikob eaddr[2] = FW_EUI64_BYTE(eui, 2); 188103285Sikob eaddr[3] = FW_EUI64_BYTE(eui, 5); 189103285Sikob eaddr[4] = FW_EUI64_BYTE(eui, 6); 190103285Sikob eaddr[5] = FW_EUI64_BYTE(eui, 7); 191103285Sikob printf("if_fwe%d: Fake Ethernet address: " 192103285Sikob "%02x:%02x:%02x:%02x:%02x:%02x\n", unit, 193103285Sikob eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 194103285Sikob 195103285Sikob /* fill the rest and attach interface */ 196103285Sikob ifp = fwe->eth_softc.ifp = if_alloc(IFT_ETHER); 197111942Ssimokawa if (ifp == NULL) { 198103285Sikob device_printf(dev, "can not if_alloc()\n"); 199103285Sikob return (ENOSPC); 200108712Ssimokawa } 201106937Ssam ifp->if_softc = &fwe->eth_softc; 202108712Ssimokawa 203108712Ssimokawa#if __FreeBSD_version >= 501113 || defined(__DragonFly__) 204108712Ssimokawa if_initname(ifp, device_get_name(dev), unit); 205103285Sikob#else 206103285Sikob ifp->if_unit = unit; 207103285Sikob ifp->if_name = "fwe"; 208103285Sikob#endif 209108712Ssimokawa ifp->if_init = fwe_init; 210106937Ssam#if defined(__DragonFly__) || __FreeBSD_version < 500000 211108712Ssimokawa ifp->if_output = ether_output; 212103285Sikob#endif 213103285Sikob ifp->if_start = fwe_start; 214103285Sikob ifp->if_ioctl = fwe_ioctl; 215103285Sikob ifp->if_mtu = ETHERMTU; 216103285Sikob ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST| 217103285Sikob IFF_NEEDSGIANT); 218103285Sikob ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; 219103285Sikob 220103285Sikob s = splimp(); 221103285Sikob#if defined(__DragonFly__) || __FreeBSD_version < 500000 222103285Sikob ether_ifattach(ifp, 1); 223103285Sikob#else 224111942Ssimokawa ether_ifattach(ifp, eaddr); 225111942Ssimokawa#endif 226103285Sikob splx(s); 227103285Sikob 228103285Sikob /* Tell the upper layer(s) we support long frames. */ 229103285Sikob ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 230103285Sikob#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 231103285Sikob ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_POLLING; 232103285Sikob ifp->if_capenable |= IFCAP_VLAN_MTU; 233103285Sikob#endif 234103285Sikob 235103285Sikob 236103285Sikob FWEDEBUG(ifp, "interface created\n"); 237113584Ssimokawa return 0; 238113584Ssimokawa} 239111942Ssimokawa 240111942Ssimokawastatic void 241111942Ssimokawafwe_stop(struct fwe_softc *fwe) 242111942Ssimokawa{ 243111942Ssimokawa struct firewire_comm *fc; 244111942Ssimokawa struct fw_xferq *xferq; 245111942Ssimokawa struct ifnet *ifp = fwe->eth_softc.ifp; 246111942Ssimokawa struct fw_xfer *xfer, *next; 247111942Ssimokawa int i; 248111942Ssimokawa 249111942Ssimokawa fc = fwe->fd.fc; 250111942Ssimokawa 251111942Ssimokawa if (fwe->dma_ch >= 0) { 252111942Ssimokawa xferq = fc->ir[fwe->dma_ch]; 253103285Sikob 254103285Sikob if (xferq->flag & FWXFERQ_RUNNING) 255103285Sikob fc->irx_disable(fc, fwe->dma_ch); 256103285Sikob xferq->flag &= 257103285Sikob ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 258103285Sikob FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 259103285Sikob xferq->hand = NULL; 260103285Sikob 261103285Sikob for (i = 0; i < xferq->bnchunk; i ++) 262103285Sikob m_freem(xferq->bulkxfer[i].mbuf); 263103285Sikob free(xferq->bulkxfer, M_FWE); 264103285Sikob 265103285Sikob for (xfer = STAILQ_FIRST(&fwe->xferlist); xfer != NULL; 266103285Sikob xfer = next) { 267103285Sikob next = STAILQ_NEXT(xfer, link); 268103285Sikob fw_xfer_free(xfer); 269108712Ssimokawa } 270106937Ssam STAILQ_INIT(&fwe->xferlist); 271108712Ssimokawa 272108712Ssimokawa xferq->bulkxfer = NULL; 273108712Ssimokawa fwe->dma_ch = -1; 274103285Sikob } 275103285Sikob 276103285Sikob#if defined(__FreeBSD__) 277103285Sikob ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 278103285Sikob#else 279103285Sikob ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 280103285Sikob#endif 281103285Sikob} 282103285Sikob 283103285Sikobstatic int 284103285Sikobfwe_detach(device_t dev) 285103285Sikob{ 286111942Ssimokawa struct fwe_softc *fwe; 287113584Ssimokawa struct ifnet *ifp; 288103285Sikob int s; 289103285Sikob 290103285Sikob fwe = device_get_softc(dev); 291103285Sikob ifp = fwe->eth_softc.ifp; 292103285Sikob 293103285Sikob#ifdef DEVICE_POLLING 294103285Sikob if (ifp->if_capenable & IFCAP_POLLING) 295103285Sikob ether_poll_deregister(ifp); 296103285Sikob#endif 297103285Sikob s = splimp(); 298103285Sikob 299103285Sikob fwe_stop(fwe); 300103285Sikob#if defined(__DragonFly__) || __FreeBSD_version < 500000 301118312Ssimokawa ether_ifdetach(ifp, 1); 302103285Sikob#else 303118312Ssimokawa ether_ifdetach(ifp); 304118312Ssimokawa if_free(ifp); 305118312Ssimokawa#endif 306103285Sikob 307103285Sikob splx(s); 308103285Sikob return 0; 309103285Sikob} 310113584Ssimokawa 311113584Ssimokawastatic void 312112400Ssimokawafwe_init(void *arg) 313103285Sikob{ 314103285Sikob struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe; 315103285Sikob struct firewire_comm *fc; 316103285Sikob struct ifnet *ifp = fwe->eth_softc.ifp; 317111942Ssimokawa struct fw_xferq *xferq; 318111942Ssimokawa struct fw_xfer *xfer; 319111942Ssimokawa struct mbuf *m; 320111942Ssimokawa int i; 321113584Ssimokawa 322111942Ssimokawa FWEDEBUG(ifp, "initializing\n"); 323113584Ssimokawa 324113584Ssimokawa /* XXX keep promiscoud mode */ 325111942Ssimokawa ifp->if_flags |= IFF_PROMISC; 326111942Ssimokawa 327111942Ssimokawa fc = fwe->fd.fc; 328111942Ssimokawa#define START 0 329111942Ssimokawa if (fwe->dma_ch < 0) { 330111942Ssimokawa for (i = START; i < fc->nisodma; i ++) { 331111942Ssimokawa xferq = fc->ir[i]; 332111942Ssimokawa if ((xferq->flag & FWXFERQ_OPEN) == 0) 333111942Ssimokawa goto found; 334113584Ssimokawa } 335111942Ssimokawa printf("no free dma channel\n"); 336111942Ssimokawa return; 337111942Ssimokawafound: 338111942Ssimokawa fwe->dma_ch = i; 339111942Ssimokawa fwe->stream_ch = stream_ch; 340113584Ssimokawa fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 341113584Ssimokawa /* allocate DMA channel and init packet mode */ 342113584Ssimokawa xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | 343113584Ssimokawa FWXFERQ_HANDLER | FWXFERQ_STREAM; 344113584Ssimokawa xferq->flag &= ~0xff; 345113584Ssimokawa xferq->flag |= fwe->stream_ch & 0xff; 346113584Ssimokawa /* register fwe_input handler */ 347111942Ssimokawa xferq->sc = (caddr_t) fwe; 348111942Ssimokawa xferq->hand = fwe_as_input; 349111942Ssimokawa xferq->bnchunk = rx_queue_len; 350111942Ssimokawa xferq->bnpacket = 1; 351111942Ssimokawa xferq->psize = MCLBYTES; 352111942Ssimokawa xferq->queued = 0; 353120660Ssimokawa xferq->buf = NULL; 354111942Ssimokawa xferq->bulkxfer = (struct fw_bulkxfer *) malloc( 355111942Ssimokawa sizeof(struct fw_bulkxfer) * xferq->bnchunk, 356111942Ssimokawa M_FWE, M_WAITOK); 357111942Ssimokawa if (xferq->bulkxfer == NULL) { 358111942Ssimokawa printf("if_fwe: malloc failed\n"); 359111942Ssimokawa return; 360103285Sikob } 361103285Sikob STAILQ_INIT(&xferq->stvalid); 362103285Sikob STAILQ_INIT(&xferq->stfree); 363103285Sikob STAILQ_INIT(&xferq->stdma); 364103285Sikob xferq->stproc = NULL; 365103285Sikob for (i = 0; i < xferq->bnchunk; i ++) { 366103285Sikob m = 367103285Sikob#if defined(__DragonFly__) || __FreeBSD_version < 500000 368103285Sikob m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 369103285Sikob#else 370103285Sikob m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); 371103285Sikob#endif 372103285Sikob xferq->bulkxfer[i].mbuf = m; 373103285Sikob if (m != NULL) { 374103285Sikob m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 375103285Sikob STAILQ_INSERT_TAIL(&xferq->stfree, 376103285Sikob &xferq->bulkxfer[i], link); 377103285Sikob } else 378103285Sikob printf("fwe_as_input: m_getcl failed\n"); 379103285Sikob } 380103285Sikob STAILQ_INIT(&fwe->xferlist); 381103285Sikob for (i = 0; i < TX_MAX_QUEUE; i++) { 382103285Sikob xfer = fw_xfer_alloc(M_FWE); 383103285Sikob if (xfer == NULL) 384103285Sikob break; 385103285Sikob xfer->send.spd = tx_speed; 386103285Sikob xfer->fc = fwe->fd.fc; 387103285Sikob xfer->retry_req = fw_asybusy; 388103285Sikob xfer->sc = (caddr_t)fwe; 389103285Sikob xfer->act.hand = fwe_output_callback; 390103285Sikob STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); 391103285Sikob } 392103285Sikob } else 393103285Sikob xferq = fc->ir[fwe->dma_ch]; 394103285Sikob 395103285Sikob 396103285Sikob /* start dma */ 397103285Sikob if ((xferq->flag & FWXFERQ_RUNNING) == 0) 398103285Sikob fc->irx_enable(fc, fwe->dma_ch); 399103285Sikob 400103285Sikob#if defined(__FreeBSD__) 401103285Sikob ifp->if_drv_flags |= IFF_DRV_RUNNING; 402108712Ssimokawa ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 403103285Sikob#else 404103285Sikob ifp->if_flags |= IFF_RUNNING; 405103285Sikob ifp->if_flags &= ~IFF_OACTIVE; 406103285Sikob#endif 407103285Sikob 408103285Sikob#if 0 409103285Sikob /* attempt to start output */ 410103285Sikob fwe_start(ifp); 411103285Sikob#endif 412103285Sikob} 413103285Sikob 414108712Ssimokawa 415108712Ssimokawastatic int 416103285Sikobfwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 417108712Ssimokawa{ 418108712Ssimokawa struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 419108712Ssimokawa struct ifstat *ifs = NULL; 420108712Ssimokawa int s, error, len; 421108712Ssimokawa 422106937Ssam switch (cmd) { 423106937Ssam case SIOCSIFFLAGS: 424106937Ssam s = splimp(); 425106937Ssam if (ifp->if_flags & IFF_UP) { 426108712Ssimokawa#if defined(__FreeBSD__) 427108712Ssimokawa if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 428108712Ssimokawa#else 429108712Ssimokawa if (!(ifp->if_flags & IFF_RUNNING)) 430103285Sikob#endif 431103285Sikob fwe_init(&fwe->eth_softc); 432103285Sikob } else { 433103285Sikob#if defined(__FreeBSD__) 434103285Sikob if (ifp->if_drv_flags & IFF_DRV_RUNNING) 435103285Sikob#else 436111942Ssimokawa if (ifp->if_flags & IFF_RUNNING) 437111942Ssimokawa#endif 438111942Ssimokawa fwe_stop(fwe); 439111942Ssimokawa } 440111942Ssimokawa /* XXX keep promiscoud mode */ 441111942Ssimokawa ifp->if_flags |= IFF_PROMISC; 442111942Ssimokawa splx(s); 443111942Ssimokawa break; 444111942Ssimokawa case SIOCADDMULTI: 445111942Ssimokawa case SIOCDELMULTI: 446111942Ssimokawa break; 447111942Ssimokawa 448111942Ssimokawa case SIOCGIFSTATUS: 449111942Ssimokawa s = splimp(); 450111942Ssimokawa ifs = (struct ifstat *)data; 451113584Ssimokawa len = strlen(ifs->ascii); 452111942Ssimokawa if (len < sizeof(ifs->ascii)) 453111942Ssimokawa snprintf(ifs->ascii + len, 454111942Ssimokawa sizeof(ifs->ascii) - len, 455113584Ssimokawa "\tch %d dma %d\n", 456113584Ssimokawa fwe->stream_ch, fwe->dma_ch); 457111942Ssimokawa splx(s); 458111942Ssimokawa break; 459111942Ssimokawa case SIOCSIFCAP: 460111942Ssimokawa#ifdef DEVICE_POLLING 461111942Ssimokawa { 462103285Sikob struct ifreq *ifr = (struct ifreq *) data; 463103285Sikob struct firewire_comm *fc = fc = fwe->fd.fc; 464103285Sikob 465103285Sikob if (ifr->ifr_reqcap & IFCAP_POLLING && 466103285Sikob !(ifp->if_capenable & IFCAP_POLLING)) { 467103285Sikob error = ether_poll_register(fwe_poll, ifp); 468103285Sikob if (error) 469103285Sikob return(error); 470103285Sikob /* Disable interrupts */ 471103285Sikob fc->set_intr(fc, 0); 472103285Sikob ifp->if_capenable |= IFCAP_POLLING; 473103285Sikob return (error); 474103285Sikob } 475103285Sikob if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 476103285Sikob ifp->if_capenable & IFCAP_POLLING) { 477103285Sikob error = ether_poll_deregister(ifp); 478103285Sikob /* Enable interrupts. */ 479103285Sikob fc->set_intr(fc, 1); 480103285Sikob ifp->if_capenable &= ~IFCAP_POLLING; 481103285Sikob return (error); 482103285Sikob } 483103285Sikob } 484103285Sikob#endif /* DEVICE_POLLING */ 485103285Sikob break; 486103285Sikob#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 487103285Sikob default: 488103285Sikob#else 489103285Sikob case SIOCSIFADDR: 490103285Sikob case SIOCGIFADDR: 491103285Sikob case SIOCSIFMTU: 492103285Sikob#endif 493103285Sikob s = splimp(); 494103285Sikob error = ether_ioctl(ifp, cmd, data); 495103285Sikob splx(s); 496111942Ssimokawa return (error); 497111942Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 498111942Ssimokawa default: 499103285Sikob return (EINVAL); 500103285Sikob#endif 501103285Sikob } 502103285Sikob 503103285Sikob return (0); 504103285Sikob} 505103285Sikob 506103285Sikobstatic void 507103285Sikobfwe_output_callback(struct fw_xfer *xfer) 508103285Sikob{ 509103285Sikob struct fwe_softc *fwe; 510103285Sikob struct ifnet *ifp; 511103285Sikob int s; 512111942Ssimokawa 513111942Ssimokawa fwe = (struct fwe_softc *)xfer->sc; 514111942Ssimokawa ifp = fwe->eth_softc.ifp; 515111942Ssimokawa /* XXX error check */ 516111942Ssimokawa FWEDEBUG(ifp, "resp = %d\n", xfer->resp); 517111942Ssimokawa if (xfer->resp != 0) 518103285Sikob ifp->if_oerrors ++; 519103285Sikob 520103285Sikob m_freem(xfer->mbuf); 521111942Ssimokawa fw_xfer_unload(xfer); 522108712Ssimokawa 523106937Ssam s = splimp(); 524108712Ssimokawa STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); 525108712Ssimokawa splx(s); 526108712Ssimokawa 527108712Ssimokawa /* for queue full */ 528103285Sikob if (ifp->if_snd.ifq_head != NULL) 529103285Sikob fwe_start(ifp); 530111942Ssimokawa} 531120660Ssimokawa 532120660Ssimokawastatic void 533113584Ssimokawafwe_start(struct ifnet *ifp) 534103285Sikob{ 535120660Ssimokawa struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 536103285Sikob int s; 537111942Ssimokawa 538103285Sikob GIANT_REQUIRED; 539103285Sikob 540103285Sikob FWEDEBUG(ifp, "starting\n"); 541103285Sikob 542103285Sikob if (fwe->dma_ch < 0) { 543103285Sikob struct mbuf *m = NULL; 544111942Ssimokawa 545103285Sikob FWEDEBUG(ifp, "not ready\n"); 546103285Sikob 547103285Sikob s = splimp(); 548103285Sikob do { 549103285Sikob IF_DEQUEUE(&ifp->if_snd, m); 550103285Sikob if (m != NULL) 551111942Ssimokawa m_freem(m); 552111942Ssimokawa ifp->if_oerrors ++; 553103285Sikob } while (m != NULL); 554103285Sikob splx(s); 555103285Sikob 556103285Sikob return; 557103285Sikob } 558103285Sikob 559113584Ssimokawa s = splimp(); 560103285Sikob#if defined(__FreeBSD__) 561103285Sikob ifp->if_drv_flags |= IFF_DRV_OACTIVE; 562111942Ssimokawa#else 563111942Ssimokawa ifp->if_flags |= IFF_OACTIVE; 564103285Sikob#endif 565111942Ssimokawa 566111942Ssimokawa if (ifp->if_snd.ifq_len != 0) 567111942Ssimokawa fwe_as_output(fwe, ifp); 568103285Sikob 569103285Sikob#if defined(__FreeBSD__) 570103285Sikob ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 571103285Sikob#else 572103285Sikob ifp->if_flags &= ~IFF_OACTIVE; 573103285Sikob#endif 574111942Ssimokawa splx(s); 575111942Ssimokawa} 576113584Ssimokawa 577111942Ssimokawa#define HDR_LEN 4 578111942Ssimokawa#ifndef ETHER_ALIGN 579111942Ssimokawa#define ETHER_ALIGN 2 580111942Ssimokawa#endif 581119119Ssimokawa/* Async. stream output */ 582113584Ssimokawastatic void 583113584Ssimokawafwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp) 584113584Ssimokawa{ 585113584Ssimokawa struct mbuf *m; 586113584Ssimokawa struct fw_xfer *xfer; 587113584Ssimokawa struct fw_xferq *xferq; 588111942Ssimokawa struct fw_pkt *fp; 589119119Ssimokawa int i = 0; 590119119Ssimokawa 591119119Ssimokawa xfer = NULL; 592119119Ssimokawa xferq = fwe->fd.fc->atq; 593119119Ssimokawa while (xferq->queued < xferq->maxq - 1) { 594119119Ssimokawa xfer = STAILQ_FIRST(&fwe->xferlist); 595119119Ssimokawa if (xfer == NULL) { 596111942Ssimokawa printf("if_fwe: lack of xfer\n"); 597111942Ssimokawa return; 598111942Ssimokawa } 599111942Ssimokawa IF_DEQUEUE(&ifp->if_snd, m); 600111942Ssimokawa if (m == NULL) 601108712Ssimokawa break; 602111942Ssimokawa STAILQ_REMOVE_HEAD(&fwe->xferlist, link); 603113584Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000 604103285Sikob if (ifp->if_bpf != NULL) 605103285Sikob bpf_mtap(ifp, m); 606103285Sikob#else 607103285Sikob BPF_MTAP(ifp, m); 608103285Sikob#endif 609103285Sikob 610103285Sikob /* keep ip packet alignment for alpha */ 611103285Sikob M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT); 612103285Sikob fp = &xfer->send.hdr; 613103285Sikob *(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr; 614103285Sikob fp->mode.stream.len = m->m_pkthdr.len; 615103285Sikob xfer->mbuf = m; 616103285Sikob xfer->send.pay_len = m->m_pkthdr.len; 617103285Sikob 618103285Sikob if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) { 619103285Sikob /* error */ 620108712Ssimokawa ifp->if_oerrors ++; 621106937Ssam /* XXX set error code */ 622108712Ssimokawa fwe_output_callback(xfer); 623108712Ssimokawa } else { 624108712Ssimokawa ifp->if_opackets ++; 625103285Sikob i++; 626103285Sikob } 627111942Ssimokawa } 628111942Ssimokawa#if 0 629103285Sikob if (i > 1) 630103285Sikob printf("%d queued\n", i); 631103285Sikob#endif 632103285Sikob if (i > 0) 633103285Sikob xferq->start(fwe->fd.fc); 634103285Sikob} 635103285Sikob 636103285Sikob/* Async. stream output */ 637103285Sikobstatic void 638103285Sikobfwe_as_input(struct fw_xferq *xferq) 639103285Sikob{ 640103285Sikob struct mbuf *m, *m0; 641103285Sikob struct ifnet *ifp; 642103285Sikob struct fwe_softc *fwe; 643103285Sikob struct fw_bulkxfer *sxfer; 644103285Sikob struct fw_pkt *fp; 645103285Sikob u_char *c; 646103285Sikob#if defined(__DragonFly__) || __FreeBSD_version < 500000 647103285Sikob struct ether_header *eh; 648103285Sikob#endif 649103285Sikob 650113506Smdodd fwe = (struct fwe_softc *)xferq->sc; 651113506Smdodd ifp = fwe->eth_softc.ifp; 652113506Smdodd 653 while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 654 STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 655 fp = mtod(sxfer->mbuf, struct fw_pkt *); 656 if (fwe->fd.fc->irx_post != NULL) 657 fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld); 658 m = sxfer->mbuf; 659 660 /* insert new rbuf */ 661 sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 662 if (m0 != NULL) { 663 m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size; 664 STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); 665 } else 666 printf("fwe_as_input: m_getcl failed\n"); 667 668 if (sxfer->resp != 0 || fp->mode.stream.len < 669 ETHER_ALIGN + sizeof(struct ether_header)) { 670 m_freem(m); 671 ifp->if_ierrors ++; 672 continue; 673 } 674 675 m->m_data += HDR_LEN + ETHER_ALIGN; 676 c = mtod(m, char *); 677#if defined(__DragonFly__) || __FreeBSD_version < 500000 678 eh = (struct ether_header *)c; 679 m->m_data += sizeof(struct ether_header); 680 m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN 681 - sizeof(struct ether_header); 682#else 683 m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN; 684#endif 685 m->m_pkthdr.rcvif = ifp; 686#if 0 687 FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n" 688 "%02x %02x %02x %02x %02x %02x\n" 689 "%02x %02x %02x %02x\n" 690 "%02x %02x %02x %02x\n" 691 "%02x %02x %02x %02x\n" 692 "%02x %02x %02x %02x\n", 693 c[0], c[1], c[2], c[3], c[4], c[5], 694 c[6], c[7], c[8], c[9], c[10], c[11], 695 c[12], c[13], c[14], c[15], 696 c[16], c[17], c[18], c[19], 697 c[20], c[21], c[22], c[23], 698 c[20], c[21], c[22], c[23] 699 ); 700#endif 701#if defined(__DragonFly__) || __FreeBSD_version < 500000 702 ether_input(ifp, eh, m); 703#else 704 (*ifp->if_input)(ifp, m); 705#endif 706 ifp->if_ipackets ++; 707 } 708 if (STAILQ_FIRST(&xferq->stfree) != NULL) 709 fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch); 710} 711 712 713static devclass_t fwe_devclass; 714 715static device_method_t fwe_methods[] = { 716 /* device interface */ 717 DEVMETHOD(device_identify, fwe_identify), 718 DEVMETHOD(device_probe, fwe_probe), 719 DEVMETHOD(device_attach, fwe_attach), 720 DEVMETHOD(device_detach, fwe_detach), 721 { 0, 0 } 722}; 723 724static driver_t fwe_driver = { 725 "fwe", 726 fwe_methods, 727 sizeof(struct fwe_softc), 728}; 729 730 731#ifdef __DragonFly__ 732DECLARE_DUMMY_MODULE(fwe); 733#endif 734DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0); 735MODULE_VERSION(fwe, 1); 736MODULE_DEPEND(fwe, firewire, 1, 1, 1); 737