Binary files sys44.orig/boot/i386/loader/loader.4th.8.gz and sys/boot/i386/loader/loader.4th.8.gz differ Binary files sys44.orig/boot/i386/loader/loader.8.gz and sys/boot/i386/loader/loader.8.gz differ Binary files sys44.orig/boot/i386/loader/loader.conf.5.gz and sys/boot/i386/loader/loader.conf.5.gz differ Binary files sys44.orig/boot/i386/pxeldr/pxeboot.8.gz and sys/boot/i386/pxeldr/pxeboot.8.gz differ diff -r -c -N sys44.orig/conf/files sys/conf/files *** sys44.orig/conf/files Thu Sep 20 00:08:13 2001 --- sys/conf/files Tue Oct 9 21:55:14 2001 *************** *** 1281,1283 **** --- 1281,1291 ---- libkern/strtoq.c standard libkern/strtoul.c standard libkern/strtouq.c standard + + net/if_fwsubr.c optional n1394 + dev/firewire/fw_dev.c optional n1394 + dev/firewire/netfw.c optional n1394 + dev/firewire/netfw_proto.c optional n1394 + dev/firewire/fwohci.c optional fwohci + dev/firewire/lynx.c optional lynx + dev/firewire/ilink.c optional ilink diff -r -c -N sys44.orig/conf/majors sys/conf/majors *** sys44.orig/conf/majors Thu Sep 20 00:08:13 2001 --- sys/conf/majors Tue Oct 9 21:55:14 2001 *************** *** 157,162 **** --- 157,163 ---- 138 usio USB Serial support 139 wanrouter Sangoma Technologies Inc. (al.feldman@sangoma.com) 140 pcfclock PCFCLOCK + 201 fwiso Firewire(IEEE1394) device (ikob@koganei.wide.ad.jp) 141 pcdmx PCDMX theatre lighting controller 142 skip SKIP port (security/skip) control device 143 urio USB Rio 500 diff -r -c -N sys44.orig/conf/options sys/conf/options *** sys44.orig/conf/options Thu Sep 20 00:08:13 2001 --- sys/conf/options Tue Oct 9 21:55:14 2001 *************** *** 434,439 **** --- 434,442 ---- # Include tweaks for running under the SimOS machine simulator. SIMOS opt_simos.h + # Firewire opt_firewire.h + N1394 opt_firewire.h + # options for bus/device framework BUS_DEBUG opt_bus.h DEVICE_SYSCTLS opt_bus.h diff -r -c -N sys44.orig/dev/firewire/README1394 sys/dev/firewire/README1394 *** sys44.orig/dev/firewire/README1394 Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/README1394 Tue Oct 9 21:55:14 2001 *************** *** 0 **** --- 1,151 ---- + The file contains this directory name as firewire-freebsd-2.2.yymmdd + is a device driver for firewire precisely IEEE1394 standard of serial + bus. This driver supports firewire NIC configured with some kind of + PCI-1394 link chipset as following: + + - TI PCILynx chip + - Apple pele basis chip (not working in proper) + - OHCI basis link chip device (may not working in proper) + + We are developing on following PCI card: + + - Radius Inc. MotoDV / PhotoDV TI PCI Lynx (TSB21LV21) + - Adaptec Inc. AHA-894x series Apple Pele (AIC-5400) + - Some vendor I don't know OHCI 1394 (TSB12LV22) + - Ratoc Sys. Inc. REX-PCIFW NEC OHCI (uPD 72861) + + The package of the driver code is provided as the diff. of FreeBSD 3.x + kernel source. You can create firewire adapted kernel as follows: + + # cd /usr/src + # patch -p < /firewire-freebsd-3.x.yymmdd + # cd i386/conf + + Edit configuration appropriately, for example, to add following + lines + + options "N1394" + + device lynx0 + device fwohci0 + + device fwiso0 + device fwiso1 + + # config + # cd ../../compile/ + # make depend; make; make install + + After rebooting, you have to make device node. If you want to communicate + with DV-VCR, you shall make a node as: + + # mknod c 201 2 /dev/dv0 + ^^ + The reason for such strange minor number for DV is as follows: + + 1. DV data stream requires kernel level special operation to the packet. + The detail of special operation could be found in the driver code. Curious + people should refer IEC61883 specification. + + 2. The above operation breaks general firewire data, so we keep minor number + zero to general firewire application. + + If you would like to know more information for the device driver, + you have to consult the paper bellow as: + + Katsushi Kobayashi, + "Design and Implementation of Firewire Device Driver on FreeBSD", + Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + pp 41-51,(1999) + + Enjoy! + ikob + + 0.1 11/04/1998 First release, it includes too many problems. + + 0.2 11/14/1998 Accord 3.0 environment. + + 0.3 3/12/1999 Possibly enable to compile on 3.1 environment with + resolve prototype check + "Masahiro Fujisawa" ) + + Resolve software interrupt confliction. + Don't work with ATM (BSD Harp) + Youki Kadobayashi + + 0.4 4/1/1999 Add sample config file as "sys/i386/conf/LYNX". + "Hitoaki Sakamoto " + + 0.5 5/3/1999 Correct the inclusion "opt_inet.h" + Re-consider work share between start_txdv() + and dv_write() + + 0.6 5/8/1999 Asynchronous stream support in IP broadcast on LYNX. + Improve stream channel mask on LYNX. + Re-consider IEC61883 timestamp to improve DV playout + quality. + + 0.7 5/13/1999 Partially support AIC5800 + Does not recieve Self-ID packet on AIC5800 + + 0.8 5/19/1999 Correct not to recieve Self-ID packet on AIC5800 + Stall isochronous packet receive after once socket + closed + Youki Kadobayashi + + 0.9 6/26/1999 Isochronous packet transmission terminate, + when device is closed.(lynx only) + Correct unstable behaviour when isochronous sending. + + 0.10 8/27/1999 Change the major device ID No. to official No. assigned + from the FreeBSD mainteinner as 127. + Add driver code for OpenHCI chipset. + + 0.11 1/10/2000 Correct some problem on OpenHCI based chipset as: + - isochronous stream treatment + - correcct the problem on asynchronous request + Update the copyright note and add reference information + + 1.00 1/15/2000 Add ad-hock bind() function to N1394 socket. + Change sockaddr structure for N13394 socket. + + 1.01 1/15/2000 Reconsider isochronous sent interrupt to improve + DV picture quality. + + 1.02 1/19/2000 Fix cannot recieve isochronous packet problem + Merge "fwiso" device code + + 1.03 1/25/2000 Temporary remove BMR election code due to exhausted mbuf + Correct the problem cannot recieve SID on lynx driver + + 1.04 1/28/2000 Improve BMR election code + Correct wrong packet length on OHCI driver + + 1.05 1/31/2000 Correct packet size, when fragmented IP transmission. + Correct larger number of DMA descripter in OHCI. + + 1.06 2/2/2000 Add device control to specify isochronous channel. + Accord data format of isochronous recieving buffer. + Correct signal problem, when kernel raising signal. + + 1.07 3/16/2000 Change platform to FreeBSD 4.x + (Probabily) Capable to IRQ share and other 4.x functions + + 1.08 3/28/2000 Correct PCI_LATENCY timer value on ilink. + + 1.09 4/8/2000 Resolve conflict in if_type.h + + 1.10 5/15/2000 A bit change fwiso device treatment + + 1.11 6/29/2000 Remove sys/net1394 and all firewire related files + are moved to directory under dev/firewire/ + Change lynx.h to firewire.h + -- + + Open issues: + + Freeze asynchronous reception, when recieving a lot of packet a moment. + + Freeze when recieving and transmitting 4 DV data stream. + ( tx-1394/rx-1394/tx-ether/rx-ether) + diff -r -c -N sys44.orig/dev/firewire/firewire.h sys/dev/firewire/firewire.h *** sys44.orig/dev/firewire/firewire.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/firewire.h Tue Oct 9 21:55:15 2001 *************** *** 0 **** --- 1,117 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: firewire.h,v 1.1.2.1 2000/06/04 17:19:05 ikob Exp $ + * + */ + + #ifndef _FIREWIRE_H + #define _FIREWIRE_H 1 + + #define DEV_DV 2 + + struct dv_data{ + u_int32_t n_write; + u_int32_t a_write; + u_int32_t k_write; + u_int32_t write_done; + u_int32_t write_len[16]; + u_int32_t write_off[16]; + u_int32_t n_read; + u_int32_t a_read; + u_int32_t k_read; + u_int32_t read_done; + u_int32_t read_len[16]; + u_int32_t read_off[16]; + }; + + struct dv_data_req_t { + unsigned long index; + unsigned long len; + unsigned long off; + }; + + /* + * ioctls + */ + + #define FW_DV_SYNC _IOWR('S', 1, unsigned int) + + #define FW_DV_TXCH _IOWR('S', 27, int32_t) + #define FW_DV_RXCH _IOWR('S', 28, int32_t) + #define FW_DV_TIME _IOWR('S', 29, int32_t) + #define FW_DV_RXSTART _IOW('S', 30, unsigned int) + #define FW_DV_RXSTOP _IOW('S', 31, unsigned int) + #define FW_GFRAMESIZE _IOR('S', 32, u_int32_t) + #define FW_DV_TXSTART _IOW('S', 33, unsigned int) + #define FW_DV_TXSTOP _IOW('S', 34, unsigned int) + #define FW_SSIGNAL_WR _IOW('S', 35, unsigned int) + #define FW_GSIGNAL_WR _IOR('S', 36, unsigned int) + #define FW_SSIGNAL_RD _IOW('S', 37, unsigned int) + #define FW_GSIGNAL_RD _IOR('S', 38, unsigned int) + + #define FW_DV_RDTXMAXB _IOR('S', 40, u_int32_t) + #define FW_DV_RDTXINGB _IOR('S', 41, u_int32_t) + #define FW_DV_RDTXLOKB _IOR('S', 42, u_int32_t) + #define FW_DV_WRTXLOKB _IOWR('S', 43, u_int32_t) + #define FW_DV_RDTXBUF _IOR('S', 45, struct dv_data_req_t) + #define FW_DV_WRTXBUF _IOWR('S', 46, struct dv_data_req_t) + + #define FW_DV_RDRXMAXB _IOR('S', 50, u_int32_t) + #define FW_DV_RDRXINGB _IOR('S', 51, u_int32_t) + #define FW_DV_RDRXLOKB _IOR('S', 52, u_int32_t) + #define FW_DV_WRRXLOKB _IOWR('S', 53, u_int32_t) + #define FW_DV_RDRXBUF _IOR('S', 55, struct dv_data_req_t) + #define FW_DV_WRRXBUF _IOWR('S', 56, struct dv_data_req_t) + + #ifdef _KERNEL + + #define UNIT2MIN(x) (((x) & 0xf) << 4) + #define UNIT(x) (((x) & 0xf0) >> 4) + #define MINOR(x) ((x) & 0xf) + + #define FW_OPEN 0x01 + + #define FW_DVINIT 0x01 + #define FW_DVOPEN 0x02 + #define FW_DVWRITE 0x04 + #define FW_DVWRWAIT 0x08 + #endif + + #endif diff -r -c -N sys44.orig/dev/firewire/fw_dev.c sys/dev/firewire/fw_dev.c *** sys44.orig/dev/firewire/fw_dev.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/fw_dev.c Tue Oct 9 21:55:15 2001 *************** *** 0 **** --- 1,680 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: fw_dev.c,v 1.1.2.1 2000/06/04 17:19:05 ikob Exp $ + * + */ + + #include "opt_inet.h" + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + + #ifdef INET + #include + #include + #include + #endif + #include + #include + #include + + #include + + #ifdef __FreeBSD__ + #include /* for rdtsc proto for clock.h below */ + #include + #include + #include + #include /* for vtophys proto */ + #include + + + /* #include */ + + #if (__FreeBSD_version >=400000) || (NSMBUS > 0) + #include /* used by smbus and newbus */ + #endif + + #if (__FreeBSD_version >=400000) + #include /* used by newbus */ + #include /* used by newbus */ + #include /* used by newbus */ + #endif + + #include + #include + #include + + #include + #include + + #define IFNAME(sc) (sc)->ac.ac_if.if_name + #define IFARG(sc) (sc)->ac.ac_if.if_unit + + #endif /* __FreeBSD__ */ + + #define CDEV_MAJOR 201 + + static d_open_t idv_open; + static d_close_t idv_close; + static d_ioctl_t idv_ioctl; + static d_read_t idv_read; + static d_write_t idv_write; + static d_mmap_t idv_mmap; + + static struct fw_softc *fwiso_get_softc __P((u_int)); + static dev_t fwiso_get_devs __P((u_int)); + + static int fwiso_devsw_num = 0; + + #define FWCHUNK 8 + + static struct fwisoarray { + int len; + device_t *devs; + } *fa = NULL; + + struct cdevsw fwiso_cdevsw = + { + fwiso_open, fwiso_close, fwiso_read, fwiso_write, + fwiso_ioctl, nopoll, fwiso_mmap, nostrategy, + "fwiso", CDEV_MAJOR, nodump, nopsize, + 0, -1 + }; + + static struct fw_softc *fwiso_get_softc( u_int unit) + { + if(unit > fwiso_devsw_num) { + return NULL; + } + return(device_get_softc(fa->devs[unit])); + } + + static dev_t fwiso_get_devs( u_int unit) + { + if(unit > fwiso_devsw_num) { + return NULL; + } + return ((dev_t) device_get_unit(fa->devs[unit])); + } + + int + fwiso_open (dev_t dev, int flags, int fmt, struct proc *p) + { + dev_t fwdev; + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_open == fwiso_open){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_open ( dev, flags, fmt, p)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_open(fwdev, flags, fmt, p)); + } + } + + static int + idv_open (dev_t dev, int flags, int fmt, struct proc *p) + { + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if (!(fc->dv_flags & FW_DVINIT)) + return ENXIO; + if (fc->dv_flags & FW_DVOPEN) + return EBUSY; + fc->dv_flags |= FW_DVOPEN; + return 0; + } + + int + fwiso_close (dev_t dev, int flags, int fmt, struct proc *p) + { + struct fw_softc *fc; + dev_t fwdev; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_close == fwiso_close){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_close ( dev, flags, fmt, p)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_close(fwdev, flags, fmt, p)); + } + } + + static int + idv_close (dev_t dev, int flags, int fmt, struct proc *p) + { + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->dv_flags & FW_DVWRWAIT){ + wakeup((caddr_t)fc); + } + + fc->write_signal = 0; + fc->dv_write_proc = 0; + fc->read_signal = 0; + fc->dv_read_proc = 0; + + fc->dv_flags &= ~FW_DVWRITE; + fc->dv_flags &= ~FW_DVOPEN; + return 0; + } + + int + fwiso_read (dev_t dev, struct uio *uio, int ioflag) + { + dev_t fwdev; + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_read == fwiso_read){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_read ( dev, uio, ioflag)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_read(fwdev, uio, ioflag)); + } + } + + static int + idv_read (dev_t dev, struct uio *uio, int ioflag) + { + /* + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + */ + return EINVAL;/* not implemented yet */ + } + + int + fwiso_write (dev_t dev, struct uio *uio, int ioflag) + { + dev_t fwdev; + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_write == fwiso_write){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_write ( dev, uio, ioflag)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_write(fwdev, uio, ioflag)); + } + } + + static int + idv_write (dev_t dev, struct uio *uio, int ioflag) + { + struct fw_softc *fc; + + u_int iseq, i; + u_int len; + int error; + + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + + if( fc->dv_flags & FW_DVWRITE ) + return(EIO); + + fc->dv_flags |= FW_DVWRITE; + if( uio->uio_resid > S100_SZ*DVBUF) + return EIO; + if((INITREG(fc, oPCR) & 1<<30) && (fc->dv.queued >= DEF_FRAME)){ + fc->dv_flags |= FW_DVWRWAIT; + error = tsleep((caddr_t)fc, FW_WRPRI, + "send", (hz ) * 2); + fc->dv_flags &= ~FW_DVWRWAIT; + if(error) { + if(INITREG(fc, oPCR) & DV_BROADCAST_ON){ + printf("sleep time out occured, now trying to restart DMA\n"); + fc->dv_start = 0; + fc->dv_end = 0; + fc->txdv(fc); + error = 0; + }else{ + return error; + } + } + } + + iseq = (fc->dv_buf->a_write + 1) % fc->dv_buf->n_write; + if( iseq == fc->dv_buf->k_write){ + iseq = (fc->dv_buf->a_write + 1) % fc->dv_buf->n_write; + } + len = uio->uio_resid / S100_SZ; + fc->dv_buf->write_len[iseq] = len; + fc->dv.queued++;if(fc->dv.queued > DEF_FRAME ) fc->dv.queued = DEF_FRAME; + fc->dv.walock = iseq; + error = uiomove((caddr_t)fc->dv_write_buf[iseq], uio->uio_resid, uio); + + fc->dv.walock = -1; + fc->dv_buf->a_write = iseq; + fc->dv_flags &= ~FW_DVWRITE; + if (error) + return error; + return 0; + } + + int + fwiso_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) + { + dev_t fwdev; + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_ioctl == fwiso_ioctl){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_ioctl ( dev, cmd, data, flag, p)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_ioctl(fwdev, cmd, data, flag, p)); + } + } + + int + idv_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) + { + struct fw_softc *fc; + int err = 0; + u_int32_t tmp; + struct dv_data_req_t *dvdata; + u_int iseq, rx_ch; + + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if (!data) + return(EINVAL); + + switch (cmd) { + case FW_DV_TXCH: /* Set iso. channel No. for DV stream transmission */ + if(INITREG(fc, oPCR) & DV_BROADCAST_ON){ + err = EBUSY; + break; + } + INITREG(fc, oMPR) &= ~(0x3f << 24); + INITREG(fc, oMPR) |= ((*(int32_t*)data & 0x3f ) << 24); + break; + case FW_DV_RXCH: /* Set iso. channel No. for DV stream reception */ + if(INITREG(fc, iPCR) & DV_BROADCAST_ON){ + err = EBUSY; + break; + } + INITREG(fc, iPCR) &= ~(0x3f << 16); + INITREG(fc, iPCR) |= ((*(int32_t*)data & 0x3f ) << 16); + break; + case FW_DV_TIME: /* Set time-stamp gap in first packet of video frame */ + fc->dv_gap = *(int32_t*)data; + break; + case FW_GFRAMESIZE: /* Get amount memory size of DV stream */ + *(u_int32_t*)data = fc->dv_buf_size; + break; + /* Set process to raise signal, when finish to send video frame */ + case FW_SSIGNAL_WR: + if(*data == 0 || *data >= NSIG){ + return(EINVAL); + } + fc->write_signal = *data; + fc->dv_write_proc = p; + break; + /* Get process to raise signal, when finish to send video frame */ + case FW_GSIGNAL_WR: + *(int *)data = fc->write_signal; + break; + /* Set process to raise signal, when fill out a recieve buffer */ + case FW_SSIGNAL_RD: + if(*data == 0 || *data >= NSIG){ + return(EINVAL); + } + fc->read_signal = *data; + fc->dv_read_proc = p; + break; + /* Get process to raise signal, when fill out a recieve buffer */ + case FW_GSIGNAL_RD: + *(int *)data = fc->read_signal; + break; + /* Set gap of frames between DMA transmission and host to write */ + case FW_DV_SYNC: + if((0 <= *data ) && (*data < fc->dv_buf->n_write )){ + fc->dv.sync = *data; + }else{ + err = EINVAL; + } + break; + case FW_DV_RXSTART: /* Start to recieve DV stream */ + rx_ch = (INITREG(fc, iPCR) >> 16 ) & 0x3f; + if(INITREG(fc, iPCR) & DV_BROADCAST_ON){ + err = EINVAL; + break; + } + if( fc->isoslot[(1 << 6) | rx_ch].type + != ISOSLOT_NULL){ + err = EBUSY; + break; + } + fc->isoslot[ (1 << 6 ) | rx_ch].type = ISOSLOT_DV; + for( iseq = 0 ; iseq < 16 ; iseq++){ + (u_int32_t)*((caddr_t)fc->dv_buf + fc->dv_buf->write_off[iseq]) |= htonl(0xf0); + } + INITREG(fc, iPCR) |= DV_BROADCAST_ON; + INITREG(fc, iPCR) &= ~(0x3f<<16); + INITREG(fc, iPCR) + |= (((INITREG(fc, oMPR) >> 24) & rx_ch) << 16); + fc->dv_buf->k_read = 0; + fc->dv.rklock = 0; + if( fc->rxdv == NULL) + break; + fc->rxdv(fc); + break; + case FW_DV_RXSTOP: /* Stop to recieve DV stream */ + rx_ch = (INITREG(fc, oPCR) >> 16) & 0x3f; + if( fc->isoslot[(1 << 6) | rx_ch].type + != ISOSLOT_DV){ + err = EINVAL; + break; + } + fc->isoslot[(1 << 6) | rx_ch].type = ISOSLOT_NULL; + INITREG(fc, iPCR) &= ~(DV_BROADCAST_ON); + if( fc->rxstop == NULL) + break; + fc->rxstop(fc); + break; + case FW_DV_RDTXMAXB: /* Set number buffers to transmit DV stream */ + *(u_int32_t *)data = fc->dv_buf->n_write; + break; + case FW_DV_RDTXINGB: /* Current buffer transmitting DV stream */ + *(u_int32_t *)data = fc->dv_buf->k_write; + break; + case FW_DV_RDTXLOKB: /* Current DV transmission frame host to write */ + *(u_int32_t *)data = fc->dv_buf->a_write; + break; + case FW_DV_WRTXLOKB: /* Set DV frame host to write */ + tmp = *(u_int32_t *)data; + if( tmp >= fc->dv_buf->n_write){ + err = EINVAL; + break; + } + if(fc->dv_buf->k_write == tmp){ + tmp ++; + } + fc->dv_buf->a_write = tmp;; + *(u_int32_t *)data = tmp; + break; + case FW_DV_RDTXBUF: /* Get DV frame information */ + dvdata = (struct dv_data_req_t *)data; + if(dvdata->index >= fc->dv_buf->n_write){ + err = EINVAL; + break; + } + dvdata->len + = fc->dv_buf->write_len[dvdata->index]; + dvdata->off + = fc->dv_buf->write_off[dvdata->index]; + break; + case FW_DV_WRTXBUF: /* Set DV frame information */ + dvdata = (struct dv_data_req_t *)data; + if(dvdata->index >= fc->dv_buf->n_write){ + err = EINVAL; + break; + } + if(dvdata->len > DVBUF){ + err = EINVAL; + break; + } + fc->dv_buf->write_len[dvdata->index] + = dvdata->len; + dvdata->off + = fc->dv_buf->write_off[dvdata->index]; + break; + + case FW_DV_RDRXMAXB: /* Set number buffers to recieve DV stream */ + *(u_int32_t *)data = fc->dv_buf->n_write; + break; + + case FW_DV_RDRXINGB: /* Current buffer recieving DV stream */ + *(u_int32_t *)data = fc->dv_buf->k_write; + break; + case FW_DV_RDRXBUF: /* Get DV frame information */ + dvdata = (struct dv_data_req_t *)data; + if(dvdata->index >= fc->dv_buf->n_write){ + err = EINVAL; + break; + } + dvdata->len + = fc->dv_buf->write_len[dvdata->index]; + dvdata->off + = fc->dv_buf->write_off[dvdata->index]; + break; + + case FW_DV_TXSTOP: /* Stop to transmit DV stream */ + /* XXX: BW and CH available Register should be checked. */ + INITREG(fc, oPCR) &= ~((0x3f<<16)|(0x0f<<10)); + INITREG(fc, oPCR) &= ~DV_BROADCAST_ON; + if( fc->txstop == NULL) + break; + fc->txstop(fc); + break; + + case FW_DV_TXSTART: /* Start to transmit DV stream */ + if(INITREG(fc, oPCR) & DV_BROADCAST_ON){ + err = EBUSY; + break; + } + INITREG(fc, oPCR) &= ~((0x3f<<16)|(0x0f<<10)); + INITREG(fc, oPCR) + |= (((INITREG(fc, oMPR) >> 24) & 0x3f) << 16) + | (0x0f < 10); + INITREG(fc, oPCR) |= DV_BROADCAST_ON; + fc->dv.wklock = 0; + fc->dv_buf->k_write = 0; + if( fc->dv.sync ){ + fc->dv_buf->k_write = ((u_int) + (fc->dv_buf->k_write + fc->dv.sync)) % fc->dv_buf->n_write; + } + fc->dv_start = 0; + fc->dv_end = 0; + if( fc->txdv == NULL) + break; + fc->txdv(fc); + break; + default: + return(ENOTTY); + } + return err; + } + + int + fwiso_mmap (dev_t dev, vm_offset_t offset, int nproto) + { + dev_t fwdev; + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + if(fc->cdev->d_mmap == fwiso_mmap){ + switch(MINOR(minor(dev))){ + case DEV_DV: + return(idv_mmap ( dev, offset, nproto)); + break; + default: + return(ENXIO); + break; + } + }else{ + if((fwdev = fwiso_get_devs(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + fwdev = (dev_t)((u_int32_t)fwdev | MINOR(minor(dev))); + return( fc->cdev->d_mmap(fwdev, offset, nproto)); + } + } + + static int + idv_mmap (dev_t dev, vm_offset_t offset, int nproto) + { + struct fw_softc *fc; + if((fc = fwiso_get_softc(UNIT(minor(dev)))) == NULL){ + return(ENXIO); + } + + if( nproto & PROT_EXEC ) return (-1); + if(!( fc->dv_flags & FW_DVINIT )) return (-1); + if( offset > fc->dv_buf_size ) return (-1); + return i386_btop(vtophys(fc->dv_buf) + offset); + } + + int fwiso_attach(device_t dev, struct cdevsw *cdev) + { + struct fw_softc *fc = device_get_softc(dev); + int unit = device_get_unit(dev); + if(fa == NULL ){ + fa = malloc(sizeof(struct fwisoarray), M_DEVBUF, M_NOWAIT); + if(fa == NULL) return; + fa->devs = (device_t *) + malloc(sizeof(device_t) * FWCHUNK, M_DEVBUF, M_NOWAIT); + if(fa->devs == NULL) return; + fa->len = FWCHUNK; + bzero(fa->devs, sizeof(device_t) * fa->len); + } + if(fwiso_devsw_num >= fa->len){ + device_t *fwdevs; + fwdevs = (device_t *) + malloc(sizeof(device_t) * (fa->len + FWCHUNK), M_DEVBUF, M_NOWAIT); + if(fwdevs == NULL) return; + bzero(fwdevs, sizeof(device_t) * (fa->len + FWCHUNK)); + bcopy(fa->devs, fwdevs, sizeof(device_t) * fa->len); + free(fa->devs, M_DEVBUF); + fa->len += FWCHUNK; + fa->devs = fwdevs; + } + fa->devs[fwiso_devsw_num] = dev; + + fc->cdev = cdev; + fc->write_signal = 0; + fc->dv_write_proc = 0; + fc->read_signal = 0; + fc->dv_read_proc = 0; + printf("Attach the probed firewire I/F to fwiso%1d\n", + fwiso_devsw_num); + /* + make_dev(&fwiso_cdevsw, UNIT2MIN(fwiso_devsw_num), + 0, 0, 0777, "fwiso%d", fwiso_devsw_num); + */ + + make_dev(&fwiso_cdevsw, UNIT2MIN(fwiso_devsw_num) + 2, + 0, 0, 0777, "dv%d", fwiso_devsw_num); + fwiso_devsw_num++; + } diff -r -c -N sys44.orig/dev/firewire/fw_dev.h sys/dev/firewire/fw_dev.h *** sys44.orig/dev/firewire/fw_dev.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/fw_dev.h Tue Oct 9 21:55:16 2001 *************** *** 0 **** --- 1,63 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: fw_dev.h,v 1.1.2.1 2000/06/04 17:19:05 ikob Exp $ + * + */ + + #define DVSIZE 60 * 8 + #define CH_DV 0x3f + #define DV_ISOTAGCIP 1 + + #define DVBUF 300 + #define DV_FRAME 12 + + extern struct cdevsw fwiso_cdevsw; + + #define FW_WRPRI (PZERO+8)|PCATCH + + int fwiso_attach __P((device_t, struct cdevsw *)); + + d_open_t fwiso_open; + d_close_t fwiso_close; + d_ioctl_t fwiso_ioctl; + d_read_t fwiso_read; + d_write_t fwiso_write; + d_mmap_t fwiso_mmap; + diff -r -c -N sys44.orig/dev/firewire/fwohci.c sys/dev/firewire/fwohci.c *** sys44.orig/dev/firewire/fwohci.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/fwohci.c Tue Oct 9 21:55:17 2001 *************** *** 0 **** --- 1,2259 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: fwohci.c,v 1.1.2.1 2000/06/04 17:19:05 ikob Exp $ + * + */ + + #define DEBUG_PACKET + #undef DEBUG_PACKET + #define ATRQ_CH 0 + #define ATRS_CH 1 + #define ARRQ_CH 2 + #define ARRS_CH 3 + #define ITX_CH 4 + #define DVTX_CH 5 + #define IRX_CH 0x24 + #define DVRX_CH 0x25 + #define IPRX_CH 0x26 + #define MAXOHCI_CH 0x44 + #define MAXIPFRAG 40 + + + #define RX_DMA + #undef RX_DMA + + #ifdef __FreeBSD__ + #include "fwohci.h" + #include "pci.h" + #endif /* __FreeBSD__ */ + + #if !defined(__FreeBSD__) || (NFWOHCI > 0 && NPCI > 0) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + #include + + #ifdef INET + #endif + #include + #include + #include + #include + #include + #include + #include + + #include + + #include + + #ifdef __FreeBSD__ + #include /* for rdtsc proto for clock.h below */ + #include + #include + #include + #include /* for vtophys proto */ + #include + + #include + + #include + #include + #include + + #define OHCI_DEBUG + #undef OHCI_DEBUG + /* + #define OHCI_DEBUG + */ + static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL", + "STOR","LOAD","NOP ","STOP",}; + static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", + "UNDEF","REG","SYS","DEV"}; + extern char linkspeed[4][0x10]; + static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; + extern char ackcode[32][0x20]; + #define OHCI_WRITE_SIGMASK 0xffff0000 + #define OHCI_READ_SIGMASK 0xffff0000 + + #define FWOHCIARGS(sc) (sc)->fc.ac.ac_if.if_unit + + #endif /* __FreeBSD__ */ + + #define senderr(e) { error = (e); goto bad;} + + static void fwohci_set_bmr __P((struct fwohci_softc *)); + static void fwohci_start_txdv __P((struct fwohci_softc *)); + static void fwohci_start_rxdv __P((struct fwohci_softc *)); + static void fwohci_stop_rxdv __P((struct fwohci_softc *)); + static void fwohci_reset __P((struct fwohci_softc *)); + static void fwohci_ibr __P((struct fwohci_softc *)); + static int fwohci_ioctl __P((struct ifnet *, u_long, caddr_t)); + static void fwohci_init __P((struct fwohci_softc *)); + static void fwohci_busreset __P((struct fwohci_softc *)); + static void fwohci_db_init __P((struct fwohci_softc *)); + static void fwohci_db_ch_init __P((struct fwohci_softc *, int, int, int)); + static void fwohci_dv_init __P((struct fwohci_softc *)); + static void fwohci_rx_enable __P((struct fwohci_softc *, int, int)); + static void fwohci_rx_disable __P((struct fwohci_softc *, int)); + static void fwohci_tx_init __P((struct fwohci_softc *, int)); + static void fwohci_rcv __P((struct fwohci_softc *, int)); + static void fwohci_txd __P((struct fwohci_softc *, int)); + static void fwohci_start __P((struct ifnet *)); + static void fwohci_intr __P((void *arg)); + static int fwohci_stop_dma __P((struct fwohci_softc *, int)); + #ifdef RX_DMA + static int fwohci_add_rx_buf __P((struct fwohcidb_tr *, struct mbuf *)); + #else + static int fwohci_forward_rx_buf __P((struct fwohcidb_tr *, int)); + #endif + static void dump_db __P((struct fwohci_softc *, int)); + static void print_db __P((struct fwohcidb *, int )); + static void dump_dma __P((struct fwohci_softc *, int)); + static void dump_fifo_ptr __P((struct fwohci_softc *)); + + typedef u_char bool_t; + + + /* + * memory allocated for DMA programs + */ + #define DMA_PROG_ALLOC (8 * PAGE_SIZE) + + #define NDB 1024 + #define NDVDB DVBUF * 16 + + #ifdef __FreeBSD__ + + static int fwohci_probe __P((device_t)); + static int fwohci_attach __P((device_t)); + static int fwohci_shutdown __P((device_t)); + + #define UNIT(x) (((x) & 0xf0) >> 4) + #define MINOR(x) ((x) & 0xf) + + static device_method_t fwohci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fwohci_probe), + DEVMETHOD(device_attach, fwohci_attach), + DEVMETHOD(device_shutdown, fwohci_shutdown), + + { 0, 0 } + }; + + static driver_t fwohci_driver = { + "fwohci", + fwohci_methods, + sizeof(struct fwohci_softc), + }; + + static devclass_t fwohci_devclass; + + DRIVER_MODULE(if_fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0); + + #endif /* __FreeBSD__ */ + + + #ifdef __FreeBSD__ + /* + * the boot time probe routine. + */ + static int + fwohci_probe( device_t dev ) + { + dev_t vendor; + dev_t device; + + vendor = pci_get_vendor(dev); + device = pci_get_device(dev); + + switch((int)vendor) { + case FW_VENDORID_NEC: + switch((int)device) { + case FW_DEVICE_uPD72861: + device_set_desc(dev, "NEC uPD72861"); + return 0; + case FW_DEVICE_uPD72870: + device_set_desc(dev, "NEC uPD72870"); + return 0; + case FW_DEVICE_uPD72871: + device_set_desc(dev, "NEC uPD72871"); + return 0; + default: + break; + } + break; + + case FW_VENDORID_TI: + switch((int)device) { + case FW_DEVICE_TI_TSB12LV22: + device_set_desc(dev, "Texas Instruments TSB12LV22"); + return 0; + case FW_DEVICE_TI_TSB12LV23: + device_set_desc(dev, "Texas Instruments TSB12LV23"); + return 0; + case FW_DEVICE_TI_TSB12LV26: + device_set_desc(dev, "Texas Instruments TSB12LV26"); + return 0; + case FW_DEVICE_TI_TSB43AA22: + device_set_desc(dev, "Texas Instruments TSB43AA22"); + return 0; + default: + break; + } + break; + + case FW_VENDORID_SONY: + switch((int)device) { + case FW_DEVICE_SONY_CXD3222: + device_set_desc(dev, "SONY IEEE1394 CXD3222"); + return 0; + default: + break; + } + break; + + case FW_VENDORID_VIA: + switch((int)device) { + case FW_DEVICE_VIA: + device_set_desc(dev, "VIA"); + return 0; + default: + break; + } + break; + + case FW_VENDORID_LUCENT: + switch((int)device) { + case FW_DEVICE_LUCENT: + device_set_desc(dev, "LUCENT"); + return 0; + default: + break; + } + break; + + case FW_VENDORID_ADVANSYS: + switch((int)device) { + case FW_DEVICE_ASC03C0400A_TQ: + device_set_desc(dev, "ADVANSYS"); + return 0; + default: + break; + } + break; + + default: + break; + } + + return ENXIO; + } + #endif /* __FreeBSD__ */ + + static int fwohci_stop_dma(struct fwohci_softc *sc, int ch) + { + int i; + if(ch > MAXOHCI_CH) + return(-1); + /* stop all DMAs */ + if( ch < 0 ){ + for( i = 0 ; i < 4 ; i ++){ + sc->base->dma_ch[i].cntl_clr = OHCI_CNTL_DMA_RUN ; + } + for( i = 0 ; i < 0x20 ; i ++){ + sc->base->dma_itch[i].cntl_clr = OHCI_CNTL_DMA_RUN ; + } + for( i = 0 ; i < 0x20 ; i ++){ + sc->base->dma_irch[i].cntl_clr = OHCI_CNTL_DMA_RUN ; + } + return(ch); + }else if(ch < ITX_CH){ + sc->base->dma_ch[ch].cntl_clr = OHCI_CNTL_DMA_RUN ; + return(ch); + }else if( ch < IRX_CH ){ + sc->base->dma_itch[ch - ITX_CH].cntl_clr = OHCI_CNTL_DMA_RUN ; + return(ch); + }else if( ch < MAXOHCI_CH){ + sc->base->dma_irch[ch - IRX_CH].cntl_clr = OHCI_CNTL_DMA_RUN ; + return(ch); + }else{ + return(-1); + } + } + /* + * The attach routine. + */ + static int + fwohci_attach( device_t dev) + { + struct fwohci_softc *sc = device_get_softc(dev); + int unit = device_get_unit(dev); + int error = 0; + struct ifnet *ifp; + volatile u_int32_t cmd, fun, latency, cache_line; + u_int ch, i; + int rid; + #ifdef __FreeBSD__ + #if 0 + sc = &fwohci[unit]; + if (unit >= NFWOHCI) { + printf("fwohci%d: attach: only %d units configured.\n", + unit, NFWOHCI); + printf("fwohci%d: attach: invalid unit number.\n", unit); + return; + } + #endif + + ifp = (struct ifnet *)&sc->fc.ac; + callout_handle_init(&sc->fc.stat_ch); + + cmd = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 2); + cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWIEN; + pci_write_config(dev, PCI_COMMAND_STATUS_REG, cmd, 2); + + latency = pci_read_config(dev, PCIR_LATTIMER, 1); + #define DEF_LATENCY 200 /* Derived from Max Bulk Transfer size 512 Bytes*/ + if( latency < DEF_LATENCY ) { + latency = DEF_LATENCY; + printf("pcilynx%d: PCI bus latency was changing to", + unit); + pci_write_config(dev, PCIR_LATTIMER,latency, 1); + } else + { + printf("pcilynx%d: PCI bus latency is", unit); + } + printf(" %d.\n", (int) latency); + #define DEF_CACHE_LINE 0x10 + cache_line = DEF_CACHE_LINE; + pci_write_config(dev, PCIR_CACHELNSZ, cache_line, 1); + /**/ + fun = pci_read_config(dev, 0xf0, 4); + fun |= 7; + pci_write_config(dev, 0xf0, fun, 4); + /**/ + rid = PCI_MAP_REG_START; + sc->fc.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE); + if (!sc->fc.mem) { + device_printf(dev, "could not map memory\n"); + error = ENXIO; + goto fail; + } + sc->base = rman_get_virtual(sc->fc.mem); + #endif /* __FreeBSD__ */ + + ifp->if_flags &= ~IFF_UP; + + /* Stop all DMA operation db.immediately */ + fwohci_stop_dma(sc, -1); + + /* FLUSH FIFO and Reset Transmitter and Reciever */ + DELAY(100); + sc->base->hcc_cntl_set |= OHCI_HCC_RESET; + + DELAY(100); + + sc->fc.sid_buf = (u_int32_t *) vm_page_alloc_contig( 1 << 11, + 0x10000, 0xffffffff, 1 << 11); + + sc->base->sid_buf = vtophys(sc->fc.sid_buf); + sc->fc.sid_buf++; + #if 1 + sc->base->bus_opt |= (0x1f<< 27 ); + #endif + sc->base->link_cntl = OHCI_CNTL_SID; + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set = OHCI_HCC_LPS; + sc->base->hcc_cntl_clr = OHCI_HCC_BIGEND; + + sc->base->hcc_cntl_clr = OHCI_HCC_PRPHY; + sc->base->hcc_cntl_clr = OHCI_HCC_PHYEN; + sc->base->hcc_cntl_clr = OHCI_HCC_POSTWR; + #if 0 + sc->base->hcc_cntl_set = OHCI_HCC_PRPHY; + sc->base->hcc_cntl_set = OHCI_HCC_PHYEN; + sc->base->hcc_cntl_set = OHCI_HCC_POSTWR; + #endif + #if 1 + sc->base->hcc_cntl_set = OHCI_HCC_LINKEN; + i = 0; + while((!(sc->base->hcc_cntl_set & OHCI_HCC_RESET)) && i < 10000 ){ + i++; + DELAY(100); + } + #endif + + sc->base->link_cntl = OHCI_CNTL_SID; + /* + */ + + /* + * probe PHY parameters + * 0. to probe PHY, whether TSB21LV3, TSB21LV01 or others. + * 1. to probe maximum speed supported by the PHY and + * number of port supported by core-logic. + * It is not actually available port. + */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + if((fun >> 5) != 7 ){ + printf("fwohci%d: Link 1394 only %s, %d ports.\n", unit, + linkspeed[(fun & FW_PHY_SPD) >> 6], fun & FW_PHY_NP); + sc->fc.asyst = 0; + }else{ + volatile u_int32_t fun2; + fun2 = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_ESPD_REG); + printf("fwohci%d: Link 1394a available %s, %d ports.\n", unit, + linkspeed[(fun2 & FW_PHY_ESPD) >> 5], fun & FW_PHY_NP); + fun2 = tsb21lv_rddata(&sc->base->phy_access, 5); + fun2 &= ~0x83; + fun2 = tsb21lv_wrdata(&sc->base->phy_access, 5, fun2); + #if 0 + fun2 = tsb21lv_rddata(&sc->base->phy_access, 5); + fun2 |= 0xbc; + fun2 = tsb21lv_wrdata(&sc->base->phy_access, 5, fun2); + #endif + sc->fc.asyst = 1; + } + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + if((fun >> 5) == 7 ){ + fun = tsb21lv_rddata(&sc->base->phy_access, 4); + fun |= 1 << 6; + tsb21lv_wrdata(&sc->base->phy_access, 4, fun); + fun = tsb21lv_rddata(&sc->base->phy_access, 4); + } + + fun = pci_read_config(dev, PCI_ID_REG, 4); + + /* fwohci_busreset() never stop ARX */ + sc->base->dma_ch[ARRQ_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + sc->base->dma_ch[ARRS_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + + fwohci_busreset(sc); + + + /* Attach PCL to dma channel */ + sc->fc.dv_flags = 0; + for( i = 0 ; i < OHCI_MAX_DMA_CH ; i ++){ + sc->ndb[i]= 0; + } + fwohci_db_init(sc); + + ifp->if_softc = sc; + ifp->if_name = "ohci"; + ifp->if_unit = unit; + ifp->if_mtu = 1500; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; + ifp->if_ioctl = fwohci_ioctl; + ifp->if_output = fw_output; + ifp->if_type = IFT_IEEE1394; + ifp->if_start = fwohci_start; + ifp->if_init = (if_init_f_t *)fwohci_init; + ifp->if_addrlen = 0; + ifp->if_hdrlen = 0; + ifp->if_snd.ifq_maxlen = 2000; + sc->fc.dv_gap = 5 << 12; + sc->fc.dv_write_proc = 0; + sc->fc.dv_read_proc = 0; + sc->fc.fw_busreset = fwohci_busreset; + + bzero(&sc->fc.ac.media.firewire.eui64, 8); + sc->fc.p_cycle_timer = &sc->base->cycle_timer; + + sc->flags = 0; + /* establish interrupt */ + rid = 0; + sc->fc.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (sc->fc.irq == NULL) { + device_printf(dev, "could not map interrupt\n"); + error = ENXIO; + goto fail; + } + + error = bus_setup_intr(dev, sc->fc.irq, INTR_TYPE_NET, + fwohci_intr, sc, &sc->fc.ih); + if (error) { + device_printf(dev, "could not setup irq\n"); + goto fail; + } + + fwohci_init(sc); + + if_attach(ifp); + + if( sc->base->node & OHCI_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->link_cntl = OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER; + } else{ + printf("This host is NOT CYCLEMASTER\n"); + sc->base->link_cntl_clr = OHCI_CNTL_CYCMTR; + sc->base->link_cntl = OHCI_CNTL_CYCTIMER; + } + sc->fc.txdv = fwohci_start_txdv; + sc->fc.rxdv = fwohci_start_rxdv; + sc->fc.txstop = NULL; + sc->fc.rxstop = fwohci_stop_rxdv; + sc->fc.set_bmr = fwohci_set_bmr; + fwiso_attach(dev, &fwiso_cdevsw); + /* specific function also attaches */ + + bpfattach(ifp, DLT_NULL, sizeof(struct fwhdr)); + /* Initiate Busreset */ + #if 1 + fwohci_ibr(sc); + #endif + fail: + return error; + } + static void fwohci_start(ifp) + register struct ifnet *ifp; + { + struct mbuf *m, *mb_head; + struct ifqueue *ifq = &ifp->if_snd; + struct fwohci_softc *sc = (struct fwohci_softc *)ifp->if_softc; + struct fwohcidb_tr *otx, *tx, *last; + struct fwohcidb_tr *asyrqstart = NULL; + struct fwohcidb_tr *asyrsstart = NULL; + struct fwohcidb_tr *isostart = NULL; + u_int32_t tcode; + int i, s, segment, osegment, req, hdr_len; + int ch; + u_int32_t proto; + struct fwhdr *ld; + u_int32_t len, *ild; + /* + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + */ + if(sc->queued[ATRQ_CH] > 0 ){ + asyrqstart = sc->db_last[ATRQ_CH]->next; + } + if(sc->queued[ATRS_CH] > 0 ){ + asyrsstart = sc->db_last[ATRS_CH]->next; + } + if(sc->queued[ITX_CH] > 0 ){ + isostart = sc->db_last[ITX_CH]->next; + } + if( asyrqstart != NULL || asyrsstart != NULL || isostart != NULL ){ + goto kick; + } + txloop: + s = splimp(); + IF_DEQUEUE(ifq, mb_head); + if (mb_head == NULL){ + splx(s); + goto kick; /* EMPTY: >>> exit here <<< */ + return; + } + splx(s); + + #if defined(__FreeBSD__) + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer to it). + */ + struct mbuf m1; + u_int af = AF_UNSPEC; + + m1.m_next = mb_head; + m1.m_len = 4; + m1.m_data = (char *)⁡ + + bpf_mtap(ifp, &m1); + } + #endif + + ifp->if_opackets++; + ld = (struct fwhdr *)mtod(mb_head, vm_offset_t); + proto = ld->cntl[0]; + + tcode = (ntohl(ld->data[0]) & 0xf0) >> 4; + if( tcode == TCODE_STREAM ){ + hdr_len = 8; + }else if( tcode == TCODE_RDREQ ) { + hdr_len = 12; + }else{ + hdr_len = 16; + } + switch(tcode){ + case TCODE_WRREQ: + case TCODE_BLKWRREQ: + case TCODE_BLKRDREQ: + case TCODE_BLKRDRES: + case TCODE_LKREQ: + case TCODE_LKRES: + ld->data[3] = ntohl(ld->data[3]); + default: + case TCODE_WRRES: + case TCODE_RDREQ: + case TCODE_RDRES: + case TCODE_SID: + ld->data[2] = ntohl(ld->data[2]); + ld->data[1] = ntohl(ld->data[1]); + case TCODE_STREAM: + ld->data[0] = ntohl(ld->data[0]); + } + if(proto == PROTO_N1394ASYRQ || proto == PROTO_N1394ASYST){ + /* remove control entry */ + switch(tcode){ + case TCODE_WRRES: + case TCODE_RDRES: + case TCODE_BLKRDRES: + case TCODE_LKRES: + ch = ATRS_CH; + break; + default: + ch = ATRQ_CH; + break; + } + if( tcode != TCODE_STREAM ){ + u_int32_t dst; + m_adj(mb_head, sizeof(fwcntl)); + ild = mtod(mb_head, u_int32_t *); + dst = ild[0] & 0xffff0000; + ild[1] &= ~0xffff0000; + ild[1] |= dst; + ild[0] &= ~(0xffff0000 | RETRY_MASK); + ild[0] |= (OHCI_ASYSRCBUS | (RETRY_X) << 8); + }else{ + m_adj(mb_head, sizeof(fwcntl) - 4); + /* length of header part (hdr_len) is already aligned at initial setting */ + ild = mtod(mb_head, u_int32_t *); + len = ild[1] & 0xffff0000; + ild[0] = ild[1] & 0x0000ffff; + ild[0] |= OHCI_SPD_S100 << 16; + ild[1] = len; + } + }else if(proto == PROTO_N1394ISOST){ + ch = ITX_CH; + m_adj(mb_head, sizeof(fwcntl) - 4); + /* length of header part (hdr_len) is already aligned at initial setting */ + ild = mtod(mb_head, u_int32_t *); + len = ild[1] & 0xffff0000; + ild[0] = ild[1] & 0x0000ffff; + ild[0] |= OHCI_SPD_S100 << 16; + ild[1] = len; + }else{ + if(mb_head != NULL){ + m_freem(mb_head); + } + goto txloop; + } + + last = sc->db_last[ch]; + otx = sc->db_last[ch]; + tx = sc->db_last[ch]->next; + + switch(proto){ + case PROTO_N1394ISOST: + isostart = last->next; + break; + case PROTO_N1394ASYRQ: + if( ch == ATRS_CH ){ + asyrsstart = last->next; + }else{ + asyrqstart = last->next; + } + break; + case PROTO_N1394ASYST: + asyrqstart = last->next; + break; + } + segment = 0; + tx->db->unit[segment].db.desc.cmd + = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | hdr_len; + /* + * Record time stamp value to status field in end of descriptor. + * Compatible to ATRQ_CH. + */ + #if 0 + if(ch == ATRS_CH){ + tx->db->unit[segment].db.desc.status + = ((sc->base->cycle_timer >> 12) + ( 1 << 13 )) + & 0x0000ffff ; + } + #endif + segment ++; + for( i = 0 ; i < hdr_len ; i+= 4){ + tx->db->unit[segment].db.immed[i/4] = ild[i/4]; + } + m_adj(mb_head, hdr_len); + tbdinit: + segment = 2; + if(mb_head->m_pkthdr.len > 0){ + for (m = mb_head; m != NULL; m = m->m_next) { + if (m->m_len != 0) { + if (segment >= ILINKDBBUF ) + break; + tx->db->unit[segment].db.desc.addr + = vtophys(mtod(m, vm_offset_t)); + tx->db->unit[segment].db.desc.cmd + = OHCI_OUTPUT_MORE | ( m->m_len & 0xffff); + segment++; + } + } + /* Number of fragmentation exceed MAX DB buffer */ + if(m != NULL){ + struct mbuf *mn; + MGETHDR(mn, M_DONTWAIT, MT_DATA); + if (mn == NULL) { + m_freem(mb_head); + goto kick; + return; + } + if (mb_head->m_pkthdr.len > MHLEN) { + MCLGET(mn, M_DONTWAIT); + if ((mn->m_flags & M_EXT) == 0) { + m_freem(mn); + m_freem(mb_head); + goto kick; + return; + } + } + m_copydata(mb_head, 0, mb_head->m_pkthdr.len, + mtod(mn, caddr_t)); + mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; + m_freem(mb_head); + mb_head = mn; + goto tbdinit; + } + } + tx->mbhead = mb_head; + tx->db->unit[segment > 2 ? segment - 1:0].db.desc.cmd + |= OHCI_OUTPUT_LAST + | OHCI_INTERRUPT_ALWAYS + | OHCI_BRANCH_ALWAYS; + /* Warning, the entry the segment value stored uses undefined area ! */ + #if 0 + tx->db->unit[0].db.desc.addr = segment; + osegment = sc->db_last[ch]->db->unit[0].db.desc.addr; + #else + tx->db->unit[ILINKDBBUF].db.desc.addr = segment; + osegment = sc->db_last[ch]->db->unit[ILINKDBBUF].db.desc.addr; + #endif + #if 0 + sc->db_last[ch]->db->unit[0].db.desc.addr = 0; + #endif + tx->db->unit[segment > 2 ? segment -1:0].db.desc.depend + = vtophys(tx->next->db->unit); + otx->db->unit[osegment > 2 ? osegment -1:0].db.desc.depend |= segment; + s = splimp(); + sc->queued[ch] ++; + splx(s); + sc->db_last[ch] = tx; + + if(sc->queued[ch] > sc->ndb[ch] ){ + goto txloop; + } + kick: + if( asyrqstart != NULL){ + /* kick asy q */ + if(!(sc->base->dma_ch[ATRQ_CH].cntl & OHCI_CNTL_DMA_ACTIVE)){ + sc->base->dma_ch[ATRQ_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + #if 0 + segment = sc->db_last[ATRQ_CH]->db->unit[0].db.desc.addr; + #else + segment = sc->db_last[ATRQ_CH]->db->unit[ILINKDBBUF].db.desc.addr; + #endif + #if 0 + sc->db_last[ATRQ_CH]->db->unit[0].db.desc.addr = 0; + #endif + sc->db_last[ATRQ_CH]->db->unit[segment > 2 ? segment - 1:0].db.desc.depend + &= 0xfffffff0; + sc->base->dma_ch[ATRQ_CH].cmd = vtophys(asyrqstart->db) | segment; + #if 0 + dump_dma(sc, ATRQ_CH); + dump_db(sc, ATRQ_CH); + #endif + sc->base->dma_ch[ATRQ_CH].cntl = OHCI_CNTL_DMA_RUN ; + sc->base->int_mask |= OHCI_INT_EN |OHCI_INT_DMA_ATRQ; + } + } + if( asyrsstart != NULL){ + /* kick asy q */ + if(!(sc->base->dma_ch[ATRS_CH].cntl & OHCI_CNTL_DMA_ACTIVE)){ + sc->base->dma_ch[ATRS_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + #if 0 + segment = sc->db_last[ATRS_CH]->db->unit[0].db.desc.addr; + #else + segment = sc->db_last[ATRS_CH]->db->unit[ILINKDBBUF].db.desc.addr; + #endif + sc->db_last[ATRS_CH]->db->unit[segment > 2 ? segment - 1:0].db.desc.depend + &= 0xfffffff0; + sc->base->dma_ch[ATRS_CH].cmd = vtophys(asyrsstart->db) | segment; + #if 0 + dump_dma(sc, ATRS_CH); + dump_db(sc, ATRS_CH); + #endif + sc->base->dma_ch[ATRS_CH].cntl = OHCI_CNTL_DMA_RUN ; + sc->base->int_mask |= OHCI_INT_EN |OHCI_INT_DMA_ATRS; + } + } + if( isostart !=NULL){ + /* kick iso q */ + if(!(sc->base->dma_itch[ITX_CH - 4].cntl & OHCI_CNTL_DMA_ACTIVE)){ + sc->base->dma_itch[ITX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN; + #if 0 + segment = sc->db_last[ITX_CH]->db->unit[0].db.desc.addr; + #else + segment = sc->db_last[ITX_CH]->db->unit[ILINKDBBUF].db.desc.addr; + #endif + sc->db_last[ITX_CH]->db->unit[segment > 2 ? segment - 1:0].db.desc.depend + &= 0xfffffff0; + sc->base->dma_itch[ITX_CH - 4].cmd = vtophys(isostart->db) | segment; + sc->base->dma_itch[ITX_CH - 4].cntl = OHCI_CNTL_DMA_RUN ; + sc->base->int_mask |= OHCI_INT_EN | OHCI_INT_DMA_IT; + sc->base->it_int_mask |= (1 << (ITX_CH - 4)); + } + } + } + static void fwohci_dv_init(sc) + register struct fwohci_softc *sc; + { + int idb; + int iseq; + int idv; + struct fwohcidb *db; + vm_offset_t buf_base; + u_int32_t *addr; + u_int32_t *ld; + + sc->fc.dv_buf_size = sizeof(struct dv_data) + 2 * MAX_DVFRAME * S100_SZ * (DVBUF + 1) + ; + sc->fc.dv_buf = (struct dv_data *)vm_page_alloc_contig( sc->fc.dv_buf_size, + 0x100000, 0xffffffff, PAGE_SIZE); + if(sc->fc.dv_buf == NULL){ + printf("Phisical memory is exhoused\n"); + /* take back track to free allocated memory */ + sc->fc.dv_flags &= ~FW_DVINIT; + return; + } + buf_base = (vm_offset_t)sc->fc.dv_buf + sizeof(struct dv_data); + for( iseq = 0, idb = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + iseq * S100_SZ * (DVBUF+1)); + sc->dbdvtx[iseq].db_tr = &sc->db_tr[DVTX_CH][idb]; + sc->fc.dv_write_buf[iseq] = &addr[S100_SZ/4]; + /* first PCL is used as dummy */ + for( idv = 0 ; idv < DVBUF ; idv++){ + db = sc->db_tr[DVTX_CH][idb].db; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 0 ){ + sc->dbdvtx[iseq].db = db; + sc->fc.dv_write_buf[iseq] = ld; + sc->fc.dv_buf->write_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + db->unit[0].db.desc.cmd = + OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8; + /* + * Lowest 4 bits specifies the number of Next DMA descripter + */ + db->unit[0].db.desc.depend = + vtophys(sc->db_tr[DVTX_CH][idb].next->db) | 3; + + db->unit[2].db.desc.cmd = + OHCI_OUTPUT_LAST | + OHCI_BRANCH_ALWAYS |((S100_SZ - 12) & 0xfff); + db->unit[2].db.desc.addr = vtophys(ld) + 4; + db->unit[2].db.desc.depend = + vtophys(sc->db_tr[DVTX_CH][idb].next->db) | 3; + + /* + * 12 means, the gap of ISO data between ISO packet + * including ISO hdr, hdr CRC and data CRC + */ + ld[0] = htonl((DV_ISOTAGCIP << 14) | + ((S100_SZ-12) << 16) | + (TCODE_STREAM << 4) ); + ld[1] = htonl((DVSIZE / 4 ) << 16); + db->unit[1].db.immed[0] = (0x0000ffff & ntohl(ld[0])) + |(OHCI_SPD_S100 << 16); + db->unit[1].db.immed[1] = ntohl(ld[0]) & 0xffff0000; + idb++; + } + db->unit[2].db.desc.cmd |= OHCI_INTERRUPT_ALWAYS; + db->unit[2].db.desc.depend &= 0xfffffff0; + + sc->dbdvtx[iseq].tail = idv; + } + for( iseq = 0, idb = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + + ( iseq + MAX_DVFRAME ) * S100_SZ * (DVBUF+1)); + sc->dbdvrx[iseq].db_tr = &sc->db_tr[DVRX_CH][idb]; + sc->fc.dv_read_buf[iseq] = &addr[S100_SZ/4]; + for( idv = 0 ; idv < DVBUF ; idv++){ + db = sc->db_tr[DVRX_CH][idb].db; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 0 ){ + sc->dbdvrx[iseq].db = db; + sc->fc.dv_read_buf[iseq] = ld; + sc->fc.dv_buf->read_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + db->unit[0].db.desc.addr = vtophys(ld); + db->unit[0].db.desc.cmd + = OHCI_INPUT_LAST | OHCI_BRANCH_ALWAYS | OHCI_UPDATE | S100_SZ & 0xfff; + db->unit[0].db.desc.depend = + vtophys(sc->db_tr[DVRX_CH][idb].next->db) | 0x1; + idb++; + } + db->unit[0].db.desc.cmd |= OHCI_INTERRUPT_ALWAYS; + sc->fc.dv_buf->read_len[iseq] = idv; + } + + sc->fc.dv.wklock = 0; + sc->fc.dv.walock = -1; + + sc->fc.dv.rklock = 0; + sc->fc.dv.ralock = -1; + + sc->fc.dv.dbc = -1; + sc->fc.dv.sync = 6; + sc->fc.dv.queued = 0; + + sc->fc.dv_buf->n_write = DEF_FRAME; + sc->fc.dv_buf->k_write = ~0; + sc->fc.dv_buf->a_write = 0x0; + + sc->fc.dv_buf->n_read = DEF_FRAME; + sc->fc.dv_buf->k_read = ~0; + sc->fc.dv_buf->a_read = 0x0; + + sc->fc.dv_flags |= FW_DVINIT; + } + static void fwohci_db_ch_init(sc, ch, ndb, len) + register struct fwohci_softc *sc; + int ch; + int ndb, len; + { + int idb; + struct fwohcidb *db; + /* allocate DB entries and attach one to each DMA channels */ + /* PCL entry must start at 16 bytes bounary. */ + fwohci_stop_dma(sc, ch); + sc->ndb[ch] = ndb; + sc->db_tr[ch] = (struct fwohcidb_tr *) + malloc(sizeof(struct fwohcidb_tr) * ndb, + M_DEVBUF, M_NOWAIT); + + sc->db_tr[ch][0].db = (struct fwohcidb *) + vm_page_alloc_contig(sizeof(struct fwohcidb) * ndb, + 0x100000, 0xffffffff, PAGE_SIZE); + + /* Attach PCL to DMA ch. */ + db = sc->db_tr[ch][0].db; + sc->queued[ch] = 0; + for(idb = 0 ; idb < ndb ; idb++){ + sc->db_tr[ch][idb].db = &(db[idb]); + #ifndef RX_DMA + if( len > 0 ){ + sc->db_tr[ch][idb].buf = + (caddr_t)vm_page_alloc_contig( MCLBYTES, + 0x100000, 0xffffffff, PAGE_SIZE); + } + #endif + if( idb != (ndb - 1)){ + sc->db_tr[ch][idb].next + = &(sc->db_tr[ch][idb + 1]); + }else{ + sc->db_tr[ch][ndb - 1].next + = &(sc->db_tr[ch][0]); + } + } + sc->db_last[ch] = &(sc->db_tr[ch][ndb - 1]); + sc->db_first[ch] = &(sc->db_tr[ch][ndb - 1]); + } + static void fwohci_db_init(sc) + register struct fwohci_softc *sc; + { + int ch; + + fwohci_db_ch_init(sc, ARRQ_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, ARRS_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, IRX_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, IPRX_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, ATRQ_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, ATRS_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, ITX_CH, NDB, MCLBYTES); + fwohci_db_ch_init(sc, DVTX_CH, NDVDB, 0); + fwohci_db_ch_init(sc, DVRX_CH, NDVDB, 0); + fwohci_dv_init(sc); + } + #if 0 + static void fwohci_rx_disable(sc, ch) + register struct fwohci_softc *sc; + int ch; + { + struct ifnet *ifp = (struct ifnet *)&sc->ac; + int idb; + struct fwohcidb *db; + + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + #ifdef RX_DMA + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + /* Attach and Invalidate current PCL pointer */ + m_freem(sc->db_tr[ch][idb].mbhead); + sc->db_tr[ch][idb].mbhead = NULL; + } + #endif + } + #endif + static void fwohci_rx_enable(sc, ch, ich) + register struct fwohci_softc *sc; + int ch; int ich; + { + int idb, z, tag; + u_int32_t tagbit; + + /* to disable DMA */ + fwohci_stop_dma(sc, ch); + if( ch < ITX_CH ){ + z = 1; + }else{ + z = 1; + } + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + #ifdef RX_DMA + fwohci_add_rx_buf(&(sc->db_tr[ch][idb]), 0); + #else + fwohci_forward_rx_buf(&(sc->db_tr[ch][idb]), ch); + #endif + if( idb != (sc->ndb[ch] - 1) ){ + sc->db_tr[ch][idb].db->unit[0].db.desc.depend + = vtophys(sc->db_tr[ch][idb + 1].db) | z; + }else{ + sc->db_tr[ch][idb].db->unit[0].db.desc.depend + = vtophys(sc->db_tr[ch][0].db) | z; + } + } + sc->db_last[ch] = &(sc->db_tr[ch][sc->ndb[ch] - 1]); + sc->db_last[ch]->db->unit[0].db.desc.depend &= 0xfffffff0; + /* stop command requires at last ? */ + if( ch < ITX_CH ){ + sc->db_last[ch]->next->db->unit[0].db.desc.cmd + = OHCI_INPUT_MORE | OHCI_INTERRUPT_ALWAYS + | OHCI_BRANCH_ALWAYS | MCLBYTES ; + sc->base->dma_ch[ch].cmd + = (fwohcireg_t) vtophys(sc->db_tr[ch][0].db) | z; + sc->base->dma_ch[ch].cntl = OHCI_CNTL_DMA_RUN ; + }else{ + tag = (ich >> 6) & 3; + switch(tag){ + case 0: + tagbit = 1 << 28; + break; + case 1: + tagbit = 1 << 29; + break; + case 2: + tagbit = 1 << 30; + break; + case 3: + tagbit = 1 << 31; + break; + default: + tagbit = 3 << 28; + break; + } + sc->db_last[ch]->next->db->unit[0].db.desc.cmd + = OHCI_INPUT_LAST | OHCI_INTERRUPT_ALWAYS + | OHCI_UPDATE | OHCI_BRANCH_ALWAYS | MCLBYTES ; + sc->base->dma_irch[ch - IRX_CH].cmd + = (fwohcireg_t) vtophys(sc->db_tr[ch][0].db) | z; + sc->base->dma_irch[ch - IRX_CH].match + = tagbit | (ich & 0x3f) ; + sc->base->ir_int_mask |= (1 << (ch - IRX_CH)); + sc->base->dma_irch[ch - IRX_CH].cntl_clr + = sc->base->dma_irch[ch - IRX_CH].cntl & 0xf0000000 ; + sc->base->dma_irch[ch - IRX_CH].cntl + = OHCI_CNTL_ISOHDR | OHCI_CNTL_DMA_RUN ; + } + } + static void fwohci_tx_init(sc, ch) + register struct fwohci_softc *sc; + int ch; + { + int idb; + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + sc->db_tr[ch][idb].mbhead = NULL; + } + if( ch < ITX_CH ){ + sc->base->dma_ch[ch].cntl_clr + = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD; + }else{ + sc->base->dma_itch[ch].cntl_clr + = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_DEAD; + } + return; + } + /* Call once after reboot */ + static void fwohci_init(sc) + register struct fwohci_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + u_int i; + u_int32_t imask_tmp; + + if_fwinit(&sc->fc); + + ifp->if_flags &= ~IFF_RUNNING; + sc->base->int_mask_clear = ~0; + sc->base->int_clear = ~0; + + sc->base->node &= 0xffff003f; + + imask_tmp = sc->base->int_mask; + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set |= OHCI_HCC_LPS; + sc->base->hcc_cntl_set |= OHCI_HCC_LINKEN; + sc->base->int_mask = imask_tmp; + + fwohci_rx_enable(sc, ARRQ_CH, 0); + fwohci_rx_enable(sc, ARRS_CH, 0); + + sc->base->areq_hi = ~0; + sc->base->areq_lo = ~0; + + fwohci_tx_init(sc, ATRQ_CH); + fwohci_tx_init(sc, ATRS_CH); + sc->base->retry = (0xffff << 16 )| (0x0f << 8) | (0x0f << 4) | 0x0f ; + sc->base->int_mask |= + OHCI_INT_EN | OHCI_INT_ERR | OHCI_INT_PHY_SID + | OHCI_INT_DMA_ATRQ | OHCI_INT_DMA_ATRS + | OHCI_INT_DMA_PTRQ | OHCI_INT_DMA_PTRS + | OHCI_INT_DMA_ARRQ | OHCI_INT_DMA_ARRS + | OHCI_INT_PHY_BUS_R ; + sc->base->dma_ch[ARRQ_CH].cntl_clr = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_WAKE; + sc->base->dma_ch[ARRS_CH].cntl_clr = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_WAKE; + + ifp->if_flags |= IFF_RUNNING; + return; + } + static int fwohci_shutdown(device_t dev) + { + struct fwohci_softc *sc = device_get_softc(dev); + u_int ch, i; + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + + ifp->if_flags &= ~IFF_UP; + fwohci_stop_dma(sc, -1); + return 0; + } + static void + fwohci_intr( void *arg ) + { + struct fwohci_softc *sc = (struct fwohci_softc *)arg; + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + u_int32_t csr; + #if 0 + while(csr = sc->base->pci_int_stat) + #else + csr = sc->base->int_stat; + #endif + { + sc->base->int_clear = ~0; + + #ifdef OHCI_DEBUG + printf("fwohci%d INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x, 0x%08x\n", + FWOHCIARGS(sc), + csr & OHCI_INT_EN ? "DMA_EN ":"", + csr & OHCI_INT_PHY_REG ? "PHY_REG ":"", + csr & OHCI_INT_CYC_LONG ? "CYC_LONG ":"", + csr & OHCI_INT_ERR ? "INT_ERR ":"", + csr & OHCI_INT_CYC_ERR ? "CYC_ERR ":"", + csr & OHCI_INT_CYC_LOST ? "CYC_LOST ":"", + csr & OHCI_INT_CYC_64SECOND ? "CYC_64SECOND ":"", + csr & OHCI_INT_CYC_START ? "CYC_START ":"", + csr & OHCI_INT_PHY_INT ? "PHY_INT ":"", + csr & OHCI_INT_PHY_BUS_R ? "BUS_RESET ":"", + csr & OHCI_INT_PHY_SID ? "SID ":"", + csr & OHCI_INT_LR_ERR ? "DMA_LR_ERR ":"", + csr & OHCI_INT_PW_ERR ? "DMA_PW_ERR ":"", + csr & OHCI_INT_DMA_IR ? "DMA_IR ":"", + csr & OHCI_INT_DMA_IT ? "DMA_IT " :"", + csr & OHCI_INT_DMA_PTRS ? "DMA_PTRS " :"", + csr & OHCI_INT_DMA_PTRQ ? "DMA_PTRQ " :"", + csr & OHCI_INT_DMA_ARRS ? "DMA_ARRS " :"", + csr & OHCI_INT_DMA_ARRQ ? "DMA_ARRQ " :"", + csr & OHCI_INT_DMA_ATRS ? "DMA_ATRS " :"", + csr & OHCI_INT_DMA_ATRQ ? "DMA_ATRQ " :"", + csr, sc->base->int_mask + ); + #endif + if(csr & OHCI_INT_PHY_BUS_R ){ + printf("BUS reset\n"); + /* disable cycle master */ + sc->base->link_cntl_clr = (OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER); + fwohci_busreset(sc); + /* + if( sc->base->node & OHCI_NODE_ROOT ){ + sc->base->link_cntl = OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER ; + }else{ + sc->base->link_cntl_clr = OHCI_CNTL_CYCMTR; + sc->base->link_cntl = OHCI_CNTL_CYCTIMER ; + } + */ + if( ifp->if_flags & IFF_RUNNING ){ + sc->base->dma_ch[ARRQ_CH].cntl = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_WAKE; + sc->base->dma_ch[ARRS_CH].cntl = OHCI_CNTL_DMA_RUN | OHCI_CNTL_DMA_WAKE; + } + } + if(csr & OHCI_INT_PHY_SID ){ + if( sc->base->node & OHCI_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->link_cntl = OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER ; + }else{ + printf("This host is not CYCLEMASTER\n"); + sc->base->link_cntl_clr = OHCI_CNTL_CYCMTR; + sc->base->link_cntl = OHCI_CNTL_CYCTIMER ; + } + if( sc->base->sid_cnt & 1 << 31 ){ + DELAY(100); + fwohci_ibr(sc); + + }else{ + sc->fc.sid_cnt = (sc->base->sid_cnt & 0x1fff) >> 3; + INITREG(&sc->fc, TOPO_MAP + 8) = 0; + fw_sid_set(&(sc->fc.ac.ac_if)); + } + } + if(csr & OHCI_INT_ERR ){ + printf("Error occured\n"); + } + if((csr & OHCI_INT_DMA_IR )){ + u_int32_t isr; + isr = sc->base->ir_int_stat; + + sc->base->ir_int_clear = 0xffffffff; + if((1 << (IPRX_CH - IRX_CH)) & isr){ + fwohci_rcv(sc, IPRX_CH); + } + if((1 << (IRX_CH - IRX_CH)) & isr){ + fwohci_rcv(sc, IRX_CH); + } + if((1 << (DVRX_CH - IRX_CH)) & isr){ + u_int k_read = (sc->fc.dv_buf->k_read + 1) % 16; + u_int32_t *read_buf; + read_buf = (u_int32_t *) ((caddr_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + while((*read_buf & htonl(0xf0)) != htonl(0xf0)){ + *read_buf |= htonl(0xf0); + k_read = (k_read + 1) % 16; + read_buf = (u_int32_t *) ((caddr_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + } + sc->fc.dv_buf->k_read = k_read; + /* if signal is registered, raise up signal */ + if( sc->fc.dv_read_proc != 0 && + !(sc->fc.read_signal & OHCI_READ_SIGMASK)){ + psignal(sc->fc.dv_read_proc, sc->fc.read_signal ); + } + } + } + if((csr & OHCI_INT_DMA_PTRQ )){ + u_int32_t next_cmd; + sc->base->dma_ch[ARRQ_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + next_cmd = sc->base->dma_ch[ARRQ_CH].cmd; + sc->base->dma_ch[ARRQ_CH].cmd + = vtophys(sc->db_last[ARRQ_CH]->next->next->db) | 1; + sc->base->dma_ch[ARRQ_CH].cntl = OHCI_CNTL_DMA_RUN; + fwohci_rcv(sc, ARRQ_CH); + } + if((csr & OHCI_INT_DMA_PTRS )){ + u_int32_t next_cmd; + sc->base->dma_ch[ARRS_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + next_cmd = sc->base->dma_ch[ARRS_CH].cmd; + sc->base->dma_ch[ARRS_CH].cmd + = vtophys(sc->db_last[ARRS_CH]->next->next->db) | 1; + sc->base->dma_ch[ARRS_CH].cntl = OHCI_CNTL_DMA_RUN; + fwohci_rcv(sc, ARRS_CH); + } + if((csr & OHCI_INT_DMA_ATRQ )){ + #if 0 + dump_dma(sc, ATX_CH); + dump_db(sc, ATX_CH); + #endif + fwohci_txd(sc, ATRQ_CH); + if (ifp->if_snd.ifq_head != NULL){ + fwohci_start(ifp); + } + } + if((csr & OHCI_INT_DMA_ATRS )){ + #if 0 + dump_dma(sc, ATX_CH); + dump_db(sc, ATX_CH); + #endif + fwohci_txd(sc, ATRS_CH); + if (ifp->if_snd.ifq_head != NULL){ + fwohci_start(ifp); + } + } + if((csr & OHCI_INT_DMA_IT )){ + u_int32_t ist; + ist = sc->base->it_int_stat; + + sc->base->it_int_clear = ~0; + + if((1 << (ITX_CH - ITX_CH)) & ist){ + fwohci_txd(sc, ITX_CH); + if (ifp->if_snd.ifq_head != NULL){ + fwohci_start(ifp); + } + } + if((1 << (DVTX_CH - ITX_CH)) & ist){ + if(INITREG(&sc->fc, oPCR) & DV_BROADCAST_ON){ + fwohci_start_txdv(sc); + }else if( sc->fc.dv_start != 0 ){ + fwohci_start_txdv(sc); + }else{ + sc->base->it_mask_clear + = 1 << (DVTX_CH - 4); + sc->base->dma_itch[DVTX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN ; + sc->fc.dv_buf->k_write = ~0; + } + if( sc->fc.dv_start == 0 ){ + /* if write operation is blocked, wake up it */ + if(sc->fc.dv_flags & FW_DVWRWAIT){ + wakeup((caddr_t)sc); + } + /* if signal is registered, raise up signal */ + if( sc->fc.dv_write_proc != 0 && + !(sc->fc.write_signal & OHCI_WRITE_SIGMASK)){ + psignal(sc->fc.dv_write_proc, + sc->fc.write_signal ); + } + } + } + } + #if 0 + if((csr & OHCI_INT_AT_BAD )){ + dump_dma(sc, ATX_CH); + dump_db(sc, ATX_CH); + fwohci_txd(sc, ATX_CH); + if (ifp->if_snd.ifq_head != NULL){ + fwohci_start(ifp); + } + } + #endif + #if 0 + if(csr & OHCI_INT_IT_BAD ){ + dump_dma(sc, DVTX_CH); + dump_db(sc, DVTX_CH); + sc->base->dma_itch[DVTX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN; + sc->fc.dv_buf->k_write = ~0; + sc->base->int_mask_clear = OHCI_INT_IT_BAD; + sc->base->int_mask_clear = OHCI_INT_DMA_ITB; + } + #endif + } + return; + } + /* + * TX'd mbuf housekeeping + */ + void fwohci_txd(sc, ch) + struct fwohci_softc *sc; + int ch; + { + struct fwohcidb_tr *txd, *current; + int s; + int imask_tmp; + volatile u_int32_t *cntl, *cntl_clr, *cmd; + + /* if error, stop DMA, reset TX buffer */ + txd = sc->db_first[ch]; + if( ch < ITX_CH ){ + cntl = &(sc->base->dma_ch[ch].cntl); + cntl_clr = &(sc->base->dma_ch[ch].cntl_clr); + cmd = &(sc->base->dma_ch[ch].cmd); + }else{ + cntl = &(sc->base->dma_itch[ch - 4].cntl); + cntl_clr = &(sc->base->dma_itch[ch - 4].cntl_clr); + cmd = &(sc->base->dma_itch[ch - 4].cmd); + } + if((*cmd & 0xfffffff0) == vtophys(txd->db)){ + return; + } + while(sc->queued[ch] > 0){ + /* Buggy ?, Where, Who does care unset queueed packet */ + current = txd->next; + if(*cntl & OHCI_CNTL_DMA_DEAD ){ + #ifdef LYNX_DEBUG + dump_dma(sc, ch); + dump_db(sc, ch); + #endif + /* Stopping DMA db.immediately */ + *cntl_clr = OHCI_CNTL_DMA_RUN ; + if( ch == ATRQ_CH ){ + printf("resetting ATF\n"); + imask_tmp = sc->base->int_mask; + /* + sc->base->hcc_cntl_set |= OHCI_HCC_RESET; + DELAY(100); + */ + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set |= OHCI_HCC_LPS; + sc->base->hcc_cntl_set |= OHCI_HCC_LINKEN; + sc->base->int_mask = imask_tmp; + }else if( ch == ATRS_CH ){ + printf("resetting ATF\n"); + imask_tmp = sc->base->int_mask; + /* + sc->base->hcc_cntl_set |= OHCI_HCC_RESET; + DELAY(100); + */ + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set |= OHCI_HCC_LPS; + sc->base->hcc_cntl_set |= OHCI_HCC_LINKEN; + sc->base->int_mask = imask_tmp; + }else if( ch == ITX_CH ){ + printf("resetting ITF\n"); + imask_tmp = sc->base->int_mask; + /* + sc->base->hcc_cntl_set |= OHCI_HCC_RESET; + DELAY(100); + */ + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set |= OHCI_HCC_LPS; + sc->base->hcc_cntl_set |= OHCI_HCC_LINKEN; + sc->base->int_mask = imask_tmp; + }else{ + printf("Which ch does error occured ???\n"); + } + *cntl_clr = OHCI_CNTL_DMA_RUN; + } + m_freem(current->mbhead); + current->mbhead = NULL; + + s = splimp(); + sc->queued[ch] --; + splx(s); + txd = current; + sc->db_first[ch] = current; + if((*cmd & 0xfffffff0) == vtophys(current->db)){ + return; + } + } + } + static int + fwohci_ioctl( struct ifnet *ifp, u_long cmd, caddr_t data ) + { + struct fwohci_softc *sc = ifp->if_softc; + struct arpcom *ac = (struct arpcom *)ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *) data; + struct fwintreq *fwintr = (struct fwintreq *) data; + u_int32_t *npm = (u_int32_t *)data; + u_int32_t ch; + int err = 0; + u_int fun; + switch (cmd){ + case SIOCSNPM: + ch = fw_setbmslot(ifp, *npm & 0xff); + break; + case SIOCSIFADDR: + sc->base->dma_irch[IPRX_CH - IRX_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + fwohci_rx_enable(sc, + IPRX_CH, ac->media.firewire.broadcast ); + sc->base->int_mask |= OHCI_INT_EN| OHCI_INT_DMA_IR; + sc->base->dma_irch[IPRX_CH - IRX_CH].cntl = OHCI_CNTL_DMA_RUN; + if(!(sc->fc.fw_flags & FWIP_UP)){ + firewire_ifinit(ac, ifa); + } + ifp->if_flags |= IFF_UP ; + sc->fc.fw_flags |= FWIP_UP; + break; + case SIOCRDCSR: + fwintr->req.mem.data = read_reg((struct fw_softc *)sc, fwintr->req.mem.addr); + break; + case SIOCGETTLABEL: + fwintr->req.pcbreq.data + = fw_get_tlabel(ifp, TLABEL_PCB, fwintr->req.pcbreq.pcb); + break; + case SIOCRELTLABEL: + break; + case SIOCISOENA: + /* more queue is required */ + if(fwintr->req.pcbreq.data >= 0x100 ){ + err = EINVAL; + return err; + } + if(sc->flags & OHCI_ISORA){ + err = EBUSY; + return err; + } + if( sc->fc.isoslot[fwintr->req.pcbreq.data].type + != ISOSLOT_NULL){ + err = EBUSY; + return err; + } + ifp->if_flags |= IFF_UP ; + + sc->flags |= OHCI_ISORA; + + fwohci_stop_dma(sc, IRX_CH); + fwohci_rx_enable(sc, IRX_CH, fwintr->req.pcbreq.data); + sc->base->int_mask |= OHCI_INT_EN| OHCI_INT_DMA_IR; + sc->fc.isoslot[fwintr->req.pcbreq.data].type = ISOSLOT_PCB; + sc->fc.isoslot[fwintr->req.pcbreq.data].resp.pcb + = fwintr->req.pcbreq.pcb; + sc->base->dma_irch[IRX_CH - IRX_CH].cntl + = OHCI_CNTL_ISOHDR | OHCI_CNTL_DMA_RUN; + break; + case SIOCISODIS: + if(fwintr->req.pcbreq.data >= 0x100 ){ + err = EINVAL; + return err; + } + sc->base->ir_mask_clear = (1 << (IRX_CH - IRX_CH)); + sc->fc.isoslot[fwintr->req.pcbreq.data].type = ISOSLOT_NULL; + sc->flags &= ~OHCI_ISORA; + fwohci_stop_dma(sc, IRX_CH); + + break; + case SIOCGIFADDR: + err = EINVAL; + case SIOCFWRESET: + fwohci_ibr(sc); + break; + /* + case SIOCCYCMTR: + sc->base->link_cntl |= LYNX_LINK_CYCMASTER; + break; + case SIOCCYCSLV: + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + break; + */ + case SIOCDEBUGPHY: + if( fwintr->req.mem.addr < 8){ + fun = tsb21lv_rddata(&sc->base->phy_access, + fwintr->req.mem.addr); + fwintr->req.mem.data = fun; + }else{ + err = EINVAL; + } + break; + case DUMPDMA: + if(fwintr->req.ch <= OHCI_MAX_DMA_CH ){ + dump_dma(sc, fwintr->req.ch); + dump_db(sc, fwintr->req.ch); + }else{ + err = EINVAL; + } + break; + case SIOCFWWRREG: + #define OHCI_MAX_REG 0x800 + if(fwintr->req.mem.addr <= OHCI_MAX_REG){ + fwohcireg_t *reg; + reg = (fwohcireg_t *)sc->base; + reg[fwintr->req.mem.addr/4] + = fwintr->req.mem.data; + fwintr->req.mem.data + = reg[fwintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + case SIOCFWRDREG: + if(fwintr->req.mem.addr < OHCI_MAX_REG){ + fwohcireg_t *reg; + reg = (fwohcireg_t *)sc->base; + fwintr->req.mem.data = reg[fwintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + default: + err = EINVAL; + } + /* Anyway send a packet and get a status */ + return err; + } + void dump_dma(struct fwohci_softc *sc, int ch){ + struct ohci_dma *dma_reg; + fwohcireg_t stat; + if(ch < ITX_CH ){ + dma_reg = &sc->base->dma_ch[ch]; + }else if(ch < IRX_CH){ + dma_reg = (struct ohci_dma *)&sc->base->dma_itch[ch - ITX_CH]; + }else{ + dma_reg = &sc->base->dma_irch[ch - IRX_CH]; + } + stat = dma_reg->cntl; + + printf("fwohci%d dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x \n", + FWOHCIARGS(sc), + ch, + dma_reg->cntl, + stat, + dma_reg->cmd, + dma_reg->match); + stat &= 0xffff ; + if(stat & 0xff00){ + printf("fwohci%d dma %d ch:%s%s%s%s%s%s %s(%x)\n", + FWOHCIARGS(sc), + ch, + stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", + stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", + stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", + stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", + stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", + stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", + ackcode[(stat & 0xf) * 2], + stat & 0xf + ); + }else{ + printf("fwohci%d dma %d ch: Nostat\n", + FWOHCIARGS(sc), ch); + } + } + void dump_db(struct fwohci_softc *sc, int ch){ + struct fwohcidb_tr *db_tr; + struct fwohcidb *curr = NULL, *prev; + int idb, jdb; + struct ohci_dma *dma_reg; + + if( sc->ndb[ch] == 0 ){ + printf("No DB is attached ch= %d\n", ch); + return; + } + if(ch < ITX_CH ){ + dma_reg = &sc->base->dma_ch[ch]; + }else if(ch < IRX_CH){ + dma_reg = (struct ohci_dma *)&sc->base->dma_itch[ch - ITX_CH]; + }else{ + dma_reg = &sc->base->dma_irch[ch - IRX_CH]; + } + + db_tr = sc->db_tr[ch]; + + prev = db_tr[sc->ndb[ch] - 1].db; + for(idb = 0 ; idb < sc->ndb[ch] ; idb ++ ){ + for(jdb = 0 ; jdb <= ILINKDBBUF ; jdb ++ ){ + if((dma_reg->cmd & 0xfffffff0) + == vtophys(&(db_tr[idb].db->unit[jdb]))){ + curr = db_tr[idb].db; + goto outdb; + } + } + prev = db_tr[idb].db; + } + outdb: + if( curr != NULL){ + printf("Previous DB\n"); + print_db(prev, ch); + printf("Current DB\n"); + print_db(curr, ch); + }else{ + printf("dbdump err ch = %d cmd = 0x%08x\n", ch, dma_reg->cmd); + } + return; + } + void print_db(struct fwohcidb *db, int ch){ + fwohcireg_t stat; + int i, key; + + printf("ch = %d\n%8s %s %s %s %s %4s %8s %8s %8s\n", + ch, + "Current", + "OP ", + "KEY", + "INT", + "BR ", + "bytes", + "Addr", + "Depend", + "Status"); + for( i = 0 ; i <= ILINKDBBUF ; i ++){ + key = db->unit[i].db.desc.cmd & OHCI_KEY_MASK; + printf("%08x %s %s %s %s %5d %08x %08x %08x", + vtophys(&db->unit[i]), + dbcode[(db->unit[i].db.desc.cmd >> 28) & 0xf], + dbkey[(db->unit[i].db.desc.cmd >> 24) & 0x7], + dbcond[(db->unit[i].db.desc.cmd >> 20) & 0x3], + dbcond[(db->unit[i].db.desc.cmd >> 18) & 0x3], + db->unit[i].db.desc.cmd & 0xffff, + db->unit[i].db.desc.addr, + db->unit[i].db.desc.depend, + db->unit[i].db.desc.status); + stat = db->unit[i].db.desc.status >> 16 ; + if(stat & 0xff00){ + printf(" %s%s%s%s%s%s %s(%x)\n", + stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", + stat & OHCI_CNTL_DMA_WAKE ? "WAKE," : "", + stat & OHCI_CNTL_DMA_DEAD ? "DEAD," : "", + stat & OHCI_CNTL_DMA_ACTIVE ? "ACTIVE," : "", + stat & OHCI_CNTL_DMA_BT ? "BRANCH," : "", + stat & OHCI_CNTL_DMA_BAD ? "BADDMA," : "", + ackcode[(stat & 0xf) * 2], + stat & 0xf + ); + }else{ + printf(" Nostat\n"); + } + if(key == OHCI_KEY_ST2 ){ + printf("0x%08x 0x%08x 0x%08x 0x%08x\n", + db->unit[i+1].db.immed[0], + db->unit[i+1].db.immed[1], + db->unit[i+1].db.immed[2], + db->unit[i+1].db.immed[3]); + } + if(key == OHCI_KEY_DEVICE){ + return; + } + if((db->unit[i].db.desc.cmd & OHCI_BRANCH_MASK) + == OHCI_BRANCH_ALWAYS){ + return; + } + if(key == OHCI_KEY_ST2 ){ + i++; + } + } + return; + } + void fwohci_ibr(sc) + struct fwohci_softc *sc; + { + u_int32_t fun; + /* Bus reset should be initiated and processed only by PHY chip set */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_IBR_REG); + fun |= FW_PHY_IBR; + fun = tsb21lv_wrdata(&sc->base->phy_access, FW_PHY_IBR_REG, fun); + } + void fwohci_stop_rxdv(sc) + struct fwohci_softc *sc; + { + sc->base->dma_irch[DVRX_CH - IRX_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + sc->base->ir_mask_clear |= (1 << (DVRX_CH - IRX_CH)); + } + void fwohci_start_rxdv(sc) + struct fwohci_softc *sc; + { + int ch, idb, iseq; + if( sc->fc.dv.rklock ) return; /* avoid duplication */ + sc->fc.dv.rklock = 1; + + ch = (INITREG(&sc->fc, iPCR) >> 16) & 0x3f; + + sc->base->dma_irch[DVRX_CH - IRX_CH].cntl_clr = OHCI_CNTL_DMA_RUN; + for( iseq = 0 ; iseq < MAX_DVFRAME ; iseq ++){ + for( idb = 0 ; idb < DVBUF ; idb++){ + sc->dbdvrx[iseq].db_tr[idb].db->unit[1].db.desc.status = 0; + } + } + sc->base->dma_irch[DVRX_CH - IRX_CH].cmd + = vtophys(sc->dbdvrx[0].db) | 1; + sc->base->dma_irch[DVRX_CH - IRX_CH].match + = 0xf0000000 | (ch & 0x3f) ; + sc->base->int_mask |= OHCI_INT_EN| OHCI_INT_DMA_IR; + sc->base->ir_int_mask |= (1 << (DVRX_CH - IRX_CH)); + sc->base->dma_irch[DVRX_CH - IRX_CH].cntl = OHCI_CNTL_DMA_RUN ; + + sc->fc.dv.rklock = 0; + } + void fwohci_set_bmr(sc) + struct fwohci_softc *sc; + { + int i; + sc->base->csr_data = 0; + sc->base->csr_cmp = 0; + sc->base->csr_cntl = 0; + for( i = 0 ; i < 10000000 ; i++){ + if(sc->base->csr_cntl & (1 << 31 )) break; + } + if((sc->base->csr_data & 0x3f ) == 0x3f ){ + INITREG(&sc->fc, BUS_MGR_ID) = + sc->base->csr_data = (INITREG(&sc->fc, NODE_IDS) >> 16) & 0x3f ; + sc->base->csr_cmp = 0x3f; + sc->base->csr_cntl = 0; + }else{ + INITREG(&sc->fc, BUS_MGR_ID) = sc->base->csr_data; + } + } + void fwohci_start_txdv(sc) + struct fwohci_softc *sc; + { + u_int i, i_cnt, size; + u_int32_t *ld; + u_int ch, seq, len, iseq; + struct fw_softc *fc = &sc->fc; + struct dv_data *dv_buf; + struct fwohcidb_tr *db_tr, *db_tr_next; + u_int32_t cyc; + + if( fc->dv.wklock ) return; /* avoid duplicate */ + fc->dv.wklock = 1; + + dv_buf = fc->dv_buf; + + sc->base->int_mask |= OHCI_INT_EN | OHCI_INT_DMA_IT ; + sc->base->it_int_mask |= (1 << (DVTX_CH - 4)); + + if( fc->dv_start == 0 ){ + /* attempt to get next frame */ + dv_buf->k_write + = (dv_buf->k_write + 1) % dv_buf->n_write; + if(dv_buf->k_write == dv_buf->a_write){ + dv_buf->k_write = + (dv_buf->k_write + dv_buf->n_write - 1) + % dv_buf->n_write; + } + } + iseq = dv_buf->k_write; + + ch = (INITREG(fc, oMPR) >> 24) & 0x3f; + len = dv_buf->write_len[iseq]; + if( len > (DVBUF - 1)){ + INITREG(fc, oPCR) &= ~DV_BROADCAST_ON; + fc->dv.queued = 0; + sc->base->dma_itch[DVTX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN ; + goto out; + } + + if( fc->dv_end == 0){ + fc->dv_end = len; + } + if( fc->dv_end > len ){ + fc->dv_end = len; + } + if( fc->dv_start > fc->dv_end ){ + fc->dv_start = 0; + } + ld = &(sc->fc.dv_write_buf[iseq][fc->dv_start * S100_SZ/4]); + for( i = fc->dv_start ; i < fc->dv_end ; i++){ + db_tr = &(sc->dbdvtx[iseq].db_tr[i]); + size = ntohl(ld[0]) >> 16; + if(size >= S100_SZ - 12 ) size = S100_SZ - 12; + if( size < 0x8 ) size = 8; /* CIP header only */ + db_tr->db->unit[0].db.desc.cmd + = OHCI_OUTPUT_MORE | OHCI_KEY_ST2 | 8; + ld[0] = htonl((DV_ISOTAGCIP << 14) | + (TCODE_STREAM << 4)| size << 16 | (ch << 8)); + db_tr->db->unit[1].db.immed[0] + = (OHCI_SPD_S100 << 16 ) | (DV_ISOTAGCIP << 14 ) | + (TCODE_STREAM << 4) | (ch << 8); + db_tr->db->unit[1].db.immed[1] + = size << 16; + db_tr->db->unit[0].db.desc.status = 0; + ld[1] = htonl((((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f) << 24) | + ((DVSIZE / 4 ) << 16 )| (fc->dv.dbc & 0xff)); + if( size > 8 ){ + fc->dv.dbc++; + } + db_tr->db->unit[0].db.desc.depend + &= 0xfffffff0; + db_tr->db->unit[2].db.desc.cmd + = OHCI_OUTPUT_LAST | + OHCI_BRANCH_ALWAYS | (size & 0xfff); + db_tr_next = db_tr->next; + db_tr->db->unit[0].db.desc.depend + = db_tr->db->unit[2].db.desc.depend + = vtophys(db_tr_next->db); + db_tr->db->unit[2].db.desc.depend |= 3; + db_tr->db->unit[0].db.desc.depend |= 3; + if( i == (fc->dv_intr - 1)){ + db_tr->db->unit[2].db.desc.cmd + |= OHCI_INTERRUPT_ALWAYS; + }else if( i >= (len - 1)){ + db_tr->db->unit[2].db.desc.cmd &= ~OHCI_BRANCH_ALWAYS; + db_tr->db->unit[2].db.desc.cmd + |= OHCI_INTERRUPT_ALWAYS; + db_tr->db->unit[2].db.desc.depend &= 0xfffffff0; + db_tr->db->unit[0].db.desc.depend &= 0xfffffff0; + } + ld += S100_SZ/4; + } + + if( i < len ){ + fc->dv_start = fc->dv_intr; + fc->dv_end = 0; + goto out; + }else{ + fc->dv_start = 0; + fc->dv_end = fc->dv_intr; + } + + ld = sc->fc.dv_write_buf[iseq]; + + /**/ + for( i_cnt = 0 ; i_cnt < 10000000 ; i_cnt++){ + if(!(sc->base->dma_itch[DVTX_CH - 4].cntl & OHCI_CNTL_DMA_ACTIVE)){ + break; + } + } + /**/ + if((sc->base->dma_itch[DVTX_CH - 4].cntl & OHCI_CNTL_DMA_ACTIVE)){ + printf("OHCI still active\n"); + } + cyc = ((*(fc->p_cycle_timer)) & 0xf000) + fc->dv_gap; + ld[2] = ( ld[2] & htonl(0xffff0000)) | htonl(cyc & 0x0000ffff) ; + if(!(sc->base->dma_itch[DVTX_CH - 4].cntl & OHCI_CNTL_DMA_ACTIVE)){ + sc->base->dma_itch[DVTX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN; + sc->base->dma_itch[DVTX_CH - 4].cmd + = vtophys(sc->dbdvtx[iseq].db) | 3; + sc->base->dma_itch[DVTX_CH - 4].cntl = OHCI_CNTL_DMA_RUN; + } else{ + sc->base->dma_itch[DVTX_CH - 4].cntl_clr = OHCI_CNTL_DMA_RUN; + INITREG(fc, oPCR) &= ~((0x3f<<16)|(0x0f<<10)); + INITREG(fc, oPCR) &= ~DV_BROADCAST_ON; + fc->dv_buf->k_write = 0xffffffff; + } + fc->dv.queued--;if(fc->dv.queued < 0 ) fc->dv.queued = 0; + out: + fc->dv.wklock = 0; + } + + static void fwohci_reset(sc) + struct fwohci_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + ifp->if_flags &= ~IFF_UP; + /* Not implemented yet. */ + + ifp->if_flags |= IFF_UP; + return; + } + #ifdef RX_DMA + int fwohci_add_rx_buf(db_tr, oldm) + struct fwohcidb_tr *db_tr; + struct mbuf *oldm; + { + struct mbuf *m; + struct fwohcidb *db = db_tr->db; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m != NULL) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + if (oldm == NULL) return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + } else { + if (oldm == NULL) + return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + m->m_pkthdr.len = m->m_len = MCLBYTES; + + db_tr->mbhead = m; + db->data[0].ptr = vtophys(mtod(m, vm_offset_t)) ; + db->data[0].ptr += sizeof(fwcntl); + db->data[0].cntl = LYNX_PCL_RCV_UPDATE | LYNX_PCL_INT + | LYNX_PCL_LASTBUF | (MCLBYTES - 4); + db->db_next &= ~LYNX_DMA_PCL_EN;; + return(m == oldm); + } + #else + int fwohci_forward_rx_buf(db_tr, ch) + struct fwohcidb_tr *db_tr; + int ch; + { + struct fwohcidb *db = db_tr->db; + + db_tr->mbhead = 0; + db->unit[0].db.desc.addr = vtophys(db_tr->buf) ; + db->unit[0].db.desc.addr += sizeof(fwcntl); + if( ch < ITX_CH){ + db->unit[0].db.desc.cmd + = OHCI_INPUT_MORE | OHCI_INTERRUPT_ALWAYS + | OHCI_BRANCH_ALWAYS | MCLBYTES ; + }else{ + db->unit[0].db.desc.cmd + = OHCI_INPUT_LAST | OHCI_INTERRUPT_ALWAYS + | OHCI_UPDATE | OHCI_BRANCH_ALWAYS | MCLBYTES ; + } + db->unit[0].db.desc.status = 0; + return(0); + } + #endif + + static void fwohci_rcv(sc, ch) + struct fwohci_softc *sc; + int ch; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + struct mbuf *m; + int idb = 0, i; + u_int tcode; + struct fwohcidb_tr *db_tr; + struct fwhdr *ld; + struct ohci_dma *dma_reg; + #if 0 + dump_dma(sc, ch); + dump_db(sc, ch); + #endif + if(ch < ITX_CH ){ + dma_reg = &sc->base->dma_ch[ch]; + }else{ + dma_reg = &sc->base->dma_irch[ch - IRX_CH]; + } + rcvloop: + if((vtophys(sc->db_last[ch]->next->db) + == ( dma_reg->cmd & 0xfffffff0)) || idb >= sc->ndb[ch]){ + return; + } + db_tr = sc->db_last[ch]->next; + + idb++; + ifp->if_ipackets++; + #ifdef RX_DMA + if((m = db_tr->mbhead) != NULL ){ + if( fwohci_add_rx_buf(db_tr, m) == 0){ + #else + MGETHDR(m, M_DONTWAIT, MT_DATA); + if(m == NULL) + return; + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + fwohci_forward_rx_buf(db_tr, ch); + return; + } + if((db_tr->db->unit[0].db.desc.status & 0xffff) != 0 ){ + m->m_pkthdr.len = m->m_len = + MCLBYTES - (db_tr->db->unit[0].db.desc.status & 0xffff) + + sizeof(fwcntl); + }else{ + m->m_pkthdr.len = m->m_len = MCLBYTES; + } + if( ch == ARRQ_CH && + ((db_tr->db->unit[0].db.desc.status & OHCI_XSTAT_MASK) + == OHCI_XSTAT_PHY )){ + ld = mtod(m, struct fwhdr *); + m->m_pkthdr.len = m->m_len + = sizeof(fwcntl) + 4 + (sc->base->sid_cnt & 0xfff); + for( i = 4 ; i < m->m_len ; i+= 4){ + ld->data[i/4] = htonl(sc->fc.sid_buf[i/4]); + } + ld->data[0] = htonl(TCODE_SID << 4); + }else{ + if(( ch != ARRQ_CH ) && ( ch != ARRS_CH)){ + m->m_pkthdr.len -= 4; + m->m_len -= 4; + bcopy(db_tr->buf + 4, mtod(m, caddr_t), m->m_len); + ld = mtod(m, struct fwhdr *); + tcode = TCODE_STREAM; + m->m_pkthdr.len = m->m_len = + (ld->data[0] >> 16) + sizeof(struct fwisohdr); + }else{ + m->m_pkthdr.len -= 4; + m->m_len -= 4; + bcopy(db_tr->buf, mtod(m, caddr_t), m->m_len); + ld = mtod(m, struct fwhdr *); + tcode = (ld->data[0] & 0xf0) >> 4; + } + /* Asy transaction header requires endian arrangement */ + switch(tcode){ + case TCODE_BLKWRREQ: + case TCODE_BLKRDRES: + case TCODE_LKRES: + case TCODE_LKREQ: + m->m_pkthdr.len = m->m_len = + (ld->data[3] >> 16) + sizeof(struct fwasyhdr); + case TCODE_BLKRDREQ: + ld->data[3] = htonl(ld->data[3]); + case TCODE_RDRES: + default: + ld->data[2] = htonl(ld->data[2]); + ld->data[1] = htonl(ld->data[1]); + case TCODE_STREAM: + ld->data[0] = htonl(ld->data[0]); + } + } + #if 0 + printf("0x%08lx ", ntohl(ld->data[0])); + printf("0x%08lx ", ntohl(ld->data[1])); + printf("0x%08lx ", ntohl(ld->data[2])); + printf("0x%08lx\n", ntohl(ld->data[3])); + #endif + #endif + m->m_pkthdr.rcvif = ifp; + if (ifp->if_bpf) { + struct mbuf m0; + u_int af = AF_UNSPEC; + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } + ld = mtod(m, struct fwhdr *); + switch( ch ){ + case ARRQ_CH: + if((ntohl(ld->data[0]) & 0xf0) == 0xe0){ + #if 0 + ld->cntl[0] = PROTO_N1394ISOST; + m_adj(m, 4);/* chop status area */ + m_adj(m, -4);/* chop trailer */ + fw_sid_input(ifp, m); + #else + m_freem(m); + #endif + }else{ + ld->cntl[0] = PROTO_N1394ASYRQ; + fw_asy_req_input(ifp, m); + } + break; + case ARRS_CH: + ld->cntl[0] = PROTO_N1394ASYRQ; + fw_asy_resp_input(ifp, m); + break; + default: + ld->cntl[0] = PROTO_N1394ISOST; + fw_stream_input(ifp, m); + break; + } + #ifndef RX_DMA + fwohci_forward_rx_buf(db_tr, ch); + #endif + /**/ + sc->db_last[ch]->db->unit[0].db.desc.cmd &= 0xffff0000; + sc->db_last[ch]->db->unit[0].db.desc.cmd |= MCLBYTES; + /* + db_tr->db->unit[0].db.desc.cmd &= 0xffff0000; + db_tr->db->unit[0].db.desc.cmd |= MCLBYTES; + */ + #if 0 + sc->db_last[ch]->db->unit[0].db.desc.depend |= (ch < 4 ) ? 1 : 2; + #else + sc->db_last[ch]->db->unit[0].db.desc.depend |= (ch < 4 ) ? 1 : 1; + #endif + sc->db_last[ch] = sc->db_last[ch]->next; + sc->db_last[ch]->db->unit[0].db.desc.depend &= 0xfffffff0; + goto rcvloop; + } + + /* Call every time after BUS reset */ + void fwohci_busreset(sc) + struct fwohci_softc *sc; + { + struct arpcom *ac = (struct arpcom *)sc; + int ch, ir, i, node, spd, c, pwr, p0, p1, p2; + /* Prevent LOST CYCLE interrupt */ + sc->base->int_mask_clear = OHCI_INT_CYC_LOST; + + INITREG(&sc->fc, STATE_CLEAR) + = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ; + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + /* Stopping all DMA channel processing, except Async recieve */ + + for( ch = 0 ; ch < MAXOHCI_CH ; ch ++){ + if(ch != 0x2){ + fwohci_stop_dma(sc, ch); + } + } + sc->init = 0; + /* + ** Checking whether root node or not. If this node is root, the Cycle + ** master bit is set. + */ + i = 0; + while((!(sc->base->node & OHCI_NODE_VALID)) && i < 10000 ){ + i++; + DELAY(100); + } + sc->base->link_cntl_clr = OHCI_CNTL_CYCSRC; + /* + if( sc->base->node & OHCI_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->link_cntl = OHCI_CNTL_CYCMTR | OHCI_CNTL_CYCTIMER; + }else{ + sc->base->link_cntl = OHCI_CNTL_CYCTIMER; + sc->base->link_cntl_clr = OHCI_CNTL_CYCMTR; + } + */ + node = 0x3f & sc->base->node; + /* clear bus-id */ + sc->base->node &= 0xffff003f; + INITREG(&sc->fc, NODE_IDS) = ( 0x3f & sc->base->node) << 16; + + if_fwbusreset(&sc->fc); + + printf("fwohci: node 0x%08x\n", INITREG(&sc->fc, NODE_IDS)); + + /* Link initialization is ready */ + sc->base->link_cntl = OHCI_CNTL_CYCTIMER; + /**/ + sc->base->hcc_cntl_clr = OHCI_HCC_LINKEN; + sc->base->hcc_cntl_set |= OHCI_HCC_LPS; + sc->base->hcc_cntl_set |= OHCI_HCC_LINKEN; + /**/ + INITREG(&sc->fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 ); + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + + if( sc->fc.fw_flags & FWIP_UP){ + fwohci_rx_enable(sc, + IPRX_CH, ac->media.firewire.broadcast ); + sc->base->int_mask |= OHCI_INT_EN| OHCI_INT_DMA_IR; + sc->base->dma_irch[IPRX_CH - IRX_CH].cntl = OHCI_CNTL_DMA_RUN; + } + } + #endif /* !defined(__FreeBSD__) || (FWOHCI > 0 && NPCI > 0) */ diff -r -c -N sys44.orig/dev/firewire/fwohcireg.h sys/dev/firewire/fwohcireg.h *** sys44.orig/dev/firewire/fwohcireg.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/fwohcireg.h Tue Oct 9 21:55:17 2001 *************** *** 0 **** --- 1,345 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: fwohcireg.h,v 1.1.2.1 2000/06/04 17:19:05 ikob Exp $ + * + */ + #define FW_VENDORID_NEC 0x1033 + #define FW_VENDORID_TI 0x104c + #define FW_VENDORID_SONY 0x104d + #define FW_VENDORID_VIA 0x1106 + #define FW_VENDORID_LUCENT 0x11c1 + #define FW_VENDORID_ADVANSYS 0x10cd + + /* NEC */ + #define FW_DEVICE_uPD72861 0x0063 + #define FW_DEVICE_uPD72870 0x00cd + #define FW_DEVICE_uPD72871 0x00ce + + /* Texas Instruments */ + #define FW_DEVICE_TI_TSB12LV22 0x8009 + #define FW_DEVICE_TI_TSB12LV23 0x8019 + #define FW_DEVICE_TI_TSB12LV26 0x8020 + #define FW_DEVICE_TI_TSB43AA22 0x8021 + + /* SONY */ + #define FW_DEVICE_SONY_CXD3222 0x8039 + + /* VIA */ + #define FW_DEVICE_VIA 0x3044 + + /* LUCENT */ + #define FW_DEVICE_LUCENT 0x5811 + + /* ADVANSYS */ + #define FW_DEVICE_ASC03C0400A_TQ 0x4000 + + #define OHCI_MAX_DMA_CH 0x4 + 0x20 + 0x20 + + #define ILINKDBBUF 8 + + typedef volatile u_int32_t fwohcireg_t; + struct fwohcidbunit { + union { + struct { + volatile u_int32_t cmd; + volatile u_int32_t addr; + volatile u_int32_t depend; + volatile u_int32_t status; + } desc; + volatile u_int32_t immed[4]; + } db; + /* + volatile u_int32_t db_cmd; + volatile u_int32_t db_addr; + volatile u_int32_t db_depend; + volatile u_int32_t db_status; + volatile u_int32_t immed[4]; + */ + #define OHCI_OUTPUT_MORE (0 << 28) + #define OHCI_OUTPUT_LAST (1 << 28) + #define OHCI_INPUT_MORE (2 << 28) + #define OHCI_INPUT_LAST (3 << 28) + #define OHCI_STORE_QUAD (4 << 28) + #define OHCI_LOAD_QUAD (5 << 28) + #define OHCI_NOP (6 << 28) + #define OHCI_STOP (7 << 28) + #define OHCI_STORE (8 << 28) + + #define OHCI_UPDATE 1 << 27 + + #define OHCI_KEY_ST0 (0 << 24) + #define OHCI_KEY_ST1 (1 << 24) + #define OHCI_KEY_ST2 (2 << 24) + #define OHCI_KEY_ST3 (3 << 24) + #define OHCI_KEY_REGS (5 << 24) + #define OHCI_KEY_SYS (6 << 24) + #define OHCI_KEY_DEVICE (7 << 24) + #define OHCI_KEY_MASK (7 << 24) + + #define OHCI_INTERRUPT_NEVER (0 << 20) + #define OHCI_INTERRUPT_TRUE (1 << 20) + #define OHCI_INTERRUPT_FALSE (2 << 20) + #define OHCI_INTERRUPT_ALWAYS (3 << 20) + + #define OHCI_BRANCH_NEVER (0 << 18) + #define OHCI_BRANCH_TRUE (1 << 18) + #define OHCI_BRANCH_FALSE (2 << 18) + #define OHCI_BRANCH_ALWAYS (3 << 18) + #define OHCI_BRANCH_MASK (3 << 18) + + #define OHCI_WAIT_NEVER (0 << 16) + #define OHCI_WAIT_TRUE (1 << 16) + #define OHCI_WAIT_FALSE (2 << 16) + #define OHCI_WAIT_ALWAYS (3 << 16) + }; + + #define OHCI_SPD_S100 0x4 + #define OHCI_SPD_S200 0x1 + #define OHCI_SPD_S400 0x2 + + #define OHCI_XSTAT_MASK (0x1f < 16) + #define OHCI_XSTAT_PHY (9 < 16) + + struct fwohcidb { + struct fwohcidbunit unit[ILINKDBBUF+1]; + }; + struct ohci_registers { + fwohcireg_t ver; /* Version No. 0x0 */ + fwohcireg_t guid; /* GUID_ROM No. 0x4 */ + fwohcireg_t retry; /* AT retries 0x8 */ + fwohcireg_t csr_data; /* CSR data 0xc */ + fwohcireg_t csr_cmp; /* CSR compare 0x10 */ + fwohcireg_t csr_cntl; /* CSR compare 0x14 */ + fwohcireg_t rom_hdr; /* config ROM ptr. 0x18 */ + fwohcireg_t bus_id; /* BUS_ID 0x1c */ + fwohcireg_t bus_opt; /* BUS option 0x20 */ + fwohcireg_t guid_hi; /* GUID hi 0x24 */ + fwohcireg_t guid_lo; /* GUID lo 0x28 */ + fwohcireg_t dummy0[2]; /* dummy 0x2c-0x30 */ + fwohcireg_t config_rom; /* config ROM map 0x34 */ + fwohcireg_t post_wr_lo; /* post write addr lo 0x38 */ + fwohcireg_t post_wr_hi; /* post write addr hi 0x3c */ + fwohcireg_t vender; /* vender ID 0x40 */ + fwohcireg_t dummy1[3]; /* dummy 0x44-0x4c */ + fwohcireg_t hcc_cntl_set; /* HCC control set 0x50 */ + fwohcireg_t hcc_cntl_clr; /* HCC control clr 0x54 */ + #define OHCI_HCC_BIGEND (1 << 30) + #define OHCI_HCC_PRPHY (1 << 23) + #define OHCI_HCC_PHYEN (1 << 22) + #define OHCI_HCC_LPS (1 << 19) + #define OHCI_HCC_POSTWR (1 << 18) + #define OHCI_HCC_LINKEN (1 << 17) + #define OHCI_HCC_RESET (1 << 16) + fwohcireg_t dummy2[2]; /* dummy 0x58-0x5c */ + fwohcireg_t dummy3[1]; /* dummy 0x60 */ + fwohcireg_t sid_buf; /* self id buffer 0x64 */ + fwohcireg_t sid_cnt; /* self id count 0x68 */ + fwohcireg_t dummy4[1]; /* dummy 0x6c */ + fwohcireg_t ir_mask_hi_set; /* ir mask hi set 0x70 */ + fwohcireg_t ir_mask_hi_clr; /* ir mask hi set 0x74 */ + fwohcireg_t ir_mask_lo_set; /* ir mask hi set 0x78 */ + fwohcireg_t ir_mask_lo_clr; /* ir mask hi set 0x7c */ + fwohcireg_t int_stat; /* 0x80 */ + fwohcireg_t int_clear; /* 0x84 */ + fwohcireg_t int_mask; /* 0x88 */ + fwohcireg_t int_mask_clear; /* 0x8c */ + fwohcireg_t it_int_stat; /* 0x90 */ + fwohcireg_t it_int_clear; /* 0x94 */ + fwohcireg_t it_int_mask; /* 0x98 */ + fwohcireg_t it_mask_clear; /* 0x9c */ + fwohcireg_t ir_int_stat; /* 0xa0 */ + fwohcireg_t ir_int_clear; /* 0xa4 */ + fwohcireg_t ir_int_mask; /* 0xa8 */ + fwohcireg_t ir_mask_clear; /* 0xac */ + fwohcireg_t dummy5[11]; /* dummy 0xb0-d8 */ + fwohcireg_t fairness; /* fairness control 0xdc */ + fwohcireg_t link_cntl; /* Chip control 0xe0*/ + fwohcireg_t link_cntl_clr; /* Chip control clear 0xe4*/ + fwohcireg_t node; /* Node ID 0xe8 */ + #define OHCI_NODE_VALID (1 << 31) + #define OHCI_NODE_ROOT (1 << 30) + + #define OHCI_ASYSRCBUS (1 << 23) + + fwohcireg_t phy_access; /* PHY cntl 0xec */ + #define TSB21_RDDONE (1<<31) + #define TSB21_RDPHY (1<<15) + #define TSB21_WRPHY (1<<14) + #define TSB21_REGADDR 8 + #define TSB21_WRDATA 0 + #define TSB21_RDADDR 24 + #define TSB21_RDDATA 16 + + fwohcireg_t cycle_timer; /* Cycle Timer 0xf0 */ + fwohcireg_t dummy6[3]; /* dummy 0xf4-fc */ + fwohcireg_t areq_hi; /* Async req. filter hi 0x100 */ + fwohcireg_t areq_hi_clr; /* Async req. filter hi 0x104 */ + fwohcireg_t areq_lo; /* Async req. filter lo 0x108 */ + fwohcireg_t areq_lo_clr; /* Async req. filter lo 0x10c */ + fwohcireg_t preq_hi; /* Async req. filter hi 0x110 */ + fwohcireg_t preq_hi_clr; /* Async req. filter hi 0x114 */ + fwohcireg_t preq_lo; /* Async req. filter lo 0x118 */ + fwohcireg_t preq_lo_clr; /* Async req. filter lo 0x11c */ + + fwohcireg_t pys_upper; /* Physical Upper bound 0x120 */ + + fwohcireg_t dummy7[23]; /* dummy 0x124-0x17c */ + + struct ohci_dma{ + fwohcireg_t cntl; + + #define OHCI_CNTL_CYCMATCH_S (0x1 << 31) + + #define OHCI_CNTL_BUFFIL (0x1 << 31) + #define OHCI_CNTL_ISOHDR (0x1 << 30) + #define OHCI_CNTL_CYCMATCH_R (0x1 << 29) + #define OHCI_CNTL_MULTICH (0x1 << 28) + + #define OHCI_CNTL_DMA_RUN (0x1 << 15) + #define OHCI_CNTL_DMA_WAKE (0x1 << 12) + #define OHCI_CNTL_DMA_DEAD (0x1 << 11) + #define OHCI_CNTL_DMA_ACTIVE (0x1 << 10) + #define OHCI_CNTL_DMA_BT (0x1 << 8) + #define OHCI_CNTL_DMA_BAD (0x1 << 7) + #define OHCI_CNTL_DMA_STAT (0xff) + + fwohcireg_t cntl_clr; + fwohcireg_t dummy0; + fwohcireg_t cmd; + fwohcireg_t match; + fwohcireg_t dummy1; + fwohcireg_t dummy2; + fwohcireg_t dummy3; + }; + /* 0x180, 0x184, 0x188, 0x18c */ + /* 0x190, 0x194, 0x198, 0x19c */ + /* 0x1a0, 0x1a4, 0x1a8, 0x1ac */ + /* 0x1b0, 0x1b4, 0x1b8, 0x1bc */ + /* 0x1c0, 0x1c4, 0x1c8, 0x1cc */ + /* 0x1d0, 0x1d4, 0x1d8, 0x1dc */ + /* 0x1e0, 0x1e4, 0x1e8, 0x1ec */ + /* 0x1f0, 0x1f4, 0x1f8, 0x1fc */ + struct ohci_dma dma_ch[0x4]; + + /* 0x200, 0x204, 0x208, 0x20c */ + /* 0x210, 0x204, 0x208, 0x20c */ + struct ohci_itdma{ + fwohcireg_t cntl; + fwohcireg_t cntl_clr; + fwohcireg_t dummy0; + fwohcireg_t cmd; + }; + struct ohci_itdma dma_itch[0x20]; + + /* 0x400, 0x404, 0x408, 0x40c */ + /* 0x410, 0x404, 0x408, 0x40c */ + + struct ohci_dma dma_irch[0x20]; + }; + + struct fwohcidb_tr{ + struct fwohcidb_tr *next; + struct mbuf *mbhead; + struct fwohcidb *db; + caddr_t buf; + caddr_t buf2; + }; + + /* + * OHCI info structure. + */ + struct fwohci_softc { + struct fw_softc fc; + volatile struct ohci_registers *base; + int init; + #define SIDPHASE 1 + u_int32_t flags; + struct fwohcidb_tr *db_tr[OHCI_MAX_DMA_CH]; + struct fwohcidb_tr *db_first[OHCI_MAX_DMA_CH]; + struct fwohcidb_tr *db_last[OHCI_MAX_DMA_CH]; + struct { + int tail; + struct fwohcidb_tr *db_tr; + struct fwohcidb *db; + }dbdvtx[MAX_DVFRAME], dbdvrx[MAX_DVFRAME]; + int ndb[OHCI_MAX_DMA_CH]; + u_int32_t isohdr[OHCI_MAX_DMA_CH]; + int queued[OHCI_MAX_DMA_CH]; + int dma_ch[OHCI_MAX_DMA_CH]; + }; + + #define OHCI_CNTL_CYCSRC (0x1 << 22) + #define OHCI_CNTL_CYCMTR (0x1 << 21) + #define OHCI_CNTL_CYCTIMER (0x1 << 20) + #define OHCI_CNTL_PHYPKT (0x1 << 10) + #define OHCI_CNTL_SID (0x1 << 9) + + #define OHCI_INT_DMA_ATRQ (0x1 << 0) + #define OHCI_INT_DMA_ATRS (0x1 << 1) + #define OHCI_INT_DMA_ARRQ (0x1 << 2) + #define OHCI_INT_DMA_ARRS (0x1 << 3) + #define OHCI_INT_DMA_PTRQ (0x1 << 4) + #define OHCI_INT_DMA_PTRS (0x1 << 5) + #define OHCI_INT_DMA_IT (0x1 << 6) + #define OHCI_INT_DMA_IR (0x1 << 7) + #define OHCI_INT_PW_ERR (0x1 << 8) + #define OHCI_INT_LR_ERR (0x1 << 9) + + #define OHCI_INT_PHY_SID (0x1 << 16) + #define OHCI_INT_PHY_BUS_R (0x1 << 17) + + #define OHCI_INT_PHY_INT (0x1 << 19) + #define OHCI_INT_CYC_START (0x1 << 20) + #define OHCI_INT_CYC_64SECOND (0x1 << 21) + #define OHCI_INT_CYC_LOST (0x1 << 22) + #define OHCI_INT_CYC_ERR (0x1 << 23) + + #define OHCI_INT_ERR (0x1 << 24) + #define OHCI_INT_CYC_LONG (0x1 << 25) + #define OHCI_INT_PHY_REG (0x1 << 26) + + #define OHCI_INT_EN (0x1 << 31) + + #define IP_CHANNELS 0x0234 + + #define OHCI_ISORA 0x02 + #define OHCI_ISORB 0x04 + + diff -r -c -N sys44.orig/dev/firewire/ilink.c sys/dev/firewire/ilink.c *** sys44.orig/dev/firewire/ilink.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/ilink.c Tue Oct 9 21:55:17 2001 *************** *** 0 **** --- 1,1824 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ilink.c,v 1.1.2.1 2000/06/04 17:19:06 ikob Exp $ + * + */ + + #define DEBUG_PACKET + #undef DEBUG_PACKET + #define ATX_CH 0 + #define ARX_CH 1 + #define ITX_CH 2 + #define DVTX_CH 3 + #define IRX_CH 4 + #define DVRX_CH 5 + #define MAXIPFRAG 40 + + #define RX_DMA + #undef RX_DMA + + #define PREVENT_ISOHDR + #undef PREVENT_ISOHDR + + #ifdef __FreeBSD__ + #include "ilink.h" + #include "pci.h" + #endif /* __FreeBSD__ */ + + #if !defined(__FreeBSD__) || (NILINK > 0 && NPCI > 0) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + + #include + #include + #include + + #ifdef INET + #include + #include + #include + #include + #include + #include + #endif + + #include + #include + + #include + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + + #define ILINK_DEBUG + #undef ILINK_DEBUG + + static char dbcode[16][0x10]={"OUTM", "OUTL","INPM","INPL", + "STOR","LOAD","NOP ","STOP",}; + static char dbkey[8][0x10]={"ST0", "ST1","ST2","ST3", + "UNDEF","REG","SYS","DEV"}; + extern char linkspeed[4][0x10]; + static char dbcond[4][0x10]={"NEV","C=1", "C=0", "ALL"}; + extern char ackcode[32][0x20]; + + #define ILINK_WRITE_SIGMASK 0xffff0000 + #define ILINK_READ_SIGMASK 0xffff0000 + + #define ILINKARGS(sc) (sc)->fc.ac.ac_if.if_unit + + #define senderr(e) { error = (e); goto bad;} + + static void ilink_start_txdv __P((struct ilink_softc *)); + static void ilink_start_rxdv __P((struct ilink_softc *)); + static void ilink_stop_rxdv __P((struct ilink_softc *)); + static void ilink_reset __P((struct ilink_softc *)); + static void ilink_ibr __P((struct ilink_softc *)); + static int ilink_ioctl __P((struct ifnet *, u_long, caddr_t)); + static void ilink_init __P((struct ilink_softc *)); + static void ilink_busreset __P((struct ilink_softc *)); + static void ilink_db_init __P((struct ilink_softc *)); + static void ilink_db_ch_init __P((struct ilink_softc *, int, int, int)); + static void ilink_dv_init __P((struct ilink_softc *)); + static void ilink_rx_enable __P((struct ilink_softc *, int, int)); + static void ilink_rx_disable __P((struct ilink_softc *, int)); + static void ilink_tx_init __P((struct ilink_softc *, int)); + static void ilink_rcv __P((struct ilink_softc *, int)); + static void ilink_txd __P((struct ilink_softc *, int)); + static void ilink_start __P((struct ifnet *)); + static void ilink_intr __P((void *arg)); + #ifdef RX_DMA + static int ilink_add_rx_buf __P((struct ilinkdb_tr *, struct mbuf *)); + #else + static int ilink_forward_rx_buf __P((struct ilinkdb_tr *)); + #endif + static void dump_db __P((struct ilink_softc *, int)); + static void print_db __P((struct ilinkdb *, int )); + static void dump_dma __P((struct ilink_softc *, int)); + static void dump_fifo_ptr __P((struct ilink_softc *)); + + #define NDB 1024 + #define NDVDB DVBUF * 16 + + #define DV_FRAME 12 + + + #ifdef __FreeBSD__ + + static int ilink_probe __P((device_t)); + static int ilink_attach __P((device_t)); + static int ilink_shutdown __P((device_t)); + + #define UNIT(x) (((x) & 0xf0) >> 4) + #define MINOR(x) ((x) & 0xf) + + static device_method_t ilink_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ilink_probe), + DEVMETHOD(device_attach, ilink_attach), + DEVMETHOD(device_shutdown, ilink_shutdown), + { 0, 0 } + }; + + static driver_t ilink_driver = { + "ilink", + ilink_methods, + sizeof(struct ilink_softc), + }; + + static devclass_t ilink_devclass; + + DRIVER_MODULE(if_ilink, pci, ilink_driver, ilink_devclass, 0, 0); + #endif /* __FreeBSD__ */ + + + #ifdef __FreeBSD__ + static int + ilink_probe(device_t dev) + { + if ((pci_get_vendor(dev) == ILINK_VENDORID_SONY) && + (pci_get_device(dev) == ILINK_DEVICE_CX1947)) { + device_set_desc(dev, "SONY CX1947"); + return 0; + } + if ((pci_get_vendor(dev) == ILINK_VENDORID_ADAPTEC) && + (pci_get_device(dev) == ILINK_DEVICE_AIC5800)) { + device_set_desc(dev, "Adaptec AIC-5800"); + return 0; + } + + return ENXIO; + } + #endif /* __FreeBSD__ */ + + static int + ilink_attach( device_t dev) + { + struct ilink_softc *sc = device_get_softc(dev); + int unit = device_get_unit(dev); + int error = 0; + struct ifnet *ifp; + volatile u_int32_t cmd, latency, cache_line, fun; + u_int ch; + int rid; + #ifdef __FreeBSD__ + + ifp = (struct ifnet *)&sc->fc.ac; + + callout_handle_init(&sc->fc.stat_ch); + + cmd = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); + cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWIEN ; + pci_write_config(dev, PCI_COMMAND_STATUS_REG, cmd, 4); + + latency = pci_read_config(dev, PCIR_LATTIMER, 1); + #define DEF_LATENCY 200 /* Derived from Max Bulk Transfer size 512 Bytes */ + if( latency < DEF_LATENCY ) { + latency = DEF_LATENCY; + printf("pciilink%d: PCI bus latency was changing to", unit); + pci_write_config(dev, PCIR_LATTIMER, latency, 1); + } else { + printf("pcilynx%d: PCI bus latency is", unit); + } + printf(" %d.\n", (int) latency); + + #define DEF_CACHE_LINE 0x10 + cache_line = DEF_CACHE_LINE; + pci_write_config(dev, PCIR_CACHELNSZ, cache_line, 1); + + rid = PCI_MAP_REG_START; + sc->fc.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE); + if (!sc->fc.mem) { + device_printf(dev, "could not map memory\n"); + error = ENXIO; + goto fail; + } + sc->base = rman_get_virtual(sc->fc.mem); /* XXX use bus_space */ + #endif /* __FreeBSD__ */ + + sc->fc.sid_buf = (u_int32_t *) vm_page_alloc_contig( 1 << 11, + 0x10000, 0xffffffff, 1 << 11); + + ifp->if_flags &= ~IFF_UP; + + for( ch = 0 ; ch < ILINK_MAX_DMA_CH ; ch ++){ + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + } + + /* FLUSH FIFO and Reset Transmitter and Reciever */ + sc->base->reset = ILINK_RESET_RX | ILINK_RESET_TX + | ILINK_RESET_RF | ILINK_RESET_ITF | ILINK_RESET_ATF; + + sc->base->reset = 0; + + /* Enable PCI operation */ + sc->base->cntl |= ILINK_CNTL_CLKRUN | ILINK_CNTL_LINK; + fun = sc->base->cntl; + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + + printf("ilink%d: Link %s, %d ports.\n", unit, + linkspeed[(fun & FW_PHY_SPD) >> 6], fun & FW_PHY_NP); + + sc->flags = 0; + if ((pci_get_vendor(dev) == ILINK_VENDORID_ADAPTEC) && + (pci_get_device(dev) == ILINK_DEVICE_AIC5800)) { + sc->flags |= ILINK_ADAPTEC; + } + + sc->base->dma_ch[ARX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->reset = ILINK_RESET_RX | ILINK_RESET_RF ; + + ilink_busreset(sc); + sc->base->retry = ILINK_DEF_RETRY; + + /* Attach PCL to dma channel */ + sc->fc.dv_flags = 0; + ilink_db_init(sc); + + ifp->if_softc = sc; + ifp->if_name = "ilink"; + ifp->if_unit = unit; + ifp->if_mtu = 1500; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; + ifp->if_ioctl = ilink_ioctl; + ifp->if_output = fw_output; + ifp->if_type = IFT_IEEE1394; + ifp->if_start = ilink_start; + ifp->if_init = (if_init_f_t *)ilink_init; + ifp->if_addrlen = 0; + ifp->if_hdrlen = 0; + ifp->if_snd.ifq_maxlen = 2000; + sc->fc.dv_gap = 3 << 12; /* Value from empirical */ + sc->fc.dv_write_proc = 0; + sc->fc.dv_read_proc = 0; + sc->fc.fw_busreset = ilink_busreset; + sc->fc.p_cycle_timer = &sc->base->cycle_timer; + + bzero(&sc->fc.ac.media.firewire.eui64, 8); + + /* establish interrupt */ + rid = 0; + sc->fc.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (sc->fc.irq == NULL) { + device_printf(dev, "could not map interrupt\n"); + error = ENXIO; + goto fail; + } + + error = bus_setup_intr(dev, sc->fc.irq, INTR_TYPE_NET, + ilink_intr, sc, &sc->fc.ih); + if (error) { + device_printf(dev, "could not setup irq\n"); + goto fail; + } + + ilink_init(sc); + + if_attach(ifp); + + if( sc->base->node & ILINK_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCTIMER); + sc->base->cntl |= ILINK_CNTL_CYCMTR; + sc->base->cntl |= ILINK_CNTL_CYCTIMER; + } else{ + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCTIMER); + sc->base->cntl |= ILINK_CNTL_CYCTIMER; + } + sc->fc.txdv = ilink_start_txdv; + sc->fc.rxdv = ilink_start_rxdv; + sc->fc.txstop = NULL; + sc->fc.rxstop = ilink_stop_rxdv; + fwiso_attach(dev, &fwiso_cdevsw); + + bpfattach(ifp, DLT_NULL, sizeof(struct fwhdr)); + /* Initiate Busreset */ + ilink_ibr(sc); + return error; + fail: + return error; + } + static void ilink_start(ifp) + register struct ifnet *ifp; + { + struct mbuf *m, *mb_head; + struct ifqueue *ifq = &ifp->if_snd; + struct ilink_softc *sc = (struct ilink_softc *)ifp->if_softc; + struct ilinkdb_tr *tx, *last; + struct ilinkdb_tr *asystart = NULL; + struct ilinkdb_tr *isostart = NULL; + int s, segment; + int ch; + u_int32_t isocntl = 0; + u_int32_t proto; + struct fwhdr *ld; + + /* + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + */ + if(sc->queued[ATX_CH] > 0 ){ + asystart = sc->db_last[ATX_CH]->next; + } + if(sc->queued[ITX_CH] > 0 ){ + isostart = sc->db_last[ITX_CH]->next; + } + if( asystart != NULL || isostart != NULL ){ + goto kick; + } + sc->base->dma_ch[ATX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->dma_ch[ITX_CH].cntl = ILINK_CNTL_DMA_STOP; + txloop: + s = splimp(); + IF_DEQUEUE(ifq, mb_head); + if (mb_head == NULL){ + splx(s); + goto kick; /* EMPTY: >>> exit here <<< */ + return; + } + splx(s); + + #if defined(__FreeBSD__) + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer to it). + */ + struct mbuf m1; + u_int af = AF_UNSPEC; + + m1.m_next = mb_head; + m1.m_len = 4; + m1.m_data = (char *)⁡ + + bpf_mtap(ifp, &m1); + } + #endif + + ifp->if_opackets++; + ld = (struct fwhdr *)mtod(mb_head, vm_offset_t); + proto = ld->cntl[0]; + /* + if(proto == PROTO_N1394ASYST){ + proto = PROTO_N1394ISOST; + } + */ + if(proto == PROTO_N1394ASYRQ){ + u_int32_t dst; + + m_adj(mb_head, sizeof(fwcntl)); + + ch = ATX_CH; + dst = ld->data[0] & htonl(0xffff0000); + ld->data[1] &= htonl(0x0000ffff); + ld->data[1] |= dst; + ld->data[0] &= htonl(0x0000ffff); + if(sc->flags & ILINK_ASYFIRST) { + sc->flags &= ~ILINK_ASYFIRST; + ld->data[0] |= htonl(ILINK_INIT_SNDBUF); + } + }else if(proto == PROTO_N1394ISOST){ + m_adj(mb_head, sizeof(fwcntl)); + ch = ITX_CH; + /* Obtain iso. channel No. and store control register */ + isocntl = (ntohl(ld->data[0]) & 0x0000ff00) << 16; + if(sc->flags & ILINK_ADAPTEC) isocntl |= 0x30; + }else if(proto == PROTO_N1394ASYST){ + /* re-use control information space for CRC data, when asy. stream */ + u_int32_t *ald; + ald = mtod(mb_head, u_int32_t *); + ald[sizeof(fwcntl)/4 - 2] = htonl(ILINK_PKTROW); + ald[sizeof(fwcntl)/4 - 1] = ld->data[0]; + ald[sizeof(fwcntl)/4] + = htonl(crcfw(mb_head, 1, sizeof(fwcntl)/4 - 1)); + m = mb_head; + ch = ATX_CH; + while(m->m_next) + m = m->m_next; + if(M_TRAILINGSPACE(m) < 4 ){ + /* APPEND one more mbuf, if required */ + MGET(m, M_DONTWAIT, MT_DATA); + if( m == NULL){ + m_freem(mb_head); + goto kick; + } + ald = mtod(m, u_int32_t *); + ald[0] = htonl(crcfw(mb_head, 0, sizeof(fwcntl)/4+1)); + m->m_len = 4; + m_cat(mb_head, m); + }else{ + ald = mtod(m, u_int32_t *); + ald[(m->m_len + 3)/4] = + htonl(crcfw(mb_head, 0, sizeof(fwcntl)/4+1)); + mb_head->m_pkthdr.len += 4; + m->m_len += 4; + } + + if((sizeof(fwcntl) - 8) > 0) + m_adj(mb_head, sizeof(fwcntl) - 8); + + if(sc->flags & ILINK_ASYFIRST) { + sc->flags &= ~ILINK_ASYFIRST; + ld->data[0] |= htonl(ILINK_INIT_SNDBUF); + } + }else{ + goto txloop; + } + + last = sc->db_last[ch]; + tx = sc->db_last[ch]->next; + + if(proto == PROTO_N1394ISOST){ + isostart = last->next; + }else{ + asystart = last->next; + } + tbdinit: + if(proto == PROTO_N1394ISOST){ + tx->db->unit[0].db_cmd = ILINK_STORE_QUAD | ILINK_KEY_SYS | 4; + tx->db->unit[0].db_addr + = vtophys(&sc->base->iso_cntl[ITX_CH - 2].conf); + tx->db->unit[0].db_depend = isocntl; + m_adj(mb_head, 4); /* chop ISO hdr */ + }else{ + tx->db->unit[0].db_cmd = ILINK_NOP; + } + + for (m = mb_head, segment = 1; m != NULL; m = m->m_next) { + if (m->m_len != 0) { + if (segment >= ILINKDBBUF ) + break; + tx->db->unit[segment].db_addr + = vtophys(mtod(m, vm_offset_t)); + tx->db->unit[segment].db_cmd + = ILINK_OUTPUT_MORE | ( m->m_len & 0xffff); + segment++; + } + } + /* Number of fragmentation exceed MAX DB buffer */ + if(m != NULL){ + struct mbuf *mn; + MGETHDR(mn, M_DONTWAIT, MT_DATA); + if (mn == NULL) { + m_freem(mb_head); + goto kick; + return; + } + if (mb_head->m_pkthdr.len > MHLEN) { + MCLGET(mn, M_DONTWAIT); + if ((mn->m_flags & M_EXT) == 0) { + m_freem(mn); + m_freem(mb_head); + goto kick; + return; + } + } + m_copydata(mb_head, 0, mb_head->m_pkthdr.len, + mtod(mn, caddr_t)); + mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; + m_freem(mb_head); + mb_head = mn; + goto tbdinit; + } + + tx->mbhead = mb_head; + tx->db->unit[segment - 1].db_cmd + |= ILINK_OUTPUT_LAST; + if(proto == PROTO_N1394ISOST){ + tx->db->unit[segment].db_depend = vtophys(tx->next->db->unit); + tx->db->unit[segment].db_cmd = ILINK_NOP | + ILINK_INTERRUPT_ALWAYS | ILINK_BRANCH_ALWAYS; + tx->next->db->unit[0].db_cmd = ILINK_STOP; + sc->base->int_mask |= ILINK_INT_DMA_ITA; + }else if(proto == PROTO_N1394ASYRQ){ + sc->base->dma_ch[ATX_CH].branch = 0x00100010; + tx->db->unit[segment - 1].db_depend = vtophys(tx->db->unit); + tx->db->unit[segment - 1].db_cmd |= ILINK_BRANCH_TRUE; + tx->db->unit[segment].db_depend = vtophys(tx->next->db->unit); + tx->db->unit[segment].db_cmd = ILINK_NOP | + ILINK_INTERRUPT_ALWAYS | ILINK_BRANCH_ALWAYS; + tx->next->db->unit[0].db_cmd = ILINK_STOP; + sc->base->int_mask |= ILINK_INT_DMA_AT; + }else if(proto == PROTO_N1394ASYST){ + tx->db->unit[segment].db_depend = vtophys(tx->next->db->unit); + tx->db->unit[segment].db_cmd = ILINK_NOP | + ILINK_INTERRUPT_ALWAYS | ILINK_BRANCH_ALWAYS; + tx->next->db->unit[0].db_cmd = ILINK_STOP; + sc->base->int_mask |= ILINK_INT_DMA_AT; + }else{ + m_freem(mb_head); + goto txloop; + } + s = splimp(); + sc->queued[ch] ++; + splx(s); + sc->db_last[ch] = tx; + + if(sc->queued[ch] > sc->ndb[ch] ){ + goto txloop; + } + kick: + if( asystart != NULL){ + /* kick asy q */ + if(!(sc->base->dma_ch[ATX_CH].stat & ILINK_CNTL_DMA_RUNNING)){ + sc->base->dma_ch[ATX_CH].cmd = vtophys(asystart->db); + sc->base->dma_ch[ATX_CH].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + } + } + if( isostart !=NULL){ + /* kick iso q */ + if(!(sc->base->dma_ch[ITX_CH].stat & ILINK_CNTL_DMA_RUNNING)){ + sc->base->dma_ch[ITX_CH].cmd = vtophys(isostart->db); + sc->base->dma_ch[ITX_CH].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + } + } + } + static void ilink_dv_init(sc) + register struct ilink_softc *sc; + { + int idb; + int iseq; + int idv; + struct ilinkdb *db; + vm_offset_t buf_base; + u_int32_t *addr; + u_int32_t *ld; + + sc->fc.dv_buf_size = + sizeof(struct dv_data) + 2 * 16 * S100_SZ * (DVBUF + 1); + sc->fc.dv_buf = + (struct dv_data *)vm_page_alloc_contig( sc->fc.dv_buf_size, + 0x100000, 0xffffffff, PAGE_SIZE); + if(sc->fc.dv_buf == NULL){ + /* XXX: if failed, the allocated memory should be released. */ + printf("Phisical memory is exhoused\n"); + sc->fc.dv_flags &= ~FW_DVINIT; + return; + } + buf_base = (vm_offset_t)sc->fc.dv_buf + sizeof(struct dv_data); + for( iseq = 0, idb = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + iseq * S100_SZ * (DVBUF+1)); + sc->dbdvtx[iseq].db_tr = &sc->db_tr[DVTX_CH][idb]; + sc->fc.dv_write_buf[iseq] = &addr[S100_SZ/4]; + /* first PCL is used as dummy */ + for( idv = 0 ; idv < DVBUF ; idv++){ + db = sc->db_tr[DVTX_CH][idb].db; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 0 ){ + sc->dbdvtx[iseq].db = db; + sc->fc.dv_write_buf[iseq] = ld; + sc->fc.dv_buf->write_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + /* 12 means, the difference ISO hdr, hdr CRC and data CRC */ + db->unit[0].db_cmd = + ILINK_OUTPUT_LAST | + ILINK_BRANCH_ALWAYS |((S100_SZ - 12) & 0xfff); + db->unit[0].db_addr = vtophys(ld) + 4; + db->unit[0].db_depend = + vtophys(sc->db_tr[DVTX_CH][idb].next->db); + + db->unit[1].db_cmd + = ILINK_NOP + | ILINK_BRANCH_NEVER + | ILINK_INTERRUPT_ALWAYS; + + db->unit[2].db_cmd + = ILINK_STOP; + + /* 12 means, the difference ISO hdr, hdr CRC and data CRC */ + ld[0] = htonl((DV_ISOTAGCIP << 14) | + ((S100_SZ-12) << 16) | + (TCODE_STREAM << 4) ); + ld[1] = htonl((DVSIZE / 4 ) << 16); + idb++; + } + db->unit[0].db_cmd = + ILINK_OUTPUT_LAST | + ILINK_BRANCH_NEVER | + ((S100_SZ -12) & 0xfff); + + db->unit[1].db_cmd + = ILINK_NOP + | ILINK_BRANCH_NEVER + | ILINK_INTERRUPT_ALWAYS; + + db->unit[2].db_cmd + = ILINK_STOP; + + sc->dbdvtx[iseq].tail = idv; + } + for( iseq = 0, idb = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + + ( iseq + MAX_DVFRAME ) * S100_SZ * (DVBUF+1)); + sc->dbdvrx[iseq].db_tr = &sc->db_tr[DVRX_CH][idb]; + sc->fc.dv_read_buf[iseq] = &addr[S100_SZ/4]; + for( idv = 0 ; idv < DVBUF ; idv++){ + db = sc->db_tr[DVRX_CH][idb].db; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 0 ){ + sc->dbdvrx[iseq].db = db; + sc->fc.dv_read_buf[iseq] = ld; + sc->fc.dv_buf->read_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + db->unit[0].db_addr = vtophys(ld); + db->unit[0].db_cmd = ILINK_INPUT_LAST | + ILINK_BRANCH_ALWAYS | S100_SZ ; + db->unit[0].db_depend = + vtophys(sc->db_tr[DVRX_CH][idb].next->db); + + idb++; + } + db->unit[0].db_cmd |= ILINK_INTERRUPT_ALWAYS; + sc->fc.dv_buf->read_len[iseq] = idv; + } + + sc->fc.dv.wklock = 0; + sc->fc.dv.walock = -1; + + sc->fc.dv.rklock = 0; + sc->fc.dv.ralock = -1; + + sc->fc.dv.dbc = -1; + sc->fc.dv.sync = 6; + sc->fc.dv.queued = 0; + + sc->fc.dv_buf->n_write = DV_FRAME; + sc->fc.dv_buf->k_write = ~0; + sc->fc.dv_buf->a_write = 0; + + sc->fc.dv_buf->n_read = DV_FRAME; + sc->fc.dv_buf->k_read = ~0; + sc->fc.dv_buf->a_read = 0; + + sc->fc.dv_flags |= FW_DVINIT; + } + static void ilink_db_ch_init(sc, ch, ndb, len) + register struct ilink_softc *sc; + int ch; + int ndb, len; + { + int idb; + struct ilinkdb *db; + /* allocate DB entries and attach one to each DMA channels */ + /* PCL entry must start at 16 bytes bounary. */ + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + sc->ndb[ch] = ndb; + sc->db_tr[ch] = (struct ilinkdb_tr *) + malloc(sizeof(struct ilinkdb_tr) * ndb, + M_DEVBUF, M_NOWAIT); + + sc->db_tr[ch][0].db = (struct ilinkdb *) + vm_page_alloc_contig(sizeof(struct ilinkdb) * ndb, + 0x100000, 0xffffffff, PAGE_SIZE); + + /* Attach PCL to DMA ch. */ + db = sc->db_tr[ch][0].db; + sc->queued[ch] = 0; + for(idb = 0 ; idb < ndb ; idb++){ + sc->db_tr[ch][idb].db = &(db[idb]); + #ifndef RX_DMA + if( len > 0 ){ + sc->db_tr[ch][idb].buf = + (caddr_t)vm_page_alloc_contig( MCLBYTES, + 0x100000, 0xffffffff, PAGE_SIZE); + } + #endif + if( idb != (ndb - 1)){ + sc->db_tr[ch][idb].next + = &(sc->db_tr[ch][idb + 1]); + }else{ + sc->db_tr[ch][ndb - 1].next + = &(sc->db_tr[ch][0]); + } + } + sc->db_last[ch] = &(sc->db_tr[ch][ndb - 1]); + sc->db_first[ch] = &(sc->db_tr[ch][ndb - 1]); + } + static void ilink_db_init(sc) + register struct ilink_softc *sc; + { + int ch; + /* Stop DMA process before handle DB */ + for( ch = 0 ; ch < ILINK_MAX_DMA_CH ; ch ++){ + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + } + ilink_db_ch_init(sc, ARX_CH, NDB, MCLBYTES); + ilink_db_ch_init(sc, IRX_CH, NDB, MCLBYTES); + ilink_db_ch_init(sc, ATX_CH, NDB, MCLBYTES); + ilink_db_ch_init(sc, ITX_CH, NDB, MCLBYTES); + ilink_db_ch_init(sc, DVTX_CH, NDVDB, 0); + ilink_db_ch_init(sc, DVRX_CH, NDVDB, 0); + ilink_dv_init(sc); + } + #if 0 + static void ilink_rx_disable(sc, ch) + register struct ilink_softc *sc; + int ch; + { + struct ifnet *ifp = (struct ifnet *)&sc->ac; + int idb; + struct ilinkdb *db; + + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + #ifdef RX_DMA + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + /* Attach and Invalidate current PCL pointer */ + m_freem(sc->db_tr[ch][idb].mbhead); + sc->db_tr[ch][idb].mbhead = NULL; + } + #endif + } + #endif + static void ilink_rx_enable(sc, ch, ich) + register struct ilink_softc *sc; + int ch; int ich; + { + int idb; + + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + if( ch != ARX_CH ){ + sc->base->iso_cntl[ch - 2].conf = ((u_int32_t)(ich)) << 24; + sc->base->iso_cntl[ch - 2].conf |= 0x100; + if(sc->flags & ILINK_ADAPTEC) + sc->base->iso_cntl[ch - 2].conf |= 0x30; + sc->isohdr[ch] = htonl((ich << 8) | (TCODE_STREAM << 4 )); + } + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + #ifdef RX_DMA + ilink_add_rx_buf(&(sc->db_tr[ch][idb]), 0); + #else + ilink_forward_rx_buf(&(sc->db_tr[ch][idb])); + #endif + if( idb != (sc->ndb[ch] - 1) ){ + sc->db_tr[ch][idb].db->unit[0].db_depend + = vtophys(sc->db_tr[ch][idb + 1].db); + }else{ + sc->db_tr[ch][idb].db->unit[0].db_depend + = vtophys(sc->db_tr[ch][0].db); + } + } + + sc->db_last[ch] = &(sc->db_tr[ch][sc->ndb[ch] - 1]); + sc->db_last[ch]->next->db->unit[0].db_cmd + = ILINK_INPUT_LAST | ILINK_INTERRUPT_ALWAYS + | ILINK_BRANCH_ALWAYS | MCLBYTES; + sc->base->dma_ch[ch].cmd + = (ilinkreg_t) vtophys(sc->db_tr[ch][0].db); + } + static void ilink_tx_init(sc, ch) + register struct ilink_softc *sc; + int ch; + { + int idb; + for( idb = 0 ; idb < sc->ndb[ch] ; idb ++){ + sc->db_tr[ch][idb].mbhead = NULL; + } + return; + } + static void ilink_init(sc) + register struct ilink_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + if_fwinit(&sc->fc); + ifp->if_flags &= ~IFF_RUNNING; + sc->base->int_mask = 0x0; + sc->base->int_clear = ~0; + + sc->base->node &= 0xffff003f; + + sc->base->reset = ILINK_RESET_RX | ILINK_RESET_TX + | ILINK_RESET_RF | ILINK_RESET_ITF | ILINK_RESET_ATF; + sc->base->reset = 0; + + ilink_rx_enable(sc, ARX_CH, 0); + sc->base->p_cntl |= (1<<5); + + ilink_tx_init(sc, ATX_CH); + sc->base->iso_cntl[0].event_cyc = 0xffffffff; + sc->base->iso_cntl[1].event_cyc = 0xffffffff; + sc->base->iso_cntl[2].event_cyc = 0xffffffff; + sc->base->iso_cntl[3].event_cyc = 0xffffffff; + sc->base->retry = ILINK_DEF_RETRY; + sc->base->int_mask |= 0xff800000 | 0x00000f00 + | ILINK_INT_DMA_AT | ILINK_INT_DMA_AR + | ILINK_INT_PHY_BUS_R + | ILINK_INT_AT_BAD + | ILINK_INT_SENT_REJ | ILINK_INT_HDR_ERR + | ILINK_INT_T_CODE_ERR | ILINK_INT_CYC_LONG ; + sc->base->dma_ch[ARX_CH].cntl |= + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_WAKEUP; + + ifp->if_flags |= IFF_RUNNING; + return; + } + static int ilink_shutdown(device_t dev) + { + u_int ch; + struct ilink_softc *sc = device_get_softc(dev); + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + + ifp->if_flags &= ~IFF_UP; + + printf("shutdown\n"); + + /* Stop all DMA operation immediately */ + for( ch = 0 ; ch < ILINK_MAX_DMA_CH ; ch ++){ + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + } + + /* FLUSH FIFO and Reset Transmitter and Reciever */ + sc->base->reset = ILINK_RESET_RX | ILINK_RESET_TX + | ILINK_RESET_RF | ILINK_RESET_ITF | ILINK_RESET_ATF; + sc->base->reset = 0; + + return 0; + } + static void + ilink_intr( void *arg ) + { + struct ilink_softc *sc = (struct ilink_softc *)arg; + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + u_int32_t csr; + #if 0 + while(csr = sc->base->pci_int_stat) + #else + csr = sc->base->int_stat; + #endif + { + /* Release Pending state to avoid loop condition */ + sc->base->int_clear = 0xfffffffful; + + #ifdef ILINK_DEBUG + printf("ilink%d INTERRUPT <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x\n", + ILINKARGS(sc), + csr & ILINK_INT_DMA_AT ? "DMA_AT ":"", + csr & ILINK_INT_DMA_AR ? "DMA_AR " :"", + csr & ILINK_INT_DMA_ITA ? "DMA_ITA ":"", + csr & ILINK_INT_DMA_ITB ? "DMA_ITB " :"", + csr & ILINK_INT_DMA_IRA ? "DMA_IRA ":"", + csr & ILINK_INT_DMA_IRB ? "DMA_IRB " :"", + csr & ILINK_INT_CYC_EVTA ? "CYC_ITA ":"", + csr & ILINK_INT_CYC_EVTB ? "CYC_ITB ":"", + csr & ILINK_INT_CYC_EVRA ? "CYC_IRA ":"", + csr & ILINK_INT_CYC_EVRB ? "CYC_IRB ":"", + csr & ILINK_INT_PHY_BUS_R ? "BUS_RESET ":"", + csr & ILINK_INT_PHY_RCV_R ? "RCV_RESET ":"", + csr & ILINK_INT_PHY_INT ? "PHY_INT ":"", + csr & ILINK_INT_RCV_INT ? "RCV_DATA ":"", + csr & ILINK_INT_TX_RDY ? "TX_RDY ":"", + csr & ILINK_INT_CYC_START ? "CYC_START ":"", + csr & ILINK_INT_CYC_SECOND ? "CYC_SECOND ":"", + csr & ILINK_INT_CYC_LOST ? "CYC_LOST ":"", + csr & ILINK_INT_AT_BAD ? "AT_BAD ":"", + csr & ILINK_INT_SENT_REJ ? "SENT_REJ ":"", + csr & ILINK_INT_HDR_ERR ? "HDR_ERR ":"", + csr & ILINK_INT_T_CODE_ERR ? "T_CODE_ERR ":"", + csr & ILINK_INT_PRQU_ERR ? "PRQU_ERR ":"", + csr & ILINK_INT_PWQU_ERR ? "PWQU_ERR ":"", + csr & ILINK_INT_RS_ERR ? "RS_ERR ":"", + csr & ILINK_INT_RS_DONE ? "RS_DONE ":"", + csr & ILINK_INT_PS_OUT ? "PS_OUT ":"", + csr & ILINK_INT_CYC_LONG ? "CYC_LONG ":"", + csr & ILINK_INT_PHY_REG ? "PHY_REG ":"", + csr & ILINK_INT_IT_BAD ? "IT_BAD ":"", + csr + ); + #endif + if(csr & ILINK_INT_PHY_BUS_R ){ + /* disable cycle master */ + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCTIMER); + ilink_busreset(sc); + + if( sc->base->node & ILINK_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCTIMER); + sc->base->cntl |= ILINK_CNTL_CYCMTR ; + sc->base->cntl |= ILINK_CNTL_CYCTIMER ; + }else{ + printf("This host is not CYCLEMASTER\n"); + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCTIMER); + sc->base->cntl |= ILINK_CNTL_CYCTIMER ; + } + sc->base->reset = + ILINK_RESET_TX | ILINK_RESET_ITF | ILINK_RESET_ATF; + sc->base->reset = 0; + DELAY(200); + + if( ifp->if_flags & IFF_RUNNING ) + sc->base->dma_ch[ARX_CH].cntl |= + (ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_WAKEUP); + } + + if(csr & ILINK_INT_SENT_REJ ){ + printf("Receive FIFO overflow\n"); + sc->base->int_mask &= ~ILINK_INT_SENT_REJ; + ILINK_RESET_TX | ILINK_RESET_ITF | ILINK_RESET_ATF; + sc->base->dma_ch[DVRX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->dma_ch[IRX_CH].cntl = ILINK_CNTL_DMA_STOP; + } + if((csr & ILINK_INT_DMA_IRA )){ + ilink_rcv(sc, IRX_CH); + } + if((csr & ILINK_INT_DMA_IRB )){ + u_int k_read = (sc->fc.dv_buf->k_read + 1) % 16; + u_int32_t *read_buf; + read_buf = (u_int32_t *) ((u_int32_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + while((*read_buf & htonl(0xf0)) != htonl(0xf0)){ + *read_buf |= htonl(0xf0); + k_read = (k_read + 1) % 16; + read_buf = (u_int32_t *) ((u_int32_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + } + sc->fc.dv_buf->k_read = k_read; + /* if signal is registered, raise up signal */ + if( sc->fc.dv_read_proc != 0 && + !(sc->fc.read_signal & ILINK_READ_SIGMASK)){ + psignal(sc->fc.dv_read_proc, sc->fc.read_signal ); + } + } + if((csr & ILINK_INT_DMA_AR )){ + ilink_rcv(sc, ARX_CH); + } + if((csr & ILINK_INT_DMA_AT )){ + #if 0 + dump_dma(sc, ATX_CH); + dump_db(sc, ATX_CH); + #endif + ilink_txd(sc, ATX_CH); + if (ifp->if_snd.ifq_head != NULL){ + ilink_start(ifp); + } + } + if((csr & ILINK_INT_AT_BAD )){ + dump_dma(sc, ATX_CH); + dump_db(sc, ATX_CH); + ilink_txd(sc, ATX_CH); + if (ifp->if_snd.ifq_head != NULL){ + ilink_start(ifp); + } + } + if((csr & ILINK_INT_DMA_ITA )){ + #if 0 + dump_dma(sc, ITX_CH); + dump_db(sc, ITX_CH); + #endif + ilink_txd(sc, ITX_CH); + if (ifp->if_snd.ifq_head != NULL){ + ilink_start(ifp); + } + } + if(csr & ILINK_INT_IT_BAD ){ + dump_dma(sc, DVTX_CH); + dump_db(sc, DVTX_CH); + sc->base->dma_ch[DVTX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->fc.dv_buf->k_write = ~0; + sc->base->int_mask &= ~ILINK_INT_IT_BAD; + sc->base->int_mask &= ~ILINK_INT_DMA_ITB; + } + if(csr & ILINK_INT_DMA_ITB ){ + if(INITREG(&sc->fc, oPCR) & DV_BROADCAST_ON){ + ilink_start_txdv(sc); + }else if(sc->fc.dv_start != 0){ + ilink_start_txdv(sc); + }else{ + sc->base->int_mask &= ~ILINK_INT_DMA_ITB; + if(!(sc->base->int_mask & 0x0d)){ + sc->base->int_mask &= ~ILINK_INT_TX_RDY; + } + sc->base->dma_ch[DVTX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->fc.dv_buf->k_write = ~0; + } + if(sc->fc.dv_start == 0){ + /* if write operation is blocked, wake up it */ + if(sc->fc.dv_flags & FW_DVWRWAIT){ + wakeup((caddr_t)sc); + } + /* if signal is registered, raise up signal */ + if( sc->fc.dv_write_proc != 0 && + !(sc->fc.write_signal & ILINK_WRITE_SIGMASK)){ + psignal(sc->fc.dv_write_proc, + sc->fc.write_signal ); + } + } + } + } + return; + } + /* + * TX'd mbuf housekeeping + */ + void ilink_txd(sc, ch) + struct ilink_softc *sc; + int ch; + { + struct ilinkdb_tr *txd, *current; + int s; + /* if error, stop DMA, reset TX buffer */ + txd = sc->db_first[ch]; + while(sc->queued[ch] > 0){ + /* Buggy ?, Where, Who does care unset queueed packet */ + current = txd->next; + if(sc->base->dma_ch[ch].stat & ILINK_CNTL_DMA_DEAD ){ + #ifdef LYNX_DEBUG + dump_dma(sc, ch); + dump_db(sc, ch); + #endif + /* Stopping DMA immediately */ + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + if( ch == ATX_CH ){ + printf("resetting ATF\n"); + sc->base->reset = ILINK_RESET_ATF; + sc->base->reset = 0; + }else if( ch == ITX_CH ){ + printf("resetting ITF\n"); + sc->base->reset = ILINK_RESET_ATF; + sc->base->reset = 0; + }else{ + printf("Which ch does error occured ???\n"); + } + sc->base->dma_ch[ch].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + } + m_freem(current->mbhead); + current->mbhead = NULL; + + s = splimp(); + sc->queued[ch] --; + splx(s); + txd = current; + sc->db_first[ch] = current; + } + } + static int + ilink_ioctl( struct ifnet *ifp, u_long cmd, caddr_t data ) + { + struct ilink_softc *sc = ifp->if_softc; + struct arpcom *ac = (struct arpcom *)ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *) data; + struct fwintreq *fwintr = (struct fwintreq *) data; + u_int32_t *npm = (u_int32_t *)data; + int err = 0; + u_int fun; + u_int32_t ch; + switch (cmd){ + case SIOCSIFADDR: + if(sc->flags & ILINK_ISORA){ + err = EBUSY; + return err; + } + sc->flags |= ILINK_ISORA; + + sc->base->dma_ch[IRX_CH].cntl = ILINK_CNTL_DMA_STOP; + ilink_rx_enable(sc, + IRX_CH, ac->media.firewire.broadcast ); + sc->base->int_mask |= ILINK_INT_DMA_IRA; + sc->base->dma_ch[IRX_CH].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + if(!(sc->fc.fw_flags & FWIP_UP)){ + firewire_ifinit(ac, ifa); + } + ifp->if_flags |= IFF_UP ; + sc->fc.fw_flags |= FWIP_UP; + break; + case SIOCSNPM: /* Set Network Protocol Manager ID, internal use only */ + ch = (fw_setbmslot(ifp, *npm & 0xff)) & 0x3f; + break; + case SIOCRDCSR: /* Read initial register area */ + fwintr->req.mem.data = + read_reg(&sc->fc, fwintr->req.mem.addr); + break; + case SIOCGETTLABEL: /* Lock a transaction label */ + fwintr->req.pcbreq.data = + fw_get_tlabel(ifp, TLABEL_PCB, fwintr->req.pcbreq.pcb); + break; + case SIOCRELTLABEL: /* Release transaction label */ + break; + /* Bind Iso. socket to isochronous channel for reception */ + case SIOCISOENA: + if(fwintr->req.pcbreq.data >= 0x100 ){ + err = EINVAL; + return err; + } + if(sc->flags & ILINK_ISORA){ + err = EBUSY; + return err; + } + if( sc->fc.isoslot[fwintr->req.pcbreq.data].type + != ISOSLOT_NULL){ + err = EBUSY; + return err; + } + ifp->if_flags |= IFF_UP ; + sc->flags |= ILINK_ISORA; + + sc->base->dma_ch[IRX_CH].cntl = ILINK_CNTL_DMA_STOP; + ilink_rx_enable(sc, IRX_CH, fwintr->req.pcbreq.data ); + + sc->base->int_mask |= ILINK_INT_DMA_IRA; + sc->base->dma_ch[IRX_CH].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + sc->fc.isoslot[fwintr->req.pcbreq.data].type = ISOSLOT_PCB; + sc->fc.isoslot[fwintr->req.pcbreq.data].resp.pcb = fwintr->req.pcbreq.pcb; + break; + case SIOCISODIS: /* Release Iso. socket */ + if(fwintr->req.pcbreq.data >= 0x100 ){ + err = EINVAL; + return err; + } + sc->fc.isoslot[fwintr->req.pcbreq.data].type = ISOSLOT_NULL; + sc->flags &= ~ILINK_ISORA; + sc->base->dma_ch[IRX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->int_mask &= ~ILINK_INT_DMA_IRA; + break; + case SIOCFWRESET: /* Initiate BUS reset */ + ilink_ibr(sc); + break; + case SIOCDEBUGPHY: /* Read PHY register */ + if( fwintr->req.mem.addr < 8){ + fun = tsb21lv_rddata(&sc->base->phy_access, + fwintr->req.mem.addr); + fwintr->req.mem.data = fun; + }else{ + err = EINVAL; + } + break; + case DUMPDMA: + if(fwintr->req.ch <= ILINK_MAX_DMA_CH ){ + dump_dma(sc, fwintr->req.ch); + dump_db(sc, fwintr->req.ch); + }else{ + err = EINVAL; + } + break; + case SIOCFWWRREG: + if(fwintr->req.mem.addr <= 0x200){ + ilinkreg_t *reg; + reg = (ilinkreg_t *)sc->base; + reg[fwintr->req.mem.addr/4] + = fwintr->req.mem.data; + fwintr->req.mem.data + = reg[fwintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + case SIOCFWRDREG: + if(fwintr->req.mem.addr < 0x200){ + ilinkreg_t *reg; + reg = (ilinkreg_t *)sc->base; + fwintr->req.mem.data = reg[fwintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + default: + err = EINVAL; + } + return err; + } + static void dump_dma(struct ilink_softc *sc, int ch){ + ilinkreg_t stat = sc->base->dma_ch[ch].stat; + + printf("ilink%d dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x \n", + ILINKARGS(sc), + ch, + sc->base->dma_ch[ch].cntl, + stat, + sc->base->dma_ch[ch].cmd, + sc->base->dma_ch[ch].interrupt, + sc->base->dma_ch[ch].branch, + sc->base->dma_ch[ch].wait); + stat &= 0xffff ; + if(stat & 0xff00){ + printf("ilink%d dma %d ch:%s%s%s%s%s%s%s %s(%x)\n", + ILINKARGS(sc), + ch, + stat & ILINK_CNTL_DMA_RUNNING ? "RUN," : "", + stat & ILINK_CNTL_DMA_WAKE ? "WAKE," : "", + stat & ILINK_CNTL_DMA_DEAD ? "DEAD," : "", + stat & ILINK_CNTL_DMA_ACTIVE ? "ACTIVE," : "", + stat & ILINK_CNTL_DMA_BT ? "BRANCH," : "", + stat & ILINK_CNTL_DMA_BAD ? "BADDMA," : "", + stat & ILINK_CNTL_DMA_RETRY ? "RETRY," : "", + ackcode[(stat & 0xf) * 2], + stat & 0xf + ); + }else{ + printf("ilink%d dma %d ch: Nostat\n", + ILINKARGS(sc), ch); + } + } + void dump_db(struct ilink_softc *sc, int ch){ + struct ilinkdb_tr *db_tr; + struct ilinkdb *curr = NULL, *prev; + int idb, jdb; + db_tr = sc->db_tr[ch]; + + prev = db_tr[sc->ndb[ch] - 1].db; + for(idb = 0 ; idb < sc->ndb[ch] ; idb ++ ){ + for(jdb = 0 ; jdb <= ILINKDBBUF ; jdb ++ ){ + if((sc->base->dma_ch[ch].cmd & 0xfffffff0) == + vtophys(&(db_tr[idb].db->unit[jdb]))){ + curr = db_tr[idb].db; + goto outdb; + } + prev = db_tr[idb].db; + } + } + outdb: + if( curr != NULL){ + printf("Previous DB\n"); + print_db(prev, ch); + printf("Current DB\n"); + print_db(curr, ch); + }else{ + printf("dbdump err ch = %d cmd = 0x%08x\n", + ch, sc->base->dma_ch[ch].cmd); + } + return; + } + static void print_db(struct ilinkdb *db, int ch){ + ilinkreg_t stat; + int i; + + printf("ch = %d\n%8s %s %s %s %s %s %4s %8s %8s %8s\n", + ch, + "Current", + "OP ", + "KEY", + "INT", + "BR ", + "WT ", + "bytes", + "Addr", + "Depend", + "Status"); + for( i = 0 ; i <= ILINKDBBUF ; i ++){ + printf("%08x %s %s %s %s %s %5d %08x %08x %08x", + vtophys(&db->unit[i]), + dbcode[(db->unit[i].db_cmd >> 28) & 0xf], + dbkey[(db->unit[i].db_cmd >> 24) & 0x7], + dbcond[(db->unit[i].db_cmd >> 20) & 0x3], + dbcond[(db->unit[i].db_cmd >> 18) & 0x3], + dbcond[(db->unit[i].db_cmd >> 16) & 0x3], + db->unit[i].db_cmd & 0xffff, + db->unit[i].db_addr, + db->unit[i].db_depend, + db->unit[i].db_status); + stat = db->unit[i].db_status >> 16 ; + if(stat & 0xff00){ + printf(" %s%s%s%s%s%s%s %s(%x)\n", + stat & ILINK_CNTL_DMA_RUNNING ? "RU," : "", + stat & ILINK_CNTL_DMA_WAKE ? "WA," : "", + stat & ILINK_CNTL_DMA_DEAD ? "DE," : "", + stat & ILINK_CNTL_DMA_ACTIVE ? "AC," : "", + stat & ILINK_CNTL_DMA_BT ? "BR," : "", + stat & ILINK_CNTL_DMA_BAD ? "BA," : "", + stat & ILINK_CNTL_DMA_RETRY ? "RE," : "", + ackcode[(stat & 0xf) * 2], + stat & 0xf + ); + }else{ + printf(" Nostat\n"); + } + if(((db->unit[i].db_cmd >> 28) & 0xf ) == 7){ + return; + } + if(((db->unit[i].db_cmd >> 18) & 0x3 ) == 3){ + return; + } + } + return; + } + static void ilink_ibr(sc) + struct ilink_softc *sc; + { + u_int32_t fun; + /* Bus reset should be initiated and processed only by PHY chip set */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_IBR_REG); + fun |= FW_PHY_IBR; + fun = tsb21lv_wrdata(&sc->base->phy_access, FW_PHY_IBR_REG, fun); + } + void ilink_stop_rxdv(sc) + struct ilink_softc *sc; + { + sc->base->dma_ch[DVRX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->int_mask &= ~ILINK_INT_DMA_IRB; + } + void ilink_start_rxdv(sc) + struct ilink_softc *sc; + { + int ch; + ch = (INITREG(&sc->fc, iPCR) >> 16) & 0x3f; + if((sc->base->iso_cntl[IRX_CH - 2].conf >> 24 & 0xff) == ch ){ + if(sc->base->int_mask & ILINK_INT_DMA_IRA){ + return; + } + sc->base->iso_cntl[IRX_CH - 2].conf = 0; + } + if( sc->fc.dv.rklock ) return; /* avoid duplication */ + sc->fc.dv.rklock = 1; + + sc->base->dma_ch[DVRX_CH].cntl = ILINK_CNTL_DMA_STOP; + sc->base->iso_cntl[DVRX_CH - 2].conf = ((u_int32_t)(ch)) << 24; + sc->base->iso_cntl[DVRX_CH - 2].conf |= 0x100; + if(sc->flags & ILINK_ADAPTEC) + sc->base->iso_cntl[DVRX_CH - 2].conf |= 0x30; + + sc->base->int_mask |= ILINK_INT_DMA_IRB; + + sc->base->dma_ch[DVRX_CH].cmd = vtophys(sc->dbdvrx[0].db); + sc->base->dma_ch[DVRX_CH].cntl = + ILINK_CNTL_DMA_RUN | ILINK_CNTL_DMA_CLR; + + sc->fc.dv.rklock = 0; + } + static void ilink_start_txdv(sc) + struct ilink_softc *sc; + { + struct fw_softc *fc = &(sc->fc); + u_int i, i_cnt, size; + u_int32_t *ld; + u_int ch, seq, len, iseq; + u_int32_t cyc; + struct dv_data *dv_buf; + + if( sc->fc.dv.wklock ) return; /* avoid duplicate transmission */ + sc->fc.dv.wklock = 1; + + sc->base->int_mask |= ILINK_INT_DMA_ITB ; + + dv_buf = fc->dv_buf; + if( fc->dv_start == 0 ){ + /* attempt to get next frame */ + dv_buf->k_write + = (dv_buf->k_write + 1) % dv_buf->n_write; + if(dv_buf->k_write == dv_buf->a_write){ + dv_buf->k_write = + (dv_buf->k_write + dv_buf->n_write - 1) + % dv_buf->n_write; + } + } + iseq = sc->fc.dv_buf->k_write; + + ch = (INITREG(&sc->fc, oMPR) >> 24) & 0x3f; + len = sc->fc.dv_buf->write_len[iseq]; + if( len > (DVBUF - 1)){ + INITREG(&sc->fc, oPCR) &= ~DV_BROADCAST_ON; + sc->fc.dv.queued = 0; + sc->base->dma_ch[DVTX_CH].cntl = ILINK_CNTL_DMA_STOP; + goto out; + } + + if( fc->dv_end == 0){ + fc->dv_end = len; + } + if( fc->dv_end > len ){ + fc->dv_end = len; + } + if( fc->dv_start > fc->dv_end ){ + fc->dv_start = 0; + } + ld = &(sc->fc.dv_write_buf[iseq][fc->dv_start * S100_SZ/4]); + for( i = fc->dv_start ; i < fc->dv_end ; i++){ + + size = ntohl(ld[0]) >> 16; + if(size >= S100_SZ - 12 ) size = S100_SZ - 12; + if( size < 8 ) size = 8; + ld[0] = htonl((DV_ISOTAGCIP << 14) | + (TCODE_STREAM << 4)| size << 16 | (ch << 8)); + ld[1] = htonl((((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f) << 24) | + ((DVSIZE / 4 ) << 16) | + (fc->dv.dbc & 0xff)); + seq = (ntohl(ld[3]) >> 24 ) & 0xf; + + if( size > 8 ){ + sc->fc.dv.dbc++; + } + if( i == (fc->dv_intr - 1)){ + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_cmd + = ILINK_OUTPUT_LAST | ILINK_INTERRUPT_ALWAYS | + ILINK_BRANCH_ALWAYS | (size & 0xfff); + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_status = 0; + }else if( i < (len - 1)){ + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_cmd + = ILINK_OUTPUT_LAST | + ILINK_BRANCH_ALWAYS | (size & 0xfff); + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_status = 0; + }else{ + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_cmd + = ILINK_OUTPUT_LAST + | ILINK_BRANCH_NEVER + | (size & 0xfff); + sc->dbdvtx[iseq].db_tr[i].db->unit[0].db_status = 0; + sc->dbdvtx[iseq].db_tr[i].db->unit[1].db_status = 0; + sc->dbdvtx[iseq].db_tr[i].db->unit[2].db_status = 0; + + sc->dbdvtx[iseq].db_tr[i].db->unit[1].db_cmd + = ILINK_NOP + | ILINK_BRANCH_NEVER + | ILINK_INTERRUPT_ALWAYS; + + sc->dbdvtx[iseq].db_tr[i].db->unit[2].db_cmd + = ILINK_STOP; + } + ld += S100_SZ/4; + } + if( i < len ){ + fc->dv_start = fc->dv_intr; + fc->dv_end = 0; + goto out; + }else{ + fc->dv_start = 0; + fc->dv_end = fc->dv_intr; + } + + ld = sc->fc.dv_write_buf[iseq]; + + if(sc->base->dma_ch[DVTX_CH].stat & ILINK_CNTL_DMA_ACTIVE){ + if(sc->base->dma_ch[DVTX_CH].stat & (1 << 7)){ + sc->base->dma_ch[DVTX_CH].cntl = ILINK_CNTL_DMA_STOP ; + sc->base->reset |= ILINK_RESET_ITF; + sc->base->reset &= ~ILINK_RESET_ITF; + sc->base->dma_ch[DVTX_CH].cntl = + ILINK_CNTL_DMA_STOP | ILINK_CNTL_DMA_WAKEDOWN; + } + } + i_cnt = 0; + while(sc->base->dma_ch[DVTX_CH].stat & ILINK_CNTL_DMA_ACTIVE){ + if(i_cnt ++ > 10000000) break; + } + + cyc = *(sc->fc.p_cycle_timer) & 0x01fff000; + cyc += sc->fc.dv_gap; + ld[2] = ( ld[2] & htonl(0xffff0000)) | htonl(cyc & 0x0000ffff) ; + + if(!(sc->base->dma_ch[DVTX_CH].stat & ILINK_CNTL_DMA_ACTIVE)){ + sc->base->dma_ch[DVTX_CH].cntl = ILINK_CNTL_DMA_STOP; + + sc->base->iso_cntl[DVTX_CH - 2].conf = (ch << 24) | 0x40000000; + if(sc->flags & ILINK_ADAPTEC) + sc->base->iso_cntl[DVTX_CH - 2].conf |= 0x30; + + sc->base->dma_ch[DVTX_CH].cmd = vtophys(sc->dbdvtx[iseq].db); + sc->base->dma_ch[DVTX_CH].cntl = + ILINK_CNTL_DMA_RUN | + ILINK_CNTL_DMA_CLR | + ILINK_CNTL_DMA_WAKEUP; + }else{ + /* disable DV */ + INITREG(&sc->fc, oPCR) &= ~((0x3f<<16)|(0x0f<<10)); + INITREG(&sc->fc, oPCR) &= ~DV_BROADCAST_ON; + } + sc->fc.dv.queued--;if(sc->fc.dv.queued < 0 ) sc->fc.dv.queued = 0; + out: + sc->fc.dv.wklock = 0; + } + + static void ilink_reset(sc) + struct ilink_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + ifp->if_flags &= ~IFF_UP; + /* Not implemented yet. */ + + ifp->if_flags |= IFF_UP; + return; + } + #ifdef RX_DMA + static int ilink_add_rx_buf(db_tr, oldm) + struct ilinkdb_tr *db_tr; + struct mbuf *oldm; + { + struct mbuf *m; + struct ilinkdb *db = db_tr->db; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m != NULL) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + if (oldm == NULL) + return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + } else { + if (oldm == NULL) + return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + m->m_pkthdr.len = m->m_len = MCLBYTES; + + db_tr->mbhead = m; + db->data[0].ptr = vtophys(mtod(m, vm_offset_t)) ; + db->data[0].ptr += sizeof(fwcntl); + db->data[0].cntl = LYNX_PCL_RCV_UPDATE | LYNX_PCL_INT + | LYNX_PCL_LASTBUF | (MCLBYTES - 4); + db->db_next &= ~LYNX_DMA_PCL_EN;; + return(m == oldm); + } + #else + static int ilink_forward_rx_buf(db_tr) + struct ilinkdb_tr *db_tr; + { + struct ilinkdb *db = db_tr->db; + + db_tr->mbhead = 0; + db->unit[0].db_addr = vtophys(db_tr->buf) ; + db->unit[0].db_addr += sizeof(fwcntl); + db->unit[0].db_cmd = ILINK_INPUT_LAST | ILINK_INTERRUPT_ALWAYS + | ILINK_BRANCH_ALWAYS | MCLBYTES; + db->unit[0].db_status = 0; + + return(0); + } + #endif + + static void ilink_rcv(sc, ch) + struct ilink_softc *sc; + int ch; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + struct mbuf *m; + int idb = 0; + struct ilinkdb_tr *db_tr; + struct fwhdr *ld; + #if 0 + dump_dma(sc, ch); + dump_db(sc, ch); + #endif + rcvloop: + if((vtophys(sc->db_last[ch]->next->db) + == sc->base->dma_ch[ch].cmd ) || idb >= sc->ndb[ch]){ + return; + } + db_tr = sc->db_last[ch]->next; + + idb++; + ifp->if_ipackets++; + #ifdef RX_DMA + if((m = db_tr->mbhead) != NULL ){ + if( ilink_add_rx_buf(db_tr, m) == 0){ + #else + MGETHDR(m, M_DONTWAIT, MT_DATA); + if(m == NULL) + return; + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + ilink_forward_rx_buf(db_tr); + return; + } + if((db_tr->db->unit[0].db_status & 0xffff) != 0 ){ + m->m_pkthdr.len = m->m_len = + MCLBYTES - (db_tr->db->unit[0].db_status & 0xffff) + + sizeof(fwcntl); + }else{ + m->m_pkthdr.len = m->m_len = MCLBYTES; + } + if( ch == ARX_CH ){ + struct fwasyhdr *ld; + ld = mtod(m, struct fwasyhdr *); + #if 0 + printf("0x%08lx ", ntohl(ld->data[0])); + printf("0x%08lx ", ntohl(ld->data[1])); + printf("0x%08lx ", ntohl(ld->data[2])); + printf("0x%08lx ", ntohl(ld->data[3])); + printf("0x%08lx\n", ntohl(ld->data[4])); + #endif + bcopy(db_tr->buf, mtod(m, caddr_t), m->m_len); + }else{ + struct fwisohdr *ilh; + /* fake ISO header */ + bcopy(db_tr->buf, mtod(m, caddr_t) + 4 , m->m_len); + ilh = mtod(m, struct fwisohdr *); + ilh->data[0] = htonl((m->m_len - sizeof(fwcntl)) << 16) + | sc->isohdr[ch] ; + m->m_pkthdr.len += 4; + m->m_len += 4; + } + #endif + m->m_pkthdr.rcvif = ifp; + if (ifp->if_bpf) { + struct mbuf m0; + u_int af = AF_UNSPEC; + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } + ld = mtod(m, struct fwhdr *); + if( ch != ARX_CH ){ + ld->cntl[0] = PROTO_N1394ISOST; + fw_stream_input(ifp, m); + }else if((ntohl(ld->data[0]) & 0xf0) == 0xe0){ + m_adj(m, 4); /* chop status area */ + m_adj(m, -4); /* chop trailer */ + fw_sid_input(ifp, m); + }else{ + ld->cntl[0] = PROTO_N1394ASYRQ; + fw_asy_input(ifp, m); + } + #ifndef RX_DMA + ilink_forward_rx_buf(db_tr); + #endif + db_tr->db->unit[0].db_cmd |= (ILINK_WAIT_ALWAYS | MCLBYTES); + sc->db_last[ch]->db->unit[0].db_cmd &= ~ILINK_WAIT_ALWAYS; + sc->db_last[ch]->db->unit[0].db_cmd |= MCLBYTES; + + sc->db_last[ch] = sc->db_last[ch]->next; + goto rcvloop; + } + void ilink_busreset(sc) + struct ilink_softc *sc; + { + int ch, fun, ir, i, node, gap, spd, c, pwr, p0, p1, p2; + + sc->base->int_mask &= ~( ILINK_INT_CYC_LOST ); + + INITREG(&sc->fc, STATE_CLEAR) + = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ; + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + /* Stopping all DMA channel processing, except Async recieve */ + + for( ch = 0 ; ch < ILINK_MAX_DMA_CH ; ch ++){ + if(ch != ARX_CH) + sc->base->dma_ch[ch].cntl = ILINK_CNTL_DMA_STOP; + } + + sc->init = 0; + sc->flags |= ILINK_ASYFIRST; + + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_GC_REG); + gap = 0x3f & fun; + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + spd = (fun >> 6) & 0x3; + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P1_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p2 = 3; + }else{ + p2 = 2; + } + }else{ + p2 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P2_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p1 = 3; + }else{ + p1 = 2; + } + }else{ + p1 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P3_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p0 = 3; + }else{ + p0 = 2; + } + }else{ + p0 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_IR_REG); + ir = (fun >> 4 ) & 0x1; + c = fun & 0x1; + pwr = 0x0 & 0x07; + /* + ** Checking whether root node or not. If this I/F is root, the Cycle + ** master bit should be set. + */ + i = 0; + while((!(sc->base->node & ILINK_NODE_VALID)) && i < 10000 ){ + i++; + DELAY(100); + } + #if 0 + if( sc->base->node & ILINK_NODE_ROOT ){ + printf("This host is CYCLEMASTER\n"); + sc->base->cntl |= (ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCSRC); + sc->base->cntl &= ~ILINK_CNTL_CYCSRC; + }else{ + sc->base->cntl &= ~(ILINK_CNTL_CYCMTR | ILINK_CNTL_CYCSRC); + } + #endif + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_PHYSID_REG); + node = 0x3f & (fun >> 2); + INITREG(&sc->fc, NODE_IDS) = ( 0x3f & sc->base->node) << 16; + #if 0 + if(c){ + sc->fc.irm = (INITREG(&sc->fc, NODE_IDS) >> 16 )& 0x3f; + }else{ + sc->fc.irm = 0x3f; + } + INITREG(&sc->fc, BUS_MGR_ID) = 0x3f; + #endif + + /* Prepare topology map and generatate Self ID data itself */ + + sc->fc.sid_buf[0] = + ( 2 << 30 ) | ( node << 24 ) | 1 << 22 + | gap << 16 | spd << 14 | c << 11 | pwr << 8 + | p0 << 6 | p1 << 4 | p2 << 2 | ir << 1; + sc->fc.sid_buf[1] = ~sc->fc.sid_buf[0]; + sc->fc.sid_cnt = 1; + + if_fwbusreset(&sc->fc); + + /* Link initialization is ready */ + sc->base->cntl |= ILINK_CNTL_RX | ILINK_CNTL_TX | ILINK_CNTL_CYCTIMER; + sc->base->reset = ILINK_RESET_TX | ILINK_RESET_ITF | ILINK_RESET_ATF; + /* + sc->base->reset = ILINK_RESET_RX | ILINK_RESET_TX + | ILINK_RESET_RF | ILINK_RESET_ITF | ILINK_RESET_ATF; + */ + sc->base->reset = 0; + + INITREG(&sc->fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 ); + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + } + #endif /* !defined(__FreeBSD__) || (NILINK > 0 && NPCI > 0) */ diff -r -c -N sys44.orig/dev/firewire/ilinkreg.h sys/dev/firewire/ilinkreg.h *** sys44.orig/dev/firewire/ilinkreg.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/ilinkreg.h Tue Oct 9 21:55:18 2001 *************** *** 0 **** --- 1,276 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ilinkreg.h,v 1.1.2.1 2000/06/04 17:19:06 ikob Exp $ + * + */ + #define ILINK_VENDORID_SONY 0x104d + #define ILINK_DEVICE_CX1947 0x8009 + #define ILINK_VENDORID_ADAPTEC 0x9004 + #define ILINK_DEVICE_AIC5800 0x5800 + + #define ILINK_MAX_DMA_CH 6 + + #define ILINK_INIT_SNDBUF 1 << 19 + + #define ILINKDBBUF 20 + + typedef volatile u_int32_t ilinkreg_t; + struct ilinkdbunit { + volatile u_int32_t db_cmd; + volatile u_int32_t db_addr; + volatile u_int32_t db_depend; + volatile u_int32_t db_status; + #define ILINK_OUTPUT_MORE (0 << 28) + #define ILINK_OUTPUT_LAST (1 << 28) + #define ILINK_INPUT_MORE (2 << 28) + #define ILINK_INPUT_LAST (3 << 28) + #define ILINK_STORE_QUAD (4 << 28) + #define ILINK_LOAD_QUAD (5 << 28) + #define ILINK_NOP (6 << 28) + #define ILINK_STOP (7 << 28) + + #define ILINK_KEY_ST0 (0 << 24) + #define ILINK_KEY_ST1 (1 << 24) + #define ILINK_KEY_ST2 (2 << 24) + #define ILINK_KEY_ST3 (3 << 24) + #define ILINK_KEY_REGS (5 << 24) + #define ILINK_KEY_SYS (6 << 24) + #define ILINK_KEY_DEVICE (7 << 24) + + #define ILINK_INTERRUPT_NEVER (0 << 20) + #define ILINK_INTERRUPT_TRUE (1 << 20) + #define ILINK_INTERRUPT_FALSE (2 << 20) + #define ILINK_INTERRUPT_ALWAYS (3 << 20) + + #define ILINK_BRANCH_NEVER (0 << 18) + #define ILINK_BRANCH_TRUE (1 << 18) + #define ILINK_BRANCH_FALSE (2 << 18) + #define ILINK_BRANCH_ALWAYS (3 << 18) + + #define ILINK_WAIT_NEVER (0 << 16) + #define ILINK_WAIT_TRUE (1 << 16) + #define ILINK_WAIT_FALSE (2 << 16) + #define ILINK_WAIT_ALWAYS (3 << 16) + }; + + struct ilinkdb { + struct ilinkdbunit unit[ILINKDBBUF+1]; + }; + + struct cxd1947_registers { + struct ilink_dma{ + ilinkreg_t cntl; + + #define ILINK_CNTL_DMA_RUNNING (1 << 15) + #define ILINK_CNTL_DMA_RUN ((1 << 31) | (1 << 15)) + #define ILINK_CNTL_DMA_STOP (1 << 31) + #define ILINK_CNTL_DMA_CLR (1 << 30) + #define ILINK_CNTL_DMA_WAKE (1 << 12) + #define ILINK_CNTL_DMA_WAKEUP ((1<< 28) | (1 << 12)) + #define ILINK_CNTL_DMA_WAKEDOWN (1<< 28) + #define ILINK_CNTL_DMA_DEAD (0x1 << 11) + #define ILINK_CNTL_DMA_ACTIVE (0x1 << 10) + #define ILINK_CNTL_DMA_BT (0x1 << 8) + #define ILINK_CNTL_DMA_BAD (0x1 << 7) + #define ILINK_CNTL_DMA_RETRY (0x1 << 4) + #define ILINK_CNTL_DMA_STAT (0xff) + + ilinkreg_t stat; + ilinkreg_t dummy0; + ilinkreg_t cmd; + ilinkreg_t interrupt; + ilinkreg_t branch; + ilinkreg_t wait; + ilinkreg_t dummy1; + }; + /* 0x0, 0x4, 0x8, 0xc */ + /* 0x0, 0x4, 0x8, 0xc */ + /* 0x20, 0x24, 0x28, 0x2c */ + /* 0x30, 0x34, 0x38, 0x3c */ + /* 0x40, 0x44, 0x48, 0x4c */ + /* 0x50, 0x54, 0x58, 0x5c */ + /* 0x60, 0x64, 0x68, 0x6c */ + /* 0x70, 0x74, 0x78, 0x7c */ + struct ilink_dma dma_ch[ILINK_MAX_DMA_CH]; + /* 0x80, 0x84, 0x88, 0x8c */ + /* 0x90, 0x94, 0x98, 0x9c */ + /* 0xa0, 0xa4, 0xa8, 0xac */ + /* 0xb0, 0xb4, 0xb8, 0xbc */ + ilinkreg_t dummy3[16]; + /* 0xc0, 0xc4, 0xc8, 0xcc */ + /* 0xd0, 0xd4, 0xd8, 0xdc */ + /* 0xe0, 0xe4, 0xe8, 0xec */ + /* 0xf0, 0xf4, 0xf8, 0xfc */ + ilinkreg_t ver; /* Version No. 0x100 */ + ilinkreg_t cntl; /* Chip control 0x104 */ + ilinkreg_t node; /* Node ID 0x108 */ + #define ILINK_NODE_VALID (1 << 31) + #define ILINK_NODE_ROOT (1 << 23) + ilinkreg_t reset; /* link reset 0x10c */ + #define ILINK_RESET_RX (1 << 5) + #define ILINK_RESET_TX (1 << 4) + #define ILINK_RESET_RF (1 << 2) + #define ILINK_RESET_ITF (1 << 1) + #define ILINK_RESET_ATF (1 << 0) + ilinkreg_t p_cntl; /* packet cntl 0x110 */ + ilinkreg_t status; /* Diag. status 0x114 */ + ilinkreg_t phy_access; /* PHY cntl 0x118 */ + #define TSB21_RDDONE (1<<31) + #define TSB21_RDPHY (1<<15) + #define TSB21_WRPHY (1<<14) + #define TSB21_REGADDR 8 + #define TSB21_WRDATA 0 + #define TSB21_RDADDR 24 + #define TSB21_RDDATA 16 + ilinkreg_t retry; /* AT retries 0x11c */ + #define ILINK_DEF_RETRY 7 + ilinkreg_t ssn; /* SSN I/F 0x120 */ + ilinkreg_t cycle_timer; /* Cycle Timer 0x124 */ + ilinkreg_t dummy4[2]; + /* 0x128, 0x12c */ + struct ilink_iso{ + ilinkreg_t event_cyc; + ilinkreg_t conf; + ilinkreg_t bandwidth; + ilinkreg_t dummy; + }; + struct ilink_iso iso_cntl[4]; + /* 0x130, 0x134, 0x138, 0x13c */ + /* 0x140, 0x144, 0x148, 0x14c */ + /* 0x150, 0x154, 0x158, 0x15c */ + /* 0x160, 0x164, 0x168, 0x16c */ + ilinkreg_t rsu_enable; /* 0x170 */ + ilinkreg_t rsu_status; /* 0x174 */ + ilinkreg_t rsu_table; /* 0x178 */ + ilinkreg_t rsu_mask; /* 0x17c */ + ilinkreg_t int_stat; /* 0x180 */ + ilinkreg_t int_mask; /* 0x184 */ + ilinkreg_t int_clear; /* 0x188 */ + ilinkreg_t int_level; /* 0x18c */ + }; + + struct ilinkdb_tr{ + struct ilinkdb_tr *next; + struct mbuf *mbhead; + struct ilinkdb *db; + caddr_t buf; + caddr_t buf2; + }; + + /* + * PCILynx info structure. + */ + struct ilink_softc { + struct fw_softc fc; + volatile struct cxd1947_registers *base; + int init; + u_int32_t flags; + struct ilinkdb_tr *db_tr[ILINK_MAX_DMA_CH]; + struct ilinkdb_tr *db_first[ILINK_MAX_DMA_CH]; + struct ilinkdb_tr *db_last[ILINK_MAX_DMA_CH]; + struct { + int tail; + struct ilinkdb_tr *db_tr; + struct ilinkdb *db; + }dbdvtx[16], dbdvrx[16]; + int ndb[ILINK_MAX_DMA_CH]; + u_int32_t isohdr[ILINK_MAX_DMA_CH]; + int queued[ILINK_MAX_DMA_CH]; + int dma_ch[ILINK_MAX_DMA_CH]; + }; + + #define ILINK_CNTL_DMA_DIS (0x00 << 24) + #define ILINK_CNTL_DMA_RO (0x01 << 24) + #define ILINK_CNTL_DMA_RW (0x02 << 24) + #define ILINK_CNTL_CLKRUN (0x1 << 20) + #define ILINK_CNTL_CYCSRC (0x1 << 18) + #define ILINK_CNTL_CYCMTR (0x1 << 17) + #define ILINK_CNTL_CYCTIMER (0x1 << 16) + #define ILINK_CNTL_PWR2 (0x1 << 14) + #define ILINK_CNTL_PWR1 (0x1 << 13) + #define ILINK_CNTL_PWR0 (0x1 << 12) + #define ILINK_CNTL_STRICTISO (0x1 << 8) + #define ILINK_CNTL_PHYOFF (0x1 << 7) + #define ILINK_CNTL_PHYCONT (0x1 << 6) + #define ILINK_CNTL_PHYRESET (0x1 << 5) + #define ILINK_CNTL_LINK (0x1 << 4) + #define ILINK_CNTL_RX (0x1 << 1) + #define ILINK_CNTL_TX (0x1 << 0) + + #define ILINK_INT_DMA_AT (0x1 << 0) + #define ILINK_INT_DMA_AR (0x1 << 1) + #define ILINK_INT_DMA_ITA (0x1 << 2) + #define ILINK_INT_DMA_ITB (0x1 << 3) + #define ILINK_INT_DMA_IRA (0x1 << 4) + #define ILINK_INT_DMA_IRB (0x1 << 5) + #define ILINK_INT_CYC_EVTA (0x1 << 8) + #define ILINK_INT_CYC_EVTB (0x1 << 9) + #define ILINK_INT_CYC_EVRA (0x1 << 10) + #define ILINK_INT_CYC_EVRB (0x1 << 11) + #define ILINK_INT_PHY_BUS_R (0x1 << 12) + #define ILINK_INT_PHY_RCV_R (0x1 << 13) + #define ILINK_INT_PHY_INT (0x1 << 14) + #define ILINK_INT_RCV_INT (0x1 << 15) + #define ILINK_INT_TX_RDY (0x1 << 16) + #define ILINK_INT_CYC_START (0x1 << 17) + #define ILINK_INT_CYC_SECOND (0x1 << 18) + #define ILINK_INT_CYC_LOST (0x1 << 19) + #define ILINK_INT_AT_BAD (0x1 << 20) + #define ILINK_INT_SENT_REJ (0x1 << 21) + #define ILINK_INT_HDR_ERR (0x1 << 22) + #define ILINK_INT_T_CODE_ERR (0x1 << 23) + #define ILINK_INT_PRQU_ERR (0x1 << 24) + #define ILINK_INT_PWQU_ERR (0x1 << 25) + #define ILINK_INT_RS_ERR (0x1 << 26) + #define ILINK_INT_RS_DONE (0x1 << 27) + #define ILINK_INT_PS_OUT (0x1 << 28) + #define ILINK_INT_CYC_LONG (0x1 << 29) + #define ILINK_INT_PHY_REG (0x1 << 30) + #define ILINK_INT_IT_BAD (0x1 << 31) + + #define IP_CHANNELS 0x0234 + + #define ILINK_PKTROW 0x000000e0 + + #define ILINK_ASYFIRST 0x01 + #define ILINK_ISORA 0x02 + #define ILINK_ISORB 0x04 + #define ILINK_ADAPTEC 0x08 + diff -r -c -N sys44.orig/dev/firewire/lynx.c sys/dev/firewire/lynx.c *** sys44.orig/dev/firewire/lynx.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/lynx.c Tue Oct 9 21:55:18 2001 *************** *** 0 **** --- 1,2072 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: lynx.c,v 1.1.2.1 2000/06/04 17:19:06 ikob Exp $ + * + */ + + #if 0 + #define DDB(x) x + #define DEB(x) + #endif + #define PHYBUG + #undef PHYBUG + #define NOIRM /* prevent IRM election phase */ + #undef NOIRM + #define DEBUG_PACKET + #undef DEBUG_PACKET + #define TX_CH 1 + #define ARX_CH 0 + #define IRX_CH 3 + #define DVTX_CH 4 + #define DVRX_CH 2 + #define MAXIPFRAG 40 + + #define RX_DMA + #undef RX_DMA + #define PREVENT_ISOHDR + #undef PREVENT_ISOHDR + + #ifdef __FreeBSD__ + #include "lynx.h" + #include "pci.h" + #endif /* __FreeBSD__ */ + + #if !defined(__FreeBSD__) || (NLYNX > 0 && NPCI > 0) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + #include + + #ifdef INET + #endif + #include + #include + #include + #include + #include + #include + #ifdef INET + #endif + #include + #include + + #include + + #ifdef __FreeBSD__ + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + + #define LYNX_DEBUG + #undef LYNX_DEBUG + char pclcode[16][0x10]={"NOP", "RCV","XMIT","LOAD", + "STRQ","STR0","STR1","BR", + "TOLBUS","TOPCI","RCV&UPD", "STRD", + "UXMIT","ADD","CMP","SWAP&CMP"}; + extern char linkspeed[4][0x10]; + char pclcond[8][0x10]={"NOWAIT","DMA R1", "DMA R0", + "EX R1", "EX R0", "GPIO 2", "GPIO 3"}; + extern char ackcode[32][0x20]; + typedef int ioctl_cmd_t; + #define LYNX_WRITE_SIGMASK 0xffff0000 + #define LYNX_READ_SIGMASK 0xffff0000 + + #define LYNXARGS(sc) (sc)->fc.ac.ac_if.if_unit + + #endif /* __FreeBSD__ */ + + #define senderr(e) { error = (e); goto bad;} + + static void lynx_start_txdv __P((struct lynx_softc *)); + static void lynx_start_rxdv __P((struct lynx_softc *)); + static void lynx_stop_rxdv __P((struct lynx_softc *)); + static void lynx_reset __P((struct lynx_softc *)); + static void lynx_ibr __P((struct lynx_softc *)); + static int lynx_ioctl __P((struct ifnet *, u_long, caddr_t)); + static void lynx_init __P((struct lynx_softc *)); + void lynx_busreset __P((struct fw_softc *)); + static void lynx_pcl_init __P((struct lynx_softc *)); + static void lynx_pcl_ch_init __P((struct lynx_softc *, int, int, int)); + static void lynx_dv_init __P((struct lynx_softc *)); + static void lynx_rx_enable __P((struct lynx_softc *, int, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); + static void lynx_rx_disable __P((struct lynx_softc *, int)); + static void lynx_tx_init __P((struct lynx_softc *, int)); + static void lynx_rcv __P((struct lynx_softc *, int)); + static void lynx_txd __P((struct lynx_softc *, int)); + static void lynx_start __P((struct ifnet *)); + static void lynx_ch_start __P((struct ifnet *, int ch)); + static void lynx_intr __P((void *arg)); + static u_int lynx_gen_isomask __P((struct ifnet *)); + #ifdef RX_DMA + static int lynx_add_rx_buf __P((struct lynxpcl_tr *, struct mbuf *)); + #else + static int lynx_forward_rx_buf __P((struct lynxpcl_tr *)); + #endif + static void dump_pcl __P((struct lynx_softc *, int)); + static void dump_pcl_seq __P((struct lynx_softc *, int)); + static void print_pcl __P((struct lynxpcl *, int )); + static void dump_dma __P((struct lynx_softc *, int)); + static void dump_fifo_ptr __P((struct lynx_softc *)); + + typedef u_char bool_t; + + /* + * memory allocated for DMA programs + */ + #define DMA_PROG_ALLOC (8 * PAGE_SIZE) + + #ifdef RX_DMA + #define NPCL 32 + #else + #define NPCL 128 + #endif + #define NDVPCL DVBUF * 16 + + #define DV_FRAME 12 + + #ifdef __FreeBSD__ + + static int lynx_probe __P((device_t)); + static int lynx_attach __P((device_t)); + static int lynx_shutdown __P((device_t)); + + #define UNIT(x) (((x) & 0xf0) >> 4) + #define MINOR(x) ((x) & 0xf) + + static device_method_t lynx_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, lynx_probe), + DEVMETHOD(device_attach, lynx_attach), + DEVMETHOD(device_shutdown, lynx_shutdown), + + { 0, 0 } + }; + + static driver_t lynx_driver = { + "lynx", + lynx_methods, + sizeof(struct lynx_softc), + }; + + static devclass_t lynx_devclass; + + DRIVER_MODULE(if_lynx, pci, lynx_driver, lynx_devclass, 0, 0); + #endif /* __FreeBSD__ */ + + + #ifdef __FreeBSD__ + /* + * the boot time probe routine. + */ + static int + lynx_probe( device_t dev ) + { + if ((pci_get_vendor(dev) == LYNX_VENDORID_TI) && + (pci_get_device(dev) == LYNX_DEVICE_PCILYNX)) { + device_set_desc(dev, "Texas Instrument PCILynx"); + return 0; + } + return ENXIO; + } + #endif /* __FreeBSD__ */ + + /* + * the attach routine. + */ + static int + lynx_attach( device_t dev) + { + struct lynx_softc *sc = device_get_softc(dev); + int unit = device_get_unit(dev); + int error = 0; + + struct ifnet *ifp; + u_int32_t cmd, latency, cache_line, val; + volatile u_int32_t fun; + u_int ch; + int bootverbose = 1; + int rid; + + #ifdef __FreeBSD__ + ifp = (struct ifnet *)&sc->fc.ac; + + callout_handle_init(&sc->fc.stat_ch); + + rid = PCI_MAP_REG_START; + sc->fc.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0, ~0, 1, RF_ACTIVE); + if (!sc->fc.mem) { + device_printf(dev, "could not map memory\n"); + error = ENXIO; + goto fail; + } + sc->base = rman_get_virtual(sc->fc.mem); /* XXX use bus_space */ + + #endif /* __FreeBSD__ */ + sc->fc.sid_buf = (u_int32_t *) vm_page_alloc_contig( 1 << 11, + 0x10000, 0xffffffff, 1 << 11); + + ifp->if_flags &= ~IFF_UP; + /* + fun = sc->base->misc_cntl; + fun |= LYNX_SWRST; + sc->base->misc_cntl = fun ; + */ + /* PCILynx work around */ + /* Terminate all transmits queued to the DMA */ + /* Disable Recieve channel comparators */ + /* Wait 10msec to ensure that all recieved packet are transformed */ + /* Set the software reset bit */ + /* Flush the FIFOs by writing a 1 to each of the 3 flush bits in the FIFO control registers */ + /* Reset the Link reciever and the transmitter logic by writing 1 to each of the respective bits in the Link Layer Control Register */ + /* Also, set the software reset bit */ + for ( ch = 0 ; ch < LYNX_MAX_DMA_CH ; ch ++){ + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + sc->dma_ch[ch] = 0; + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + sc->base->dma_diag |= LYNX_DMA_TESTEN; + sc->base->dma_cntl[ch].stat |= LYNX_DMA_MSTR_ERR; + sc->base->dma_diag &= ~LYNX_DMA_TESTEN; + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_LINK; + } + for ( ch = 0 ; ch < LYNX_MAX_DMA_CH ; ch ++){ + sc->base->dma_cmp[ch].w1_mask &= ~LYNX_DMA_EN_CH_CMP; + } + DELAY(20); + sc->base->misc_cntl = LYNX_SWRST ; + sc->base->fifo_token_cntl + |= LYNX_ATF_FLUSH | LYNX_ITF_FLUSH | LYNX_GRF_FLUSH; + sc->base->link_cntl |= LYNX_LINK_RSTTX | LYNX_LINK_RSTRX; + sc->base->misc_cntl = LYNX_SWRST ; + + latency = pci_read_config(dev, PCIR_LATTIMER, 1); + #define DEF_LATENCY 200 /* Derived from Max Bulk Transfer size 512 Bytes*/ + if( latency < DEF_LATENCY ) { + latency = DEF_LATENCY; + printf("pcilynx%d: PCI bus latency was changing to", unit); + pci_write_config(dev, PCIR_LATTIMER, latency, 1); + } else + { + printf("pcilynx%d: PCI bus latency is", unit); + } + printf(" %d.\n", (int) latency); + #define DEF_CACHE_LINE 0x8 + cache_line = DEF_CACHE_LINE; + pci_write_config(dev, PCIR_CACHELNSZ, cache_line, 1); + + cmd = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); + cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN; + pci_write_config(dev, PCI_COMMAND_STATUS_REG, cmd ,4); + #define PCIR_LYNX_RAM PCIR_MAPS + 4 + fun = pci_read_config(dev, PCIR_LYNX_RAM, 4); + pci_write_config(dev, PCIR_LYNX_RAM, 0xffffffff,4); + printf("pcilynx%d:ram0: 0x%08x - 0x%08x\n", unit, fun, + fun | (lynxreg_t)~pci_read_config(dev, PCIR_LYNX_RAM ,4)); + + fun = pci_read_config(dev, PCIR_BIOS, 4); + if( fun != 0 ){ + pci_write_config(dev, PCIR_BIOS, 0xffffffff,4); + printf("pcilynx%d:rom0: 0x%08x - 0x%08x\n", unit, fun, + fun | (lynxreg_t)~pci_read_config(dev, PCIR_BIOS ,4)); + } + /* + * probe PHY parameters + * 0. to probe PHY, whether TSB21LV3, TSB21LV01 or others. + * 1. to probe maximum speed supported by the PHY and + * number of port supported by core-logic. + * It is not actually available port. + */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + + printf("pcilynx%d: Link %s, %d ports.\n", unit, + linkspeed[(fun & FW_PHY_SPD) >> 6], fun & FW_PHY_NP); + lynx_busreset((struct fw_softc *)sc); + + /* setup FIFO threshold */ + #define IP1394 + #ifdef IP1394 + #define ATF_FIFO_SZ 0x50 + #define ITF_FIFO_SZ 0x50 + #define ATF_THRESHOLD (ATF_FIFO_SZ - DEF_CACHE_LINE - 1) + #define ITF_THRESHOLD (ATF_FIFO_SZ - DEF_CACHE_LINE - 1) + #else + #define ATF_FIFO_SZ (2 * DEF_CACHE_LINE) + /*#define ITF_FIFO_SZ ((0x100 - 2 * (DEF_CACHE_LINE) ) / 2)*/ + #define ITF_FIFO_SZ (0x100 - ATF_FIFO_SZ - 0x50) + #define ATF_THRESHOLD ((ATF_FIFO_SZ) - (DEF_CACHE_LINE) - 1) + #define ITF_THRESHOLD 0x80 + #endif + #define GRF_FIFO_SZ (0xff - (ATF_FIFO_SZ) - (ITF_FIFO_SZ)) + sc->base->fifo_size = ((ITF_FIFO_SZ << 16 ) + | (ATF_FIFO_SZ << 8) + | (GRF_FIFO_SZ)); + + sc->base->atf_itf_cntl = ((ATF_FIFO_SZ - DEF_CACHE_LINE - 1 ) << 8) + | (ITF_FIFO_SZ - DEF_CACHE_LINE - 1); + + sc->base->atf_itf_cntl = ((ATF_THRESHOLD ) << 8) + | (ITF_THRESHOLD); + + sc->base->fifo_err = 0x00fe0000; + sc->base->rty_cnt_int = ( 0x16 << 8 ) | 0x16 ; + #if 1 + sc->base->dma_global |= 0x02 << 24; + #else + sc->base->dma_global = 0x0 << 24; + #endif + + /* Thease function is not required in PC environment */ + /* AUTO boot enable / not enable */ + if ( bootverbose ) { + printf("pcilynx%d: autoboot ROM is %s.\n", + unit, sc->base->misc_cntl & LYNX_AUTOBOOT_IN + ? "enable":"disable"); + } + + /* stop all DMA action */ + for ( ch = 0 ; ch < LYNX_MAX_DMA_CH ; ch ++){ + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + } + + /* Attach PCL to dma channel */ + sc->fc.dv_flags = 0; + lynx_pcl_init(sc); + + #if 0 + sc->ipl = 1; /* XXX */ + #endif + ifp->if_softc = sc; + ifp->if_name = "lynx"; + ifp->if_unit = unit; + ifp->if_mtu = 1500; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; + ifp->if_ioctl = lynx_ioctl; + ifp->if_output = fw_output; + ifp->if_type = IFT_IEEE1394; + ifp->if_start = lynx_start; + ifp->if_init = (if_init_f_t *)lynx_init; + ifp->if_addrlen = 0; + ifp->if_hdrlen = 0; + ifp->if_snd.ifq_maxlen = 8000; + + sc->fc.dv_gap = 3 << 12; + sc->fc.dv_write_proc = 0; + sc->fc.dv_read_proc = 0; + sc->flags = 0; + sc->fc.p_cycle_timer = &sc->base->cycle_timer; + sc->fc.fw_busreset = lynx_busreset; + bzero(&sc->fc.ac.media.firewire.eui64, 8); + + /* establish interrupt */ + rid = 0; + sc->fc.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + RF_SHAREABLE | RF_ACTIVE); + if (sc->fc.irq == NULL) { + device_printf(dev, "could not map interrupt\n"); + error = ENXIO; + goto fail; + } + + error = bus_setup_intr(dev, sc->fc.irq, INTR_TYPE_NET, + lynx_intr, sc, &sc->fc.ih); + if (error) { + device_printf(dev, "could not setup irq\n"); + goto fail; + } + lynx_init(sc); + + if_attach(ifp); + sc->fc.txdv = lynx_start_txdv; + sc->fc.txstop = NULL; + sc->fc.rxdv = lynx_start_rxdv; + sc->fc.rxstop = lynx_stop_rxdv; + fwiso_attach(dev, &fwiso_cdevsw); + + bpfattach(ifp, DLT_NULL, sizeof(struct fwhdr)); + /* Initiate Busreset */ + #if 0 + lynx_ibr(sc); + #endif + fail: + return error; + } + static void lynx_start(ifp) + register struct ifnet *ifp; + { + lynx_ch_start(ifp, TX_CH); + } + static void lynx_ch_start(ifp, ch) + register struct ifnet *ifp; + int ch; + { + struct mbuf *m, *mb_head; + struct ifqueue *ifq = &ifp->if_snd; + struct lynx_softc *sc = (struct lynx_softc *)ifp->if_softc; + struct lynxpcl_tr *tx, *last = 0; + int s, segment; + u_int32_t proto; + struct fwhdr *ld; + /* + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + */ + if(sc->queued[ch] > 0 ){ + last = sc->pcl_last[ch]; + tx = sc->pcl_last[ch]->next; + goto kick; + } + txloop: + s = splimp(); + IF_DEQUEUE(ifq, mb_head); + if (mb_head == NULL){ + splx(s); + if( last == 0 ){ + return; /* EMPTY: >>> exit here <<< */ + }else{ + goto kick; + } + } + splx(s); + #if defined(__FreeBSD__) + if (ifp->if_bpf) { + /* + * We need to prepend the address family as + * a four byte field. Cons up a dummy header + * to pacify bpf. This is safe because bpf + * will only read from the mbuf (i.e., it won't + * try to free it or keep a pointer to it). + */ + struct mbuf m1; + u_int af = AF_UNSPEC; + + m1.m_next = mb_head; + m1.m_len = 4; + m1.m_data = (char *)⁡ + + bpf_mtap(ifp, &m1); + } + #endif + ifp->if_opackets++; + ld = mtod(mb_head, struct fwhdr *); + proto = ld->cntl[0]; + + if(proto != PROTO_N1394ASYST){ + /* remove control entry */ + m_adj(mb_head, sizeof(fwcntl)); + }else{ + /* re-use control entry space */ + u_int32_t *ald; + /* Back to pointer 1 quadret */ + ald = mtod(mb_head, u_int32_t *); + ald[sizeof(fwcntl)/4 - 1] = ld->data[0]; + ald[sizeof(fwcntl)/4] + = htonl(crcfw(mb_head, 1, sizeof(fwcntl)/4 - 1)); + + m = mb_head; + while(m->m_next) + m = m->m_next; + if(M_TRAILINGSPACE(m) < 4 ){ + /* APPEND one more mbuf, if required */ + MGET(m, M_DONTWAIT, MT_DATA); + if( m == NULL){ + m_freem(mb_head); + goto kick; + } + ald = mtod(m, u_int32_t *); + ald[0] = htonl(crcfw(mb_head, 0, sizeof(fwcntl)/4+1)); + m->m_len = 4; + m_cat(mb_head, m); + }else{ + ald = mtod(m, u_int32_t *); + ald[(m->m_len + 3)/4] + = htonl(crcfw(mb_head, 0, sizeof(fwcntl)/4+1)); + mb_head->m_pkthdr.len += 4; + m->m_len += 4; + } + if((sizeof(fwcntl) - 4) > 0){ + m_adj(mb_head, sizeof(fwcntl) - 4); + } + } + last = sc->pcl_last[ch]; + tx = sc->pcl_last[ch]->next; + tbdinit: + /* Default scatter gathering */ + for (m = mb_head, segment = 0; m != NULL; m = m->m_next) { + if (m->m_len != 0) { + if (segment >= LYNXPCLBUF ) + break; + tx->pcl->data[segment].ptr = + vtophys(mtod(m, vm_offset_t)); + tx->pcl->data[segment].cntl = (m->m_len & 0xfff); + segment++; + } + } + /* Number of fragmentation exceed MAX PCL buffer */ + if(m != NULL){ + struct mbuf *mn; + MGETHDR(mn, M_DONTWAIT, MT_DATA); + if (mn == NULL) { + m_freem(mb_head); + goto kick; + return; + } + if (mb_head->m_pkthdr.len > MHLEN) { + MCLGET(mn, M_DONTWAIT); + if ((mn->m_flags & M_EXT) == 0) { + m_freem(mn); + m_freem(mb_head); + goto kick; + return; + } + } + m_copydata(mb_head, 0, mb_head->m_pkthdr.len, + mtod(mn, caddr_t)); + mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len; + m_freem(mb_head); + mb_head = mn; + goto tbdinit; + } + + tx->mbhead = mb_head; + tx->pcl->data[segment - 1].cntl |= LYNX_PCL_LASTBUF; + tx->pcl->data[0].cntl |= LYNX_PCL_TX_S100 | LYNX_PCL_INT + | LYNX_PCL_WAITDMA_0 | LYNX_PCL_WAIT; + switch(proto){ + case PROTO_N1394ASYRQ: + tx->pcl->data[0].cntl |= LYNX_PCL_XMIT; + break; + case PROTO_N1394ISOST: + tx->pcl->data[0].cntl |= LYNX_PCL_XMIT; + tx->pcl->data[0].cntl |= LYNX_PCL_TXISO ; + #ifdef MULTIISO + tx->pcl->data[0].cntl |= LYNX_PCL_MULTIISO; + #endif + break; + case PROTO_N1394ASYST: + tx->pcl->data[0].cntl |= LYNX_PCL_UXMIT; + break; + case PROTO_N1394RAW: + tx->pcl->data[0].cntl |= LYNX_PCL_UXMIT; + break; + default: + printf("lynx%d:bad 1394 proto = 0x%08x\n", + LYNXARGS(sc), proto); + /* send it anyway */ + tx->pcl->data[0].cntl |= LYNX_PCL_UXMIT; + break; + } + + sc->base->pci_int_ena |= + LYNX_INT_PEND | LYNX_P1394_INT + | ( LYNX_DMA0_PCL << ( 2 * ch)) + | ( LYNX_DMA0_HLT << ( 2 * ch)); + + #if 0 + dump_dma(sc, ch); + dump_pcl(sc, ch); + dump_fifo_ptr(sc); + #endif + s = splimp(); + tx->pcl->pcl_next |= 0x1; + last->pcl->pcl_next &= ~0x1; + /* + printf("txloop last 0x%08x tx 0x%08x\n", + last->pcl->pcl_next, tx->pcl->pcl_next ); + */ + + sc->queued[ch] ++; + splx(s); + sc->pcl_last[ch] = tx; + /* pointed out by Kawa@mb.kcom.ne.jp */ + if(sc->queued[ch] > sc->npcl[ch] ){ + goto txloop; + } + kick: + if(!(sc->base->dma_cntl[ch].cntl & LYNX_DMA_BSY)){ + sc->base->dma_cntl[ch].curr_pcl &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ch].curr_pcl = + vtophys(last->pcl) & ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ch].cntl |= LYNX_DMA_LINK; + } + } + static void lynx_dv_init(sc) + register struct lynx_softc *sc; + { + int ipcl; + int iseq; + int idv; + struct lynxpcl *pcl; + vm_offset_t buf_base; + u_int32_t *addr; + u_int32_t *ld, *hd; + u_int32_t *rxhdr; + + sc->fc.dv_buf_size = sizeof(struct dv_data) + 2 * MAX_DVFRAME * S100_SZ * (DVBUF + 1); + sc->fc.dv_buf = (struct dv_data *)vm_page_alloc_contig( sc->fc.dv_buf_size, + 0x100000, 0xffffffff, PAGE_SIZE); + rxhdr = (u_int32_t *)vm_page_alloc_contig( sizeof(u_int32_t) * DVBUF * MAX_DVFRAME, 0x100000, 0xffffffff, PAGE_SIZE); + if(sc->fc.dv_buf == NULL){ + printf("Phisical memory is exhoused\n"); + /* take back track to free allocated memory */ + sc->fc.dv_flags &= ~FW_DVINIT; + return; + } + buf_base = (vm_offset_t)sc->fc.dv_buf + sizeof(struct dv_data); + for( iseq = 0, ipcl = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + iseq * S100_SZ * (DVBUF+1)); + sc->pcldvtx[iseq].pcl_tr = &sc->pcl_tr[DVTX_CH][ipcl]; + sc->fc.dv_write_buf[iseq] = &addr[S100_SZ/4]; + /* first PCL is used as dummy */ + for( idv = 0 ; idv < DVBUF ; idv++){ + pcl = sc->pcl_tr[DVTX_CH][ipcl].pcl; + if( idv == 0 ) + sc->pcldvtx[iseq].prev_pcl = pcl; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 1 ){ + sc->fc.dv_write_buf[iseq] = ld; + sc->fc.dv_buf->write_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + pcl->data[0].ptr = vtophys(ld); + pcl->data[0].cntl = LYNX_PCL_XMIT + | LYNX_PCL_TXISO ; + pcl->data[0].cntl |= LYNX_PCL_LASTBUF; + pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + pcl->data[0].cntl |= S100_SZ & 0xfff; + + ld[0] = htonl((DV_ISOTAGCIP << 14) | + ((S100_SZ-12) << 16) | (TCODE_STREAM << 4) ); + ld[1] = htonl((DVSIZE / 4 ) << 16); + ipcl++; + } + pcl->data[0].cntl |= LYNX_PCL_INT; + pcl->pcl_next |= LYNX_DMA_PCL_EN; + sc->fc.dv_buf->write_len[iseq] = idv - 1; + } + for( iseq = 0, ipcl = 0; iseq < MAX_DVFRAME ; iseq++){ + addr = (u_int32_t *) (buf_base + + ( iseq + MAX_DVFRAME ) * S100_SZ * (DVBUF+1)); + sc->pcldvrx[iseq].pcl_tr = &sc->pcl_tr[DVRX_CH][ipcl]; + sc->fc.dv_read_buf[iseq] = &addr[S100_SZ/4]; + /* first PCL is used as dummy */ + for( idv = 0 ; idv < DVBUF ; idv++){ + hd = &(rxhdr[iseq * DVBUF + idv]); + pcl = sc->pcl_tr[DVRX_CH][ipcl].pcl; + if( idv == 0 ) + sc->pcldvrx[iseq].prev_pcl = pcl; + ld = &(addr[idv * S100_SZ/4]); + if( idv == 0 ){ + sc->fc.dv_read_buf[iseq] = ld; + sc->fc.dv_buf->read_off[iseq] + = (u_int32_t)ld - (u_int32_t)sc->fc.dv_buf; + } + pcl->data[0].ptr = vtophys(hd); + pcl->data[0].cntl = LYNX_PCL_RCV_UPDATE; + /* pcl->data[0].cntl |= LYNX_PCL_LASTBUF;*/ + pcl->data[0].cntl |= 0x4; + + pcl->data[1].ptr = vtophys(ld); + pcl->data[1].cntl = LYNX_PCL_RCV_UPDATE; + pcl->data[1].cntl |= LYNX_PCL_LASTBUF; + pcl->data[1].cntl |= S100_SZ & 0xfff; + pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + + ipcl++; + } + pcl->data[0].cntl |= LYNX_PCL_INT; + /* pcl->pcl_next |= LYNX_DMA_PCL_EN;*/ + sc->fc.dv_buf->read_len[iseq] = idv; + } + /* pcl->pcl_next |= LYNX_DMA_PCL_EN;*/ + sc->pcldvrx[0].prev_pcl = pcl; + + sc->fc.dv.wklock = 0; + sc->fc.dv.walock = -1; + + sc->fc.dv.rklock = 0; + sc->fc.dv.ralock = -1; + + sc->fc.dv.dbc = -1; + sc->fc.dv.sync = 6; + sc->fc.dv.queued = 0; + + sc->fc.dv_buf->n_write = DV_FRAME; + sc->fc.dv_buf->k_write = 0xffffffff; + sc->fc.dv_buf->a_write = 0x0; + + sc->fc.dv_buf->n_read = DV_FRAME; + sc->fc.dv_buf->k_read = 0xffffffff; + sc->fc.dv_buf->a_read = 0x0; + /* Attach device dependent routins */ + + sc->fc.dv_flags |= FW_DVINIT; + } + static void lynx_pcl_ch_init(sc, ch, npcl, len) + register struct lynx_softc *sc; + int ch; + int npcl; + int len; + { + int ipcl; + struct lynxpcl *pcl; + /* allocate PCL entries and attach one to each DMA channels */ + /* PCL entry must start at 16 bytes bounary. */ + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + sc->npcl[ch] = npcl; + sc->pcl_tr[ch] = (struct lynxpcl_tr *) + malloc(sizeof(struct lynxpcl_tr) * npcl, + M_DEVBUF, M_NOWAIT); + + sc->pcl_tr[ch][0].pcl = (struct lynxpcl *) + vm_page_alloc_contig(sizeof(struct lynxpcl) * npcl, + 0x100000, 0xffffffff, PAGE_SIZE); + + /* Attach PCL to DMA ch. */ + pcl = sc->pcl_tr[ch][0].pcl; + sc->queued[ch] = 0; + for(ipcl = 0 ; ipcl < npcl ; ipcl++){ + sc->pcl_tr[ch][ipcl].pcl = &(pcl[ipcl]); + #ifndef RX_DMA + if( len > 0 ){ + sc->pcl_tr[ch][ipcl].buf = + #if 1 + (caddr_t)vm_page_alloc_contig( len, + 0x100000, 0xffffffff, PAGE_SIZE); + #else + (caddr_t)malloc( len, M_DEVBUF, M_NOWAIT); + #endif + } + #endif + if( ipcl != (npcl - 1)){ + sc->pcl_tr[ch][ipcl].next + = &(sc->pcl_tr[ch][ipcl + 1]); + pcl[ipcl].pcl_next + = vtophys(&pcl[ipcl + 1]) | LYNX_DMA_PCL_EN; + pcl[ipcl].err_next = 0x01; + pcl[ipcl].err_next = vtophys(&pcl[ipcl + 1]) ; + }else{ + sc->pcl_tr[ch][npcl - 1].next + = &(sc->pcl_tr[ch][0]); + pcl[npcl - 1].pcl_next + = vtophys(&pcl[0]) | LYNX_DMA_PCL_EN; + pcl[npcl - 1].err_next = 0x01; + pcl[npcl - 1].err_next = vtophys(&pcl[0]) ; + } + } + pcl = sc->pcl_tr[ch][0].pcl; + sc->pcl_tr[ch][0].pcl->pcl_next |= LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ch].curr_pcl + = (lynxreg_t) vtophys(&pcl[0]) | LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ch].curr_pcl + = (lynxreg_t) vtophys(&(sc->pcl_tr[ch][0].pcl[0])) + | LYNX_DMA_PCL_EN; + sc->pcl_last[ch] = &(sc->pcl_tr[ch][0]); + sc->pcl_first[ch] = &(sc->pcl_tr[ch][0]); + } + static void lynx_pcl_init(sc) + register struct lynx_softc *sc; + { + int ch; + /* Stop DMA process before handle PCL */ + for( ch = 0 ; ch < LYNX_MAX_DMA_CH ; ch ++) { + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + } + lynx_pcl_ch_init(sc, ARX_CH, NPCL, MCLBYTES); + lynx_pcl_ch_init(sc, IRX_CH, NPCL, MCLBYTES); + lynx_pcl_ch_init(sc, TX_CH, NPCL, 0); + lynx_pcl_ch_init(sc, DVTX_CH, NDVPCL, 0); /* incl. dummy PCL */ + lynx_pcl_ch_init(sc, DVRX_CH, NDVPCL, 0); /* incl. dummy PCL */ + + lynx_dv_init(sc); + } + static void lynx_rx_disable(sc, ch) + register struct lynx_softc *sc; + int ch; + { + #ifdef RX_DMA + int ipcl; + #endif + + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + #ifdef RX_DMA + for( ipcl = 0 ; ipcl < sc->npcl[ch] ; ipcl ++){ + /* Attach and Invalidate current PCL pointer */ + m_freem(sc->pcl_tr[ch][ipcl].mbhead); + sc->pcl_tr[ch][ipcl].mbhead = NULL; + } + #endif + } + + static void lynx_rx_enable(sc, ch, w0v, w0m, w1v, w1m) + register struct lynx_softc *sc; + int ch; + u_int32_t w0v, w0m, w1v, w1m; + { + int ipcl; + + /* to disable DMA */ + sc->base->dma_cntl[ch].cntl &= ~LYNX_DMA_CH_ENA; + + /* to enable recieve queue comparator */ + sc->base->dma_cmp[ch].w0_val = w0v; + sc->base->dma_cmp[ch].w0_mask = w0m; + sc->base->dma_cmp[ch].w1_val = w1v; + sc->base->dma_cmp[ch].w1_mask = w1m; + + for( ipcl = 0 ; ipcl < sc->npcl[ch] ; ipcl ++){ + /* Append PCL list */ + #ifdef RX_DMA + lynx_add_rx_buf(&(sc->pcl_tr[ch][ipcl]), 0); + #else + lynx_forward_rx_buf(&(sc->pcl_tr[ch][ipcl])); + #endif + sc->pcl_tr[ch][0].pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + } + /* Clear GRF */ + sc->base->fifo_token_cntl |= LYNX_GRF_FLUSH; + + sc->pcl_last[ch] = &(sc->pcl_tr[ch][0]); + sc->pcl_last[ch]->pcl->pcl_next |= LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ch].curr_pcl + = (lynxreg_t) vtophys(&(sc->pcl_tr[ch][0].pcl[0])) + | LYNX_DMA_PCL_EN; + } + static void lynx_tx_init(sc, ch) + register struct lynx_softc *sc; + int ch; + { + int ipcl; + for( ipcl = 0 ; ipcl < sc->npcl[ch] ; ipcl ++){ + sc->pcl_tr[ch][ipcl].pcl->pcl_next |= 0x01; + sc->pcl_tr[ch][ipcl].pcl->status = (lynxreg_t) 0x0; + sc->pcl_tr[ch][ipcl].mbhead = NULL; + } + return; + } + static void lynx_init(sc) + register struct lynx_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + ifp->if_flags &= ~IFF_RUNNING; + sc->base->pci_int_ena = 0x0ul; + sc->base->link_int_ena = 0x0ul; + + + if_fwinit(&sc->fc); + /* Clear FIFO's */ + #if 1 + sc->base->link_cntl |= LYNX_LINK_RSTTX|LYNX_LINK_RSTRX; + #else + sc->base->link_cntl |= LYNX_LINK_RSTTX; + #endif + + lynx_rx_enable(sc, ARX_CH, + sc->base->link_bus_node << 16, 0xffff00a0, + 0x0, + LYNX_DMA_EN_CH_CMP | ( 0x0f << 11) + | LYNX_DMA_WRITE_REQ_ACK_SEL | LYNX_DMA_SELF_ID_EN ); + + lynx_tx_init(sc, TX_CH); + + sc->base->rty_cnt_int = ( 0x16 << 8 ) | 0x16 ; + + sc->base->dma_cntl[TX_CH].cntl |= LYNX_DMA_CH_ENA; + + sc->base->dma_cntl[ARX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cntl[ARX_CH].curr_pcl &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ARX_CH].cntl |= LYNX_DMA_LINK; + + sc->base->pci_int_ena |= + LYNX_INT_PEND | LYNX_P1394_INT + | ( LYNX_DMA0_PCL << ( 2 * ARX_CH )) + | ( LYNX_DMA0_HLT << ( 2 * ARX_CH )); + + sc->base->link_int_ena |= LYNX_INT_LINK_INT | LYNX_INT_PHY_TIMEOUT + | LYNX_INT_LINK_INT | LYNX_INT_ATF_UNDERFLOW + | LYNX_INT_ITF_UNDERFLOW | LYNX_INT_PHY_BUSRESET + | LYNX_INT_CYC_ARB_FAILED | LYNX_INT_CYC_LOST ; + + ifp->if_flags |= IFF_RUNNING; + + return; + } + static int lynx_shutdown(device_t dev) + { + struct lynx_softc *sc = device_get_softc(dev); + u_int32_t fun; + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + + ifp->if_flags &= ~IFF_UP; + + printf("shutdown\n"); + fun = sc->base->misc_cntl; + fun |= LYNX_SWRST; + sc->base->misc_cntl = fun ; + + return 0; + } + + static void + lynx_intr( void *arg ) + { + struct lynx_softc *sc = (struct lynx_softc *)arg; + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + u_int32_t csr, lsr; + struct lynxpcl_tr *pcl_tr; + int ipcl; + + #if 0 + while(csr = sc->base->pci_int_stat) + #else + csr = sc->base->pci_int_stat; + #endif + { + if(csr & LYNX_P1394_INT){ + lsr = sc->base->link_int_stat; + }else{ + lsr = 0; + } + /* Release Pending state to avoid loop condition */ + /* The suspection is pointed out by kawa@mb.kcom.ne.jp */ + sc->base->pci_int_stat = 0xffffffff; + sc->base->link_int_stat = 0xffffffff; + + #ifdef LYNX_DEBUG + printf("lynx%d INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x\n", + LYNXARGS(sc), + csr & LYNX_INT_PEND ? "PEND ":"", + csr & LYNX_FRC_INT ? "FORCE " :"", + csr & LYNX_SLV_ADDR_PERR ? "A_PERR ": "", + csr & LYNX_SLV_DAT_PERR ? "D_PERR ":"", + csr & LYNX_MST_DAT_PERR ? "MST_DERR ":"", + csr & LYNX_MST_DEV_TO ? "DEV_TO ":"", + csr & LYNX_MST_RETRY_TO ? "RTY_TO ":"", + csr & LYNX_INTERNAL_SLV_TO ? "INT_TO" :"", + csr & LYNX_P1394_INT ? "PHY " :"", + csr & LYNX_DMA4_PCL ? "PCL4 " :"", + csr & LYNX_DMA4_HLT ? "HLT4 ":"", + csr & LYNX_DMA3_PCL ? "PCL3 " :"", + csr & LYNX_DMA3_HLT ? "HLT3 ":"", + csr & LYNX_DMA2_PCL ? "PCL2 " :"", + csr & LYNX_DMA2_HLT ? "HLT2 ":"", + csr & LYNX_DMA1_PCL ? "PCL1 " :"", + csr & LYNX_DMA1_HLT ? "HLT1 ":"", + csr & LYNX_DMA0_PCL ? "PCL0 " :"", + csr & LYNX_DMA0_HLT ? "HLT0 ":"", + csr + ); + if(csr & LYNX_P1394_INT){ + printf("lynx%d phy INTERRUPT < %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s> 0x%08x\n", + LYNXARGS(sc), + lsr & LYNX_INT_LINK_INT ? "INT ": "", + lsr & LYNX_INT_PHY_TIMEOUT ? "TIMEOUT " : "", + lsr & LYNX_INT_PHY_REG_RCVD ? "REG_RCVD " : "", + lsr & LYNX_INT_PHY_BUSRESET ? "BUSRESET" : "", + lsr & LYNX_INT_TX_RDY ? "TXD " : "", + lsr & LYNX_INT_RX_DATA_RDY ? "RXD " : "", + lsr & LYNX_INT_IT_STUCK ? "ISO STUCK " : "", + lsr & LYNX_INT_AT_STUCK ? "ASY STUCK " : "", + lsr & LYNX_INT_SNTRJ ? "SENT BUSY " : "", + lsr & LYNX_INT_HDR_ERR ? "HDRERR " : "", + lsr & LYNX_INT_TC_ERR ? "TCERR " : "", + lsr & LYNX_INT_CYC_SEC ? "CYCSEC " : "", + lsr & LYNX_INT_CYC_STRT ? "CYCSTRT " : "", + lsr & LYNX_INT_CYC_DONE ? "CYCDONE " : "", + lsr & LYNX_INT_CYC_PEND ? "CYCPEND " : "", + lsr & LYNX_INT_CYC_LOST ? "CYCLOST " : "", + lsr & LYNX_INT_CYC_ARB_FAILED ? "CYCARB_FAILED " : "", + lsr & LYNX_INT_GRF_OVER_FLOW ? "GRFOVERFLOW " : "", + lsr & LYNX_INT_ITF_UNDERFLOW ? "ITFUNDERFLOW " : "", + lsr & LYNX_INT_ATF_UNDERFLOW ? "ATFUNDERFLOW " : "", + lsr & LYNX_INT_IARB_FAILED ? "IARB_FAILED " : "", + lsr + ); + #endif + #if 0 + if(csr & ( ( LYNX_DMA0_HLT << ( 2 * DVRX_CH)))){ + printf("DVRX INT\n"); + } + #endif + if(csr & ( ( LYNX_DMA0_PCL << ( 2 * DVRX_CH)))){ + u_int k_read = (sc->fc.dv_buf->k_read + 1 ) % 16; + u_int32_t *read_buf; + read_buf = (u_int32_t *) ((caddr_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + while((*read_buf & htonl(0xf0)) != htonl(0xf0)){ + *read_buf |= htonl(0xf0); + k_read = (k_read + 1) % 16; + read_buf = (u_int32_t *) ((caddr_t)sc->fc.dv_buf + sc->fc.dv_buf->write_off[k_read]); + } + /* printf("0x%08x 0x%08x\n", k_read, *read_buf);*/ + sc->fc.dv_buf->k_read = k_read; + /* if signal is registered, raise up signal */ + if( sc->fc.dv_read_proc != 0 && + !(sc->fc.read_signal & LYNX_READ_SIGMASK)){ + psignal(sc->fc.dv_read_proc, + sc->fc.read_signal ); + } + } + if(csr & ( ( LYNX_DMA0_PCL << ( 2 * DVTX_CH)))){ + if(INITREG(&sc->fc, oPCR) & DV_BROADCAST_ON){ + lynx_start_txdv(sc); + }else if( sc->fc.dv_start != 0 ){ + lynx_start_txdv(sc); + }else{ + sc->base->pci_int_ena &= + ~( LYNX_DMA0_HLT << ( 2 * DVTX_CH )); + sc->base->dma_cntl[DVTX_CH].cntl + &= ~LYNX_DMA_CH_ENA; + sc->fc.dv_buf->k_write = 0xffffffff; + } + /* if write operation is blocked, wake up it */ + if( sc->fc.dv_start == 0 ){ + if(sc->fc.dv_flags & FW_DVWRWAIT){ + wakeup((caddr_t)sc); + } + /* if signal is registered, raise up signal */ + if( sc->fc.dv_write_proc != 0 && + !(sc->fc.write_signal & LYNX_WRITE_SIGMASK)){ + psignal(sc->fc.dv_write_proc, + sc->fc.write_signal ); + } + } + } + if(csr & ( ( LYNX_DMA0_PCL << ( 2 * TX_CH)) + | ( LYNX_DMA0_HLT << ( 2 * TX_CH)))){ + lynx_txd(sc, TX_CH); + if (ifp->if_snd.ifq_head != NULL){ + lynx_ch_start(ifp, TX_CH); + } + } + if(csr & LYNX_P1394_INT){ + if(lsr & LYNX_INT_PHY_TIMEOUT ){ + u_int32_t tmp; + #ifdef LYNX_DEBUG + printf("lynx%d PHY timeout\n", LYNXARGS(sc)); + #endif + tmp = sc->base->link_cntl & LYNX_LINK_CYCMASTER; + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + DELAY(1); + sc->base->link_cntl + |= LYNX_LINK_RSTTX | LYNX_LINK_RSTRX; + sc->base->link_cntl |= tmp; + } + if(lsr & LYNX_INT_PHY_BUSRESET ){ + printf("lynx%d BUS reset\n", LYNXARGS(sc)); + /* disable cycle master */ + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + /* DELAY(1);*/ + lynx_busreset((struct fw_softc *)sc); + } + if(lsr & LYNX_INT_ITF_UNDERFLOW ){ + printf("lynx%d ITF underflow\n", LYNXARGS(sc)); + } + if(lsr & LYNX_INT_ATF_UNDERFLOW ){ + printf("lynx%d ATF underflow\n", LYNXARGS(sc)); + } + } + #ifdef LYNX_DEBUG + if(csr & LYNX_DMA4_PCL){ + dump_pcl(sc, 4); + } + if(csr & LYNX_DMA4_HLT){ + dump_dma(sc, 4); + } + if(csr & LYNX_DMA3_PCL){ + dump_pcl(sc, 3); + } + if(csr & LYNX_DMA3_HLT){ + dump_dma(sc, 3); + } + if(csr & LYNX_DMA2_PCL){ + dump_pcl(sc, 2); + } + if(csr & LYNX_DMA2_HLT){ + dump_dma(sc, 2); + } + if(csr & LYNX_DMA1_PCL){ + dump_dma(sc, 1); + } + if(csr & LYNX_DMA1_HLT){ + dump_dma(sc, 1); + } + if(csr & LYNX_DMA0_PCL){ + dump_dma(sc, 0); + } + if(csr & LYNX_DMA0_HLT){ + dump_dma(sc, 0); + } + #endif + if((csr & (LYNX_DMA0_PCL << (2 * ARX_CH ))) ){ + lynx_rcv(sc, ARX_CH); + } + if(csr & (LYNX_DMA0_PCL << (2 * IRX_CH ))){ + lynx_rcv(sc, IRX_CH); + } + if(csr & ( LYNX_DMA0_HLT << (ARX_CH * 2))){ + sc->pcl_last[ARX_CH]->pcl->pcl_next |= 0x01; + pcl_tr = sc->pcl_last[ARX_CH]; + for( ipcl = 0 ; ipcl < (sc->npcl[ARX_CH] - 1) ; ipcl ++){ + pcl_tr->pcl->pcl_next &= ~0x01; + } + sc->base->dma_cntl[ARX_CH].curr_pcl &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[ARX_CH].cntl |= LYNX_DMA_LINK; + } + if(csr & ( LYNX_DMA0_HLT << (IRX_CH * 2))){ + sc->pcl_last[IRX_CH]->pcl->pcl_next |= 0x01; + pcl_tr = sc->pcl_last[IRX_CH]; + for( ipcl = 0 ; ipcl < (sc->npcl[IRX_CH] - 1) ; ipcl ++){ + pcl_tr->pcl->pcl_next &= ~0x01; + } + sc->base->dma_cntl[IRX_CH].curr_pcl &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_LINK; + } + } + return; + } + /* + * TX'd mbuf housekeeping + */ + void lynx_txd(sc, ch) + struct lynx_softc *sc; + int ch; + { + struct lynxpcl_tr *txd, *current; + int s; + /* if error, stop DMA, reset TX buffer */ + txd = sc->pcl_first[ch]; + while(sc->queued[ch] > 0){ + current = txd->next; + if((!(current->pcl->status & (0x01 << 28))) + &&(sc->base->dma_cntl[TX_CH].cntl & LYNX_DMA_CH_ENA)){ + if(!(current->pcl->status & LYNX_PCL_PKTCMP)){ + /* Buggy ??????? */ + break; + } + } else { + #ifdef LYNX_DEBUG + dump_dma(sc, TX_CH); + dump_pcl(sc, TX_CH); + #endif + sc->base->dma_cntl[TX_CH].cntl &= ~LYNX_DMA_CH_ENA; + sc->base->dma_diag |= LYNX_DMA_TESTEN; + sc->base->dma_cntl[TX_CH].stat |= LYNX_DMA_MSTR_ERR; + sc->base->dma_diag &= ~LYNX_DMA_TESTEN; + sc->base->dma_cntl[TX_CH].cntl &= ~LYNX_DMA_LINK; + sc->base->link_cntl |= LYNX_LINK_RSTTX; + sc->base->fifo_token_cntl |= LYNX_ATF_FLUSH | LYNX_ITF_FLUSH; + sc->base->dma_cntl[TX_CH].cntl |= LYNX_DMA_CH_ENA; + } + txd->pcl->pcl_next |= 0x01; + /* + printf("txintr txd 0x%08x current 0x%08x stat 0x%08x\n", + txd->pcl->pcl_next, current->pcl->pcl_next, + current->pcl->status); + */ + + m_freem(current->mbhead); + current->mbhead = NULL; + + s = splimp(); + sc->queued[ch] --; + splx(s); + current->pcl->status &= ~((0xf << 14)|LYNX_PCL_PKTCMP ); + txd = current; + sc->pcl_first[ch] = current; + } + } + static u_int lynx_gen_isomask(struct ifnet *ifp) + { + struct lynx_softc *sc = ifp->if_softc; + struct arpcom *ac = (struct arpcom *)ifp->if_softc; + u_int mask, val, i; + val = ac->media.firewire.broadcast & 0xff; + for( mask = 0xff, i = 0 ; i < 0x100 ; i++){ + if(sc->fc.isoslot[i].type == ISOSLOT_HAND || + sc->fc.isoslot[i].type == ISOSLOT_PCB ){ + mask &= ~(val ^ i); + } + } + return(mask); + } + int + lynx_ioctl( struct ifnet *ifp, u_long cmd, caddr_t data ) + { + struct lynx_softc *sc = ifp->if_softc; + struct arpcom *ac = (struct arpcom *)ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *) data; + struct fwintreq *lynxintr = (struct fwintreq *) data; + u_int32_t *npm = (u_int32_t *)data; + lynxreg_t *reg; + int err = 0; + u_int fun; + u_int mask; + u_int32_t ch; + + switch (cmd){ + case SIOCSNPM: + ch = (fw_setbmslot(ifp, *npm & 0xff)) & 0x3f; + mask = lynx_gen_isomask(ifp); + /* + if(!(ifp->if_flags & IFF_UP)) + break; + */ + lynx_rx_enable(sc, IRX_CH, + 0x00000000 | ch << 8, + 0x00000090 |(mask << 8), + 0x0, LYNX_DMA_EN_CH_CMP); + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cntl[IRX_CH].curr_pcl + &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_LINK; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * IRX_CH )); + break; + case SIOCSIFADDR: + mask = lynx_gen_isomask(ifp); + lynx_rx_enable(sc, IRX_CH, + #if 1 + 0x00000000 |(ac->media.firewire.broadcast << 8), + 0x00000090 |(mask << 8), + #else + 0x00000000, 0x00000090, + #endif + 0x0, LYNX_DMA_EN_CH_CMP); + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cntl[IRX_CH].curr_pcl + &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_LINK; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * IRX_CH )) + | ( LYNX_DMA0_HLT << ( 2 * IRX_CH )); + if(!(sc->fc.fw_flags & FWIP_UP)){ + firewire_ifinit(ac, ifa); + } + ifp->if_flags |= IFF_UP ; + sc->fc.fw_flags |= FWIP_UP; + break; + case SIOCRDCSR: + lynxintr->req.mem.data = read_reg((struct fw_softc *)sc, lynxintr->req.mem.addr); + break; + case SIOCWRCSR: + lynxintr->req.mem.data = write_reg((struct fw_softc *)sc, lynxintr->req.mem.addr, lynxintr->req.mem.data); + break; + case SIOCGETTLABEL: + lynxintr->req.pcbreq.data + = fw_get_tlabel(ifp, TLABEL_PCB, lynxintr->req.pcbreq.pcb); + break; + case SIOCRELTLABEL: + break; + case SIOCISOENA: + if(lynxintr->req.ch >= 0x100 ){ + err = EINVAL; + return err; + } + if( sc->fc.isoslot[lynxintr->req.pcbreq.data].type + != ISOSLOT_NULL){ + err = EBUSY; + return err; + } + sc->fc.isoslot[lynxintr->req.pcbreq.data].type + = ISOSLOT_PCB; + sc->fc.isoslot[lynxintr->req.pcbreq.data].resp.pcb + = lynxintr->req.pcbreq.pcb; + mask = lynx_gen_isomask(ifp); + + lynx_rx_enable(sc, IRX_CH, + ac->media.firewire.broadcast << 8, + 0x00000090 |(mask << 8), + 0x0, LYNX_DMA_EN_CH_CMP); + + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cntl[IRX_CH].curr_pcl + &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_LINK; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * IRX_CH )) + | ( LYNX_DMA0_HLT << ( 2 * IRX_CH )); + + ifp->if_flags |= IFF_UP; + break; + case SIOCISODIS: + if(lynxintr->req.pcbreq.data > 0x100 ){ + err = EINVAL; + return err; + } + + sc->fc.isoslot[lynxintr->req.pcbreq.data].type = ISOSLOT_NULL; + mask = lynx_gen_isomask(ifp); + + lynx_rx_enable(sc, IRX_CH, + ac->media.firewire.broadcast << 8, + 0x00000090 |(mask << 8), + 0x0, LYNX_DMA_EN_CH_CMP); + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cntl[IRX_CH].curr_pcl + &= ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[IRX_CH].cntl |= LYNX_DMA_LINK; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * IRX_CH )) + | ( LYNX_DMA0_HLT << ( 2 * IRX_CH )); + break; + case SIOCGIFADDR: + err = EINVAL; + case SIOCFWRESET: + lynx_ibr(sc); + break; + /* + case SIOCCYCMTR: + sc->base->link_cntl |= LYNX_LINK_CYCMASTER; + break; + case SIOCCYCSLV: + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + break; + */ + case SIOCDEBUGPHY: + if( lynxintr->req.mem.addr < 8){ + fun = tsb21lv_rddata(&sc->base->phy_access, + lynxintr->req.mem.addr); + lynxintr->req.mem.data = fun; + }else{ + err = EINVAL; + } + break; + case SIOCPCLSEQ: + if(lynxintr->req.ch <= LYNX_MAX_DMA_CH ){ + printf("q = 0x%x\n", sc->queued[lynxintr->req.ch]); + dump_pcl_seq(sc, lynxintr->req.ch); + }else{ + err = EINVAL; + } + break; + case DUMPRCV: + if(lynxintr->req.ch <= LYNX_MAX_DMA_CH ){ + printf("0x%08x 0x%08x\n", + vtophys(sc->pcl_last[lynxintr->req.ch]->next->pcl),sc->base->dma_cntl[lynxintr->req.ch].curr_pcl ); + }else{ + err = EINVAL; + } + break; + case DUMPDMA: + if(lynxintr->req.ch <= LYNX_MAX_DMA_CH ){ + dump_dma(sc, lynxintr->req.ch); + dump_pcl(sc, lynxintr->req.ch); + }else{ + err = EINVAL; + } + break; + case SIOCFWWRREG: + if(lynxintr->req.mem.addr <= 0xf24){ + reg = (lynxreg_t *)sc->base; + reg[lynxintr->req.mem.addr/4] + = lynxintr->req.mem.data; + lynxintr->req.mem.data + = reg[lynxintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + case SIOCFWRDREG: + if(lynxintr->req.mem.addr <= 0xf24){ + reg = (lynxreg_t *)sc->base; + lynxintr->req.mem.data = reg[lynxintr->req.mem.addr/4]; + }else{ + err = EINVAL; + } + break; + #if ARX_CH == 0 + case SIOCSNOOPON: + sc->base->link_cntl |= LYNX_SNOOP_ENABLE; + break; + case SIOCSNOOPOFF: + sc->base->link_cntl &= ~LYNX_SNOOP_ENABLE; + break; + #endif + default: + err = EINVAL; + } + /* Anyway send a packet and get a status */ + /* fill in PCL's */ + + return err; + } + void dump_fifo_ptr(struct lynx_softc *sc){ + printf("lynx%d fifo fifoptr 0x%08x 0x%08x\n", + LYNXARGS(sc), + sc->base->pci_fifo_port, + sc->base->link_fifo_port); + } + void dump_dma(struct lynx_softc *sc, int ch){ + lynxreg_t stat; + + printf("lynx%d dma ch %1x:dma regs 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x \n", + LYNXARGS(sc), + ch, + sc->base->dma_cntl[ch].stat, + sc->base->dma_cntl[ch].cntl, + sc->base->dma_cntl[ch].rdy, + sc->base->dma_cntl[ch].curr_stat, + sc->base->dma_diag, + sc->base->dma_rx_fifo_cnt, + sc->base->dma_global ); + printf("lynx%d dma ch %1x:pcl ptr Prev=0x%08x,Curr=0x%08x,Data=0x%08x\n", + LYNXARGS(sc), + ch, + sc->base->dma_cntl[ch].prev_pcl, + sc->base->dma_cntl[ch].curr_pcl, + sc->base->dma_cntl[ch].curr_dat); + stat = sc->base->dma_cntl[ch].stat; + printf("lynx%d dma ch %1x:status %s%s%s%s%s RX ch = %2x ", + LYNXARGS(sc), + ch, + stat & LYNX_DMA_SELFID ? "Self ID," : "", + stat & LYNX_DMA_RX_ISO_MODE ? "RX=ISO," : "RX=ASY,", + stat & LYNX_DMA_MSTR_ERR ? "MST ERR," : "", + stat & LYNX_DMA_PKT_ERR ? "PKT ERR," : "", + stat & LYNX_DMA_PKT_CMP ? "PKT Done," : "", + (stat & LYNX_DMA_RX_DMA_CH ) >> 21); + printf("RX=%s,", linkspeed[(LYNX_DMA_RX_SPEED & stat) >> 19]); + printf("Ack=%s(%x) ", + ackcode [((LYNX_DMA_ACKS | LYNX_DMA_ACK_TYPE)& stat) >> 14], + ((LYNX_DMA_ACKS | LYNX_DMA_ACK_TYPE)& stat) >> 14); + printf("txd=0x%03x ", stat & LYNX_DMA_TX_CNT); + printf("\n"); + + stat = sc->base->dma_cntl[ch].cntl; + printf("lynx%d dma ch %1x:control %s%s%s%s,%s,%s,%s%s%s", + LYNXARGS(sc), + ch, + stat & LYNX_DMA_CH_ENA ? "Enable," : "Disable,", + stat & LYNX_DMA_BSY ? "Busy," : "", + stat & LYNX_DMA_LINK ? "LINK on," : "LINK off,", + pclcode[(stat >>24) & 0xf], + pclcond[(stat >>20) & 0x7], + stat & LYNX_DMA_INT ? "INT=ENA," : "INT=DIS,", + stat & LYNX_DMA_LAST_BUF ? "Buf=LAST," : "", + stat & LYNX_DMA_WAIT_FOR_STAT ? "WAIT," : "", + stat & LYNX_DMA_BIG_ENDIAN ? "END=Big," : "END=Little,"); + printf("TX=%s,", linkspeed[(LYNX_DMA_TX_SPEED & stat) >> 14]); + printf("%s txd=0x%03x/PCL\n", + stat & LYNX_DMA_TX_ISO_MODE ? "TX=ISO," : "TX=ASY", + stat & LYNX_DMA_TX_BUF_CNT); + } + void dump_pcl_seq(struct lynx_softc *sc, int ch){ + struct lynxpcl *pcl; + int ipcl; + + pcl = sc->pcl_tr[ch][0].pcl; + for(ipcl = 0 ; ipcl < sc->npcl[ch] ; ipcl ++ ){ + printf("0x%02x 0x%08x 0x%08x\n", + ipcl, pcl[ipcl].pcl_next, pcl[ipcl].err_next); + } + return; + } + void dump_pcl(struct lynx_softc *sc, int ch){ + struct lynxpcl *pcl, *prev = NULL, *curr = NULL; + int ipcl; + + pcl = sc->pcl_tr[ch][0].pcl; + + for(ipcl = 0 ; ipcl < sc->npcl[ch] ; ipcl ++ ){ + if((sc->base->dma_cntl[ch].prev_pcl & 0xfffffff0) + == vtophys(&(pcl[ipcl]))){ + prev = &(pcl[ipcl]); + } + if((sc->base->dma_cntl[ch].curr_pcl & 0xfffffff0) + == vtophys(&(pcl[ipcl]))){ + curr = &(pcl[ipcl]); + } + } + if( prev != NULL ){ + printf("Previous PCL\n"); + print_pcl(prev, ch); + } + if( curr != NULL){ + printf("Current PCL\n"); + print_pcl(curr, ch); + } + if( curr == NULL && prev == NULL){ + printf("pcldump err ch = %d\n", ch); + } + return; + } + void print_pcl(struct lynxpcl *pcl, int ch){ + lynxreg_t stat; + + printf("pcl %d ch: regs Curr=0x%08x,Next=0x%08x,Err=0x%08x,Stat=0x%08x,Cntl=0x%08x,Data=0x%08x\n", + ch, + vtophys(pcl), + pcl->pcl_next, + pcl->err_next, + pcl->status, + pcl->data[0].cntl, + pcl->data[0].ptr ); + stat = pcl->status; + printf("pcl %d ch:%s%s%s%s%sRX ch=%x,", + ch, + stat & LYNX_PCL_SELFID ? "SelfID," : "", + stat & LYNX_PCL_ISOMODE ? "ISO," : "ASY,", + stat & LYNX_PCL_MSTERR ? "MST ERR," : "", + stat & LYNX_PCL_PKTERR ? "PKT ERR," : "", + stat & LYNX_PCL_PKTCMP ? "PKT Done," : "", + (stat & LYNX_PCL_RXCH )>>21 + ); + printf("Ack=%s(%x) ", + ackcode [((LYNX_DMA_ACKS | LYNX_DMA_ACK_TYPE)& stat) >> 14], + ((LYNX_DMA_ACKS | LYNX_DMA_ACK_TYPE)& stat) >> 14); + printf("\n"); + + stat = pcl->data[0].cntl; + printf("pcl %d ch:%s,", + ch, pclcode[(stat >>24) & 0xf]); + printf("%s,", pclcond[(stat >>20) & 0x7] ); + + printf("%s%s%s%s", + stat & LYNX_PCL_INT ? "INT," : "", + stat & LYNX_PCL_LASTBUF ? "LASTBUF," : "", + stat & LYNX_PCL_WAIT ? "WAIT," : "NOWAIT,", + stat & LYNX_PCL_BIGEND ? "End=Big," : "End=Little,"); + printf("TX=%s,", linkspeed[(LYNX_PCL_TX_SPEED & stat) >> 14]); + printf("%s%s TX=0x%x bytes\n", + stat & LYNX_PCL_MULTIISO ? "Multi ISO," : "", + stat & LYNX_PCL_TXISO ? "TX=ISO," : "TX=ASY,", + stat & LYNX_PCL_TXCNT ); + return; + } + void lynx_ibr(sc) + struct lynx_softc *sc; + { + u_int32_t fun; + /* Bus reset should be initiated and processed only by PHY chip set */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_IBR_REG); + fun |= FW_PHY_IBR; + fun = tsb21lv_wrdata(&sc->base->phy_access, FW_PHY_IBR_REG, fun); + } + void lynx_stop_rxdv(sc) + struct lynx_softc *sc; + { + sc->base->dma_cmp[DVRX_CH].w1_mask &= ~LYNX_DMA_EN_CH_CMP; + sc->base->dma_cntl[DVRX_CH].cntl &= ~LYNX_DMA_LINK; + sc->base->dma_cntl[DVRX_CH].cntl &= ~LYNX_DMA_CH_ENA; + } + void lynx_start_rxdv(sc) + struct lynx_softc *sc; + { + int ch; + if( sc->fc.dv.rklock ) return; /* avoid duplication */ + sc->fc.dv.rklock = 1; + + ch = (INITREG(&sc->fc, iPCR) >> 16) & 0x3f; + + sc->base->dma_cntl[DVRX_CH].cntl |= LYNX_DMA_CH_ENA; + sc->base->dma_cmp[DVRX_CH].w0_val = ch << 8; + sc->base->dma_cmp[DVRX_CH].w0_mask = 0x00000090 | (0x3f << 8); + sc->base->dma_cmp[DVRX_CH].w1_val = 0x0; + sc->base->dma_cmp[DVRX_CH].w1_mask = LYNX_DMA_EN_CH_CMP; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * DVRX_CH )) + | ( LYNX_DMA0_HLT << ( 2 * DVRX_CH )); + sc->base->dma_cntl[DVRX_CH].curr_pcl + =(lynxreg_t)vtophys(&(sc->pcl_tr[DVRX_CH][0].pcl[0])); + sc->base->dma_cntl[DVRX_CH].cntl |= LYNX_DMA_LINK; + sc->fc.dv.rklock = 0; + } + void lynx_start_txdv(sc) + struct lynx_softc *sc; + { + struct fw_softc *fc = &(sc->fc); + u_int i, i_cnt, size; + u_int32_t *ld; + u_int ch, len, iseq, seq; + struct dv_data *dv_buf; + u_int32_t cyc; + + if( fc->dv.wklock ) return; /* avoid duplicate */ + fc->dv.wklock = 1; + + dv_buf = fc->dv_buf; + + if( fc->dv_start == 0 ){ + /* attempt to get next frame */ + dv_buf->k_write + = (dv_buf->k_write + 1) % dv_buf->n_write; + if(dv_buf->k_write == dv_buf->a_write){ + dv_buf->k_write = + (dv_buf->k_write + dv_buf->n_write - 1) + % dv_buf->n_write; + } + } + iseq = sc->fc.dv_buf->k_write; + + sc->base->pci_int_ena |= + ( LYNX_DMA0_PCL << ( 2 * DVTX_CH )); + + ch = (INITREG(&sc->fc, oMPR) >> 24) & 0x3f; + len = sc->fc.dv_buf->write_len[iseq]; + if( len > (DVBUF - 1)){ + INITREG(&sc->fc, oPCR) &= ~DV_BROADCAST_ON; + sc->fc.dv.queued = 0; + sc->base->dma_cntl[DVTX_CH].cntl &= ~LYNX_DMA_LINK; + sc->base->dma_cntl[DVTX_CH].cntl &= ~LYNX_DMA_CH_ENA; + return; + } + if( fc->dv_end == 0){ + fc->dv_end = len; + } + if( fc->dv_end > len ){ + fc->dv_end = len; + } + if( fc->dv_start > fc->dv_end ){ + fc->dv_start = 0; + } + ld = &(sc->fc.dv_write_buf[iseq][fc->dv_start * S100_SZ/4]); + for( i = fc->dv_start ; i < fc->dv_end ; i++){ + size = ntohl(ld[0]) >> 16; + if(size >= S100_SZ - 4 ) size = S100_SZ - 4; + if( size < 8 ) size = 8; + sc->pcldvtx[iseq].pcl_tr[i+1].pcl->data[0].cntl + = LYNX_PCL_XMIT + | LYNX_PCL_TXISO | LYNX_PCL_LASTBUF | + ((size + 4) & 0xfff); + ld[0] = htonl((DV_ISOTAGCIP << 14) | + (TCODE_STREAM << 4)| size << 16 | (ch << 8)); + ld[1] = htonl((((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f) << 24) | + ((DVSIZE / 4 ) << 16 )| + (fc->dv.dbc & 0xff)); + seq = (ntohl(ld[3]) >> 24 ) & 0xf; + if( size > 8 ){ + sc->fc.dv.dbc++; + } + ld += S100_SZ/4; + if( i == (fc->dv_intr - 1)){ + sc->pcldvtx[iseq].pcl_tr[i].pcl->data[0].cntl + |= LYNX_PCL_INT; + sc->pcldvtx[iseq].pcl_tr[i + 1].pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + } else if( i < (len - 1)){ + sc->pcldvtx[iseq].pcl_tr[i + 1].pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + }else{ + sc->pcldvtx[iseq].pcl_tr[i].pcl->data[0].cntl + |= LYNX_PCL_INT; + sc->pcldvtx[iseq].pcl_tr[i + 1].pcl->pcl_next |= LYNX_DMA_PCL_EN; + } + } + if( i < len ){ + fc->dv_start = fc->dv_intr; + fc->dv_end = 0; + goto out; + }else{ + fc->dv_start = 0; + fc->dv_end = fc->dv_intr; + } + + ld = sc->fc.dv_write_buf[iseq]; + + i_cnt = 0; + while(sc->base->dma_cntl[DVTX_CH].cntl & LYNX_DMA_BSY){ + if(i_cnt ++ > 1000000 ) break; + } + + cyc = *(sc->fc.p_cycle_timer) & 0x01fff000; + cyc += sc->fc.dv_gap; + ld[2] = ( ld[2] & htonl(0xffff0000)) + | htonl(cyc & 0x0000ffff) ; + + if(!(sc->base->dma_cntl[DVTX_CH].cntl & LYNX_DMA_BSY)){ + sc->base->dma_cntl[DVTX_CH].curr_pcl = + vtophys(sc->pcldvtx[iseq].prev_pcl) & ~LYNX_DMA_PCL_EN; + sc->base->dma_cntl[DVTX_CH].cntl |= LYNX_DMA_LINK; + sc->base->dma_cntl[DVTX_CH].cntl |= LYNX_DMA_CH_ENA; + } + sc->fc.dv.queued--;if(sc->fc.dv.queued < 0 ) sc->fc.dv.queued = 0; + out: + sc->fc.dv.wklock = 0; + } + void lynx_reset(sc) + struct lynx_softc *sc; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + /* + * resetting PCI Lynx chip + */ + ifp->if_flags &= ~IFF_UP; + + + ifp->if_flags |= IFF_UP; + return; + } + #ifdef RX_DMA + int lynx_add_rx_buf(pcl_tr, oldm) + struct lynxpcl_tr *pcl_tr; + struct mbuf *oldm; + { + struct mbuf *m; + struct lynxpcl *pcl = pcl_tr->pcl; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m != NULL) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + if (oldm == NULL) + return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + } else { + if (oldm == NULL) + return 1; + m = oldm; + m->m_data = m->m_ext.ext_buf; + } + m->m_pkthdr.len = m->m_len = MCLBYTES; + + pcl_tr->mbhead = m; + pcl->data[0].ptr = vtophys(mtod(m, vm_offset_t)) ; + + /* move ptr forward in control header space */ + pcl->data[0].ptr += sizeof(fwcntl); + + pcl->data[0].cntl = LYNX_PCL_RCV_UPDATE | LYNX_PCL_INT + | LYNX_PCL_LASTBUF | (MCLBYTES - 4); + pcl->pcl_next &= ~LYNX_DMA_PCL_EN;; + return(m == oldm); + } + #else + int lynx_forward_rx_buf(pcl_tr) + struct lynxpcl_tr *pcl_tr; + { + struct lynxpcl *pcl = pcl_tr->pcl; + + pcl_tr->mbhead = 0; + pcl->data[0].ptr = vtophys(pcl_tr->buf) ; + /* move ptr forward in control header space */ + pcl->data[0].ptr += sizeof(fwcntl); + + pcl->data[0].cntl = LYNX_PCL_RCV_UPDATE | LYNX_PCL_INT + | LYNX_PCL_LASTBUF | MCLBYTES; + pcl->pcl_next &= ~LYNX_DMA_PCL_EN; + return(0); + } + #endif + static void lynx_rcv(sc, ch) + struct lynx_softc *sc; + int ch; + { + struct ifnet *ifp = (struct ifnet *)&sc->fc.ac; + struct mbuf *m; + int ipcl = 0; + struct lynxpcl_tr *pcl_tr; + struct fwhdr *ld; + #if 0 + dump_dma(sc, ch); + dump_pcl(sc, ch); + dump_fifo_ptr(sc); + #endif + rcvloop: + if((vtophys(sc->pcl_last[ch]->next->pcl) + == sc->base->dma_cntl[ch].curr_pcl ) && ipcl < sc->npcl[ch]){ + return; + } + pcl_tr = sc->pcl_last[ch]->next; + + ipcl++; + ifp->if_ipackets++; + #ifdef RX_DMA + if((m = pcl_tr->mbhead) == NULL ) + return; + if( lynx_add_rx_buf(pcl_tr, m) != 0) + return; + #else + MGETHDR(m, M_DONTWAIT, MT_DATA); + if(m == NULL){ + lynx_forward_rx_buf(pcl_tr); + return; + } + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + lynx_forward_rx_buf(pcl_tr); + return; + } + #endif + if((pcl_tr->pcl->status & 0xfff) != 0 ){ + m->m_pkthdr.len = m->m_len + = (pcl_tr->pcl->status & 0xfff) + sizeof(fwcntl); + }else{ + m->m_pkthdr.len = m->m_len = MCLBYTES; + } + #ifndef RX_DMA + bcopy(pcl_tr->buf, mtod(m, caddr_t), m->m_len); + #endif + m->m_pkthdr.rcvif = ifp; + if (ifp->if_bpf) { + struct mbuf m0; + u_int af = AF_UNSPEC; + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } + ld = mtod(m, struct fwhdr *); + if(pcl_tr->pcl->status & LYNX_PCL_ISOMODE ){ + ld->cntl[0] = PROTO_N1394ISOST; + fw_stream_input(ifp, m); + }else if (pcl_tr->pcl->status & LYNX_PCL_SELFID ){ + if( m->m_pkthdr.len < MCLBYTES ){ + sc->fc.sid_cnt = 1; + fw_sid_input(ifp, m); + }else{ + m_freem(m); + } + }else{ + ld->cntl[0] = PROTO_N1394ASYRQ; + fw_asy_input(ifp, m); + } + #ifndef RX_DMA + lynx_forward_rx_buf(pcl_tr); + #endif + pcl_tr->pcl->status &= ~(0xf << 14); + + sc->base->dma_cntl[ch].stat &= ~LYNX_DMA_TX_CNT; + + pcl_tr->pcl->pcl_next |= 0x01; + sc->pcl_last[ch]->pcl->pcl_next &= ~0x01; + sc->pcl_last[ch] = pcl_tr; + sc->pcl_last[ch]->next->pcl->pcl_next &= ~0x01; + + goto rcvloop; + } + #define RESET_WORK_AROUND + #undef RESET_WORK_AROUND + void lynx_busreset(fc) + struct fw_softc *fc; + { + struct lynx_softc *sc = (struct lynx_softc *)fc; + struct arpcom *ac = (struct arpcom *)fc; + int fun, ir, i, node, gap, spd, c, pwr, p0, p1, p2; + #ifdef RESET_WORK_AROUND + int cntl[LYNX_MAX_DMA_CH]; + #endif + sc->base->link_int_ena &= + ~(LYNX_INT_CYC_ARB_FAILED | LYNX_INT_CYC_LOST ); + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + + INITREG(&sc->fc, STATE_CLEAR) + = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ; + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + /* Stopping all DMA channel processing */ + #ifdef RESET_WORK_AROUND + sc->base->dma_diag |= LYNX_DMA_TESTEN; + #endif + for( i = 0 ; i < LYNX_MAX_DMA_CH ; i++){ + sc->dma_ch[i] = 0; + /* + following reset function may be nesessary procedure for sending process + after busrest, but following sequence also stop recieving channels. + Stopped channel should be recovered automatically + */ + #ifdef RESET_WORK_AROUND + cntl[i] = sc->base->dma_cntl[i].cntl + & (LYNX_DMA_CH_ENA | LYNX_DMA_LINK); + sc->base->dma_cntl[i].cntl &= ~LYNX_DMA_CH_ENA; + sc->base->dma_cntl[i].stat |= LYNX_DMA_MSTR_ERR; + sc->base->dma_cntl[i].cntl &= ~LYNX_DMA_LINK; + #endif + } + #ifdef RESET_WORK_AROUND + sc->base->dma_diag &= ~LYNX_DMA_TESTEN; + sc->base->link_cntl |= LYNX_LINK_RSTTX; + sc->base->fifo_token_cntl |= LYNX_ATF_FLUSH | LYNX_ITF_FLUSH; + #endif + sc->init = 0; + /* Clear Reciever and Transmitter Logic */ + #if 0 + sc->base->link_cntl |= LYNX_LINK_RSTTX|LYNX_LINK_RSTRX; + #else + sc->base->link_cntl |= LYNX_LINK_RSTTX; + #endif + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_GC_REG); + gap = 0x3f & fun; + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_SPD_REG); + spd = (fun >> 6) & 0x3; + + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P1_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p2 = 3; + }else{ + p2 = 2; + } + }else{ + p2 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P2_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p1 = 3; + }else{ + p1 = 2; + } + }else{ + p1 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_P3_REG); + if(fun & 0x4){ + if(fun & 0x8){ + p0 = 3; + }else{ + p0 = 2; + } + }else{ + p0 = 1; + } + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_IR_REG); + ir = (fun >> 4 ) & 0x1; + c = fun & 0x1; + #ifdef PHYBUG + /* + * Fujitsu Lab.'s Lynx card returns valid contender bit in Self ID phase. + * But, PHY register's status is not set corresponding bit. + */ + if(pci_conf_read(sc->tag, 0x2c) == 0){ + c = 1; + } + #endif /* PHYBUG */ + pwr = 0x0 & 0x07; + /* + ** Checking whether root node or not. If this node is root, the Cycle + ** master bit is set. + */ + fun = tsb21lv_rddata(&sc->base->phy_access, FW_PHY_PHYSID_REG); + if(fun & 0x02){ + printf("This host is CYCLEMASTER\n"); + sc->base->link_cntl |= LYNX_LINK_CYCMASTER; + }else{ + sc->base->link_cntl &= ~LYNX_LINK_CYCMASTER; + } + node = 0x3f & (fun >> 2); + sc->base->link_bus_node = node << 16; + INITREG(&sc->fc, NODE_IDS) = sc->base->link_bus_node; + + if_fwbusreset(&sc->fc); + #if 0 + if(c){ + /* This machine is IRM candidate */ + sc->fc.irm = (INITREG(&sc->fc, NODE_IDS) >> 16 )& 0x3f; + }else{ + sc->fc.irm = 0x3f; + } + #ifdef NOIRM + sc->fc.irm = 0x3f; + #endif + INITREG(&sc->fc, BUS_MGR_ID) = 0x3f; + #endif + printf("pcilynx: node 0x%08x\n", INITREG(&sc->fc, NODE_IDS)); + + + /* Initialize base csr register */ + + sc->fc.sid_cnt = 1; + sc->fc.sid_buf[0] = + ( 2 << 30 ) | ( node << 24 ) | 1 << 22 + | gap << 16 | spd << 14 | c << 11 | pwr << 8 + | p0 << 6 | p1 << 4 | p2 << 2 | ir << 1; + sc->fc.sid_buf[1] = ~sc->fc.sid_buf[0]; + + /* Lnk initialization is ready */ + + sc->base->link_cntl |= LYNX_LINK_TX_ASY_EN | + LYNX_LINK_CYCTIMEREN | LYNX_LINK_RX_ASY_EN | + LYNX_RCV_COMP_VALID | LYNX_LINK_RX_ISO_EN | + LYNX_LINK_TX_ISO_EN ; + #if 0 + sc->base->link_cntl |= LYNX_LINK_RSTTX|LYNX_LINK_RSTRX; + sc->base->fifo_token_cntl |= LYNX_ATF_FLUSH | LYNX_ITF_FLUSH | LYNX_GRF_FLUSH; + #else + sc->base->link_cntl |= LYNX_LINK_RSTTX; + sc->base->fifo_token_cntl |= LYNX_ATF_FLUSH | LYNX_ITF_FLUSH ; + #endif + INITREG(&sc->fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 ); + INITREG(&sc->fc, STATE_SET) = INITREG(&sc->fc, STATE_CLEAR); + #ifdef RESET_WORK_AROUND + for( i = 0 ; i < LYNX_MAX_DMA_CH ; i++){ + sc->base->dma_cntl[i].cntl |= cntl[i]; + } + #endif + } + #endif /* !defined(__FreeBSD__) || (NLYNX > 0 && NPCI > 0) */ diff -r -c -N sys44.orig/dev/firewire/lynxreg.h sys/dev/firewire/lynxreg.h *** sys44.orig/dev/firewire/lynxreg.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/lynxreg.h Tue Oct 9 21:55:19 2001 *************** *** 0 **** --- 1,451 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: lynxreg.h,v 1.1.2.1 2000/06/04 17:19:06 ikob Exp $ + * + */ + #define LYNX_VENDORID_TI 0x104c + #define LYNX_DEVICE_PCILYNX 0x8000 + + #define LYNXPCLBUF 12 + + typedef volatile u_int32_t lynxreg_t; + struct lynxpcl { + u_int32_t pcl_next; + u_int32_t err_next; + lynxreg_t dummy; + #define LYNX_PCL_SELFID (1<<31) + #define LYNX_PCL_ISOMODE (1<<30) + #define LYNX_PCL_MSTERR (1<<29) + #define LYNX_PCL_PKTERR (1<<28) + #define LYNX_PCL_PKTCMP (1<<27) + #define LYNX_PCL_RXCH (63<<21) + #define LYNX_PCL_RXSPEED (3<<19) + #define LYNX_PCL_ACK (15<<15) + #define LYNX_PCL_ACK_TYPE (1<<14) + #define LYNX_PCL_TXDCNT (0xfff) + lynxreg_t status; + lynxreg_t remain; /* used for RCV UPDATE and LBUS */ + lynxreg_t nextdata; /* used for RCV UPDATE */ + #define LYNX_PCL_NOP (0x0<<24) + #define LYNX_PCL_RCV (0x1<<24) + #define LYNX_PCL_XMIT (0x2<<24) + #define LYNX_PCL_LOAD (0x3<<24) + #define LYNX_PCL_STOREQ (0x4<<24) + #define LYNX_PCL_STORE0 (0x5<<24) + #define LYNX_PCL_STORE1 (0x6<<24) + #define LYNX_PCL_BR (0x7<<24) + #define LYNX_PCL_TOLBUS (0x8<<24) + #define LYNX_PCL_TOPCI (0x9<<24) + #define LYNX_PCL_RCV_UPDATE (0xA<<24) + #define LYNX_PCL_STORED (0xB<<24) + #define LYNX_PCL_UXMIT (0xC<<24) + #define LYNX_PCL_ADD (0xD<<24) + #define LYNX_PCL_CMP (0xE<<24) + #define LYNX_PCL_SWAP_CMP (0xF<<24) + + #define LYNX_PCL_NOWAIT (0x0<<20) + #define LYNX_PCL_WAITDMA_1 (0x1<<20) + #define LYNX_PCL_WAITDMA_0 (0x2<<20) + #define LYNX_PCL_WAITEX_1 (0x3<<20) + #define LYNX_PCL_WAITEX_0 (0x4<<20) + #define LYNX_PCL_WAITGP_1 (0x5<<20) + #define LYNX_PCL_WAITGP_0 (0x6<<20) + #define LYNX_PCL_INT (1<<19) + #define LYNX_PCL_LASTBUF (1<<18) + #define LYNX_PCL_WAIT (1<<17) + #define LYNX_PCL_BIGEND (1<<16) + #define LYNX_PCL_TX_SPEED (3<<14) + #define LYNX_PCL_TX_S100 (0<<14) + #define LYNX_PCL_TX_S200 (1<<14) + #define LYNX_PCL_TX_S400 (2<<14) + #define LYNX_PCL_MULTIISO (1<<13) + #define LYNX_PCL_TXISO (1<<12) + #define LYNX_PCL_TXCNT (0xfff) + struct pcl_data { + u_int32_t cntl; + u_int32_t ptr; + }; + struct pcl_data data[13]; + }; + + struct tsb1221_registers { + lynxreg_t pci_conf[0x10]; /* PCI configuration registers */ + /* 0x0, 0x4, 0x8, 0xc */ + /* 0x10, 0x14, 0x18, 0x1c */ + /* 0x20, 0x24, 0x28, 0x2c */ + /* 0x30, 0x34, 0x38, 0x3c */ + lynxreg_t misc_cntl; /* Misc. control 0x40 */ + #define LYNX_MAXRTY_CNT (15<<12) + #define LYNX_ENA_MST_RTY (1<<11) + #define LYNX_ENA_POST_WR (1<<7) /* Must be zero */ + #define LYNX_ENA_SLV_BURST (1<<6) /* Must be zero */ + #define LYNX_PAUSE_MSTR (1<<3) + #define LYNX_AUTOBOOT_IN (1<<2) + #define LYNX_SET_FORCE_INT (1<<1) + #define LYNX_SWRST (1<<0) + + lynxreg_t seeprom_cntl; /* SEEPROM control 0x44 */ + #define LYNX_EEPERR (1<<9) + #define LYNX_EEPCHKERR (1<<8) + #define LYNX_NOTPRS (1<<7) + #define LYNX_EEPCLK (1<<6) + #define LYNX_EEPENA (1<<5) + #define LYNX_EEPDAT (1<<4) + #define LYNX_EEPSTARTED (1<<2) + #define LYNX_TIMER_5USEC (1<<0) + + lynxreg_t pci_int_stat; /* PCI interrupt status 0x48 */ + #define LYNX_INT_PEND (1<<31) + #define LYNX_FRC_INT (1<<30) + #define LYNX_SLV_ADDR_PERR (1<<28) + #define LYNX_SLV_DAT_PERR (1<<27) + #define LYNX_MST_DAT_PERR (1<<26) + #define LYNX_MST_DEV_TO (1<<25) + #define LYNX_MST_RETRY_TO (1<<24) + #define LYNX_INTERNAL_SLV_TO (1<<23) + #define LYNX_AUX_TO (1<<18) + #define LYNX_AUX_INT (1<<17) + #define LYNX_P1394_INT (1<<16) + #define LYNX_DMA4_PCL (1<<9) + #define LYNX_DMA4_HLT (1<<8) + #define LYNX_DMA3_PCL (1<<7) + #define LYNX_DMA3_HLT (1<<6) + #define LYNX_DMA2_PCL (1<<5) + #define LYNX_DMA2_HLT (1<<4) + #define LYNX_DMA1_PCL (1<<3) + #define LYNX_DMA1_HLT (1<<2) + #define LYNX_DMA0_PCL (1<<1) + #define LYNX_DMA0_HLT (1<<0) + + lynxreg_t pci_int_ena; /* PCI interrupt enable 0x4c */ + #define LYNX_FRC_INT_EN (1<<30) + #define LYNX_SLV_ADDR_PERR_EN (1<<28) + #define LYNX_SLV_DAT_PERR_EN (1<<27) + #define LYNX_MST_DAT_PERR_EN (1<<26) + #define LYNX_MST_DEV_TO_EN (1<<25) + #define LYNX_MST_RETRY_TO_EN (1<<24) + #define LYNX_INTERNAL_SLV_TO_EN (1<<23) + #define LYNX_AUX_TO_EN (1<<18) + #define LYNX_AUX_INT_EN (1<<17) + #define LYNX_P1394_INT_EN (1<<16) + #define LYNX_DMA4_PCL_EN (1<<9) + #define LYNX_DMA4_HLT_EN (1<<8) + #define LYNX_DMA3_PCL_EN (1<<7) + #define LYNX_DMA3_HLT_EN (1<<6) + #define LYNX_DMA2_PCL_EN (1<<5) + #define LYNX_DMA2_HLT_EN (1<<4) + #define LYNX_DMA1_PCL_EN (1<<3) + #define LYNX_DMA1_HLT_EN (1<<2) + #define LYNX_DMA0_PCL_EN (1<<1) + #define LYNX_DMA0_HLT_EN (1<<0) + + lynxreg_t pci_test; /* PCI test 0x50 */ + #define LYNX_TEST_OUTPUT (1<<13) + #define LYNX_TEST_MUX_SEL (31<<8) + #define LYNX_TEST_STATUS (1<<5) + #define LYNX_TEST_SEEPROM (1<<4) + #define LYNX_SET_OUTPUT_EN (1<<3) + #define LYNX_SET_OUTPUT_FF (1<<2) + #define LYNX_DISABLE_DRIVERS (1<<1) + #define LYNX_TEST_REG_EN (1<<0) + + lynxreg_t dummy1[0x17]; /* 0x54, 0x58, 0x5c */ + /* 0x60, 0x64, 0x68, 0x6c */ + /* .................... */ + /* 0xa0, 0xa4, 0xa8, 0xac */ + + lynxreg_t localbus_cntl; /* Local Bus control 0xb0 */ + lynxreg_t localbus_addr; /* Local Bus address 0xb4 */ + lynxreg_t gpio10_cntl; /* GPIO[1:0] control 0xb8 */ + lynxreg_t gpio32_cntl; /* GPIO[3:2] control 0xbc */ + lynxreg_t gpio_data[0x10];/* GPIO data r/w port, except */ + /* of gpio_data[0] is read only */ + /* 0xc0, 0xc4, 0xc8, 0xcc */ + /* 0xd0, 0xd4, 0xd8, 0xdc */ + /* 0xe0, 0xe4, 0xe8, 0xec */ + /* 0xf0, 0xf4, 0xf8, 0xfc */ + struct lynxdmacntl { + lynxreg_t prev_pcl; /* Previous PCL addr */ + lynxreg_t curr_pcl; /* Current PCL addr */ + lynxreg_t curr_dat; /* Current data addr */ + lynxreg_t stat; /* DMA status */ + lynxreg_t cntl; /* DMA cntl */ + lynxreg_t rdy; /* DMA ready */ + lynxreg_t curr_stat; /* Current DMA status */ + lynxreg_t dummy; /* padding */ + }; + #define LYNX_DMA_PCL_EN (1<<0) + + #define LYNX_DMA_SELFID (1<<31) + #define LYNX_DMA_RX_ISO_MODE (1<<30) + #define LYNX_DMA_MSTR_ERR (1<<29) + #define LYNX_DMA_PKT_ERR (1<<28) + #define LYNX_DMA_PKT_CMP (1<<27) + #define LYNX_DMA_RX_DMA_CH (63<<21) + #define LYNX_DMA_RX_SPEED (3<<19) + #define LYNX_DMA_ACKS (15<<15) + #define LYNX_DMA_ACK_TYPE (1<<14) + #define LYNX_DMA_TX_CNT (0x1fff) + + #define LYNX_DMA_CH_ENA (1<<31) + #define LYNX_DMA_BSY (1<<30) + #define LYNX_DMA_LINK (1<<29) + #define LYNX_DMA_CMD (15<<24) + #define LYNX_DMA_COND (7<<20) + #define LYNX_DMA_WAIT_SEL (7<<20) + #define LYNX_DMA_INT (1<<19) + #define LYNX_DMA_LAST_BUF (1<<18) + #define LYNX_DMA_WAIT_FOR_STAT (1<<17) + #define LYNX_DMA_BIG_ENDIAN (1<<16) + #define LYNX_DMA_TX_SPEED (3<<14) + #define LYNX_DMA_MULTI_ISO_PKT (1<<13) + #define LYNX_DMA_TX_ISO_MODE (1<<12) + #define LYNX_DMA_TX_BUF_CNT (0xfff) + + #define LYNX_DMA_STAT (255<<24) + #define LYNX_DMA_LOCK (1<<20) + #define LYNX_DMA_LIST_OFFSET (31<<16) + #define LYNX_DMA_STATE_FLAG (1<<15) + #define LYNX_DMA_CURRENT_CONTEXT (63<<0) + /* Only lower 5 channel can be used now, TI say other channel will be */ + /* implemented and is reserved future. */ + #define LYNX_MAX_DMA_CH 5 + struct lynxdmacntl dma_cntl[64]; + /* 0x100, 0x104, 0x108, 0x10c */ + /* 0x110, 0x114, 0x118, 0x11c */ + /* .................... */ + /* 0x8e0, 0x8e4, 0x8e8, 0x80c */ + /* 0x8f0, 0x8f4, 0x8f8, 0x8fc */ + lynxreg_t dma_diag; /* DMA diag. test control 0x900 */ + #define LYNX_DMA_MASTER_BYTE_CNT (255<<24) + #define LYNX_DMA_HIGH_WATER_MARK (255<<16) + #define LYNX_DMA_ADDRTEST (1<<14) + #define LYNX_DMA_TEST_MUX_SEL_OUT (1<<13) + #define LYNX_DMA_TEST_MUX_SEL (31<<8) + #define LYNX_DMA_CHANNEL_SEL (63<<1) + #define LYNX_DMA_TESTEN (1<<0) + + lynxreg_t dma_rx_fifo_cnt; /* DMA RX FIFO count 0x904 */ + #define LYNX_DMA_REMAIN_CNT (0x1ffff) + + lynxreg_t dma_global; /* DMA global register 0x908 */ + #define LYNX_DMA_BOUND (31<<24) + #define LYNX_DMA_FIFO_FLUSH (1<<2) + #define LYNX_DMA_PREV_VALID (1<<1) + #define LYNX_DMA_RETRY (1<<0) + + lynxreg_t dummy2[0x3d]; /* 0x908, 0x90c */ + /* 0x910, 0x914, 0x918, 0x91c */ + /* .................... */ + /* 0x9e0, 0x9e4, 0x9e8, 0x90c */ + /* 0x9f0, 0x9f4, 0x9f8, 0x9fc */ + lynxreg_t fifo_size; /* FIFO size 0xa00 */ + #define LYNX_ITF_FIFOSZ (255<<16) + #define LYNX_ATF_FIFOSZ (255<<8) + #define LYNX_GRF_FIFOSZ (255<<0) + + lynxreg_t pci_fifo_port; /* PCI side FIFO port 0xa04 */ + lynxreg_t link_fifo_port; /* Link side FIFO port 0xa08 */ + #define LYNX_ITF_WAB_L (1<<26) + #define LYNX_ATF_WAB_L (1<<25) + #define LYNX_GRF_WAB_L (1<<24) + #define LYNX_ITF_WPTR (255<<16) + #define LYNX_ATF_WPTR (255<<8) + #define LYNX_GRF_WPTR (255<<0) + + lynxreg_t fifo_token_stat; /* FIFO token status 0xa0c */ + #define LYNX_GRF_FCT32 (1<<1) + #define LYNX_TF_FCT32 (0<<1) + + lynxreg_t fifo_token_cntl; /* FIFO token cntl 0xa10 */ + #define LYNX_FIFO_TEST_MUX (15<<8) + #define LYNX_GRF_FLUSH (1<<4) + #define LYNX_ITF_FLUSH (1<<3) + #define LYNX_ATF_FLUSH (1<<2) + #define LYNX_FIFO_BIG_ENDIAN (1<<1) + #define LYNX_FCT33_WR (1<<0) + + lynxreg_t atf_itf_cntl; /* ATF-ITF cntl 0xa14 */ + #define LYNX_ATF_FIFOTH (255<<8) + #define LYNX_GRF_FIFOTH (255<<0) + lynxreg_t dummy3[0x2]; /* 0xa18, 0xa1c */ + lynxreg_t gnl_rx_fifo[2]; /* General rx FIFO 0xa20, 0xa24 */ + lynxreg_t dummy4[0x2]; /* 0xa28, 0xa2c */ + lynxreg_t asy_rx_fifo[2]; /* Asynch. rx FIFO 0xa30, 0xa34 */ + lynxreg_t dummy5[0x2]; /* 0xa38, 0xa3c */ + lynxreg_t iso_rx_fifo[2]; /* ISO. rx FIFO 0xa40, 0xa44 */ + lynxreg_t dummy6[0x2e]; /* 0xa48, 0xa4c */ + /* 0xa50, 0xa54, 0xa58, 0xa5c */ + /* .................... */ + /* 0xae0, 0xae4, 0xae8, 0xa0c */ + /* 0xaf0, 0xaf4, 0xaf8, 0xafc */ + struct lynxdmacmp { + lynxreg_t w0_val; /* Word 0 receive packet value */ + lynxreg_t w0_mask; /* Word 0 receive packet mask */ + lynxreg_t w1_val; /* Word 1 receive packet value */ + lynxreg_t w1_mask; /* Word 1 receive packet mask */ + }; + struct lynxdmacmp dma_cmp[64]; /* DMA comparator registers */ + /* 0xb00, 0xb04, 0xb08, 0xb0c */ + /* 0xb10, 0xb14, 0xb18, 0xb1c */ + /* .................... */ + /* 0xee0, 0xee4, 0xee8, 0xe0c */ + /* 0xef0, 0xef4, 0xef8, 0xefc */ + #define LYNX_DMA_W0_F1 (0xffff<<16) + #define LYNX_DMA_W0_F2 (0xff<<8) + #define LYNX_DMA_W0_F3 (0xf<<4) + #define LYNX_DMA_W0_F4 (0xf<<0) + #define LYNX_DMA_W1_F1 (0xffff<<16) + #define LYNX_DMA_DEST_ID_SEL (31<<11) + #define LYNX_DMA_SELF_ID_EN (1<<10) + #define LYNX_DMA_EN_DIRECT_ADR (1<<9) + #define LYNX_DMA_EN_CH_CMP (1<<8) + #define LYNX_DMA_WRITE_REQ_ACK_SEL (1<<7) + + lynxreg_t link_bus_node; /* Bus and node address 0xf00 */ + #define LYNX_LINK_BUS_ID (0x3ff<<22) + #define LYNX_LINK_NODE_ID (0x63<<16) + + lynxreg_t link_cntl; /* Link control register 0xf04 */ + #define LYNX_LINK_BUSY_CNTRL (1<<29) + #define LYNX_LINK_TX_ISO_EN (1<<26) + #define LYNX_LINK_RX_ISO_EN (1<<25) + #define LYNX_LINK_TX_ASY_EN (1<<24) + #define LYNX_LINK_RX_ASY_EN (1<<23) + #define LYNX_LINK_RSTTX (1<<21) + #define LYNX_LINK_RSTRX (1<<20) + #define LYNX_LINK_CYCMASTER (1<<11) + #define LYNX_LINK_CYCSOURCE (1<<10) + #define LYNX_LINK_CYCTIMEREN (1<<9) + #define LYNX_RCV_COMP_VALID (1<<7) + #define LYNX_SNOOP_ENABLE (1<<6) + + lynxreg_t cycle_timer; /* Cycle timer 0xf08 */ + #define LYNX_LINK_CYCLE_SECONDS (127<<25) + #define LYNX_LINK_CYCLE_SECONDS (127<<25) + + lynxreg_t phy_access; /* Physical Layer access 0xf0c */ + #define TSB21_RDPHY (1<<31) + #define TSB21_WRPHY (1<<30) + #define TSB21_REGADDR 24 + #define TSB21_WRDATA 16 + #define TSB21_RDADDR 8 + #define TSB21_RDDATA 0 + + lynxreg_t diag_test; /* Diag. test 0xf10 */ + #define LYNX_LINK_CH_MATCH (1<<14) + #define LYNX_LINK_DMA_CH_NO (63<<8) + #define LYNX_GRF_UFLOW_TST_STB (1<<7) + #define LYNX_ATF_UFLOW_TST_STB (1<<6) + #define LYNX_ITF_UFLOW_TST_STB (1<<5) + #define LYNX_TESTMUXSEL (255<<1) + #define LYNX_DIAG1394EN (1<<0) + + lynxreg_t link_int_stat; /* LL interrupt stat 0xf14 */ + lynxreg_t link_int_ena; /* LL interrupt enable 0xf18 */ + #define LYNX_INT_LINK_INT (1<<31) + #define LYNX_INT_PHY_TIMEOUT (1<<30) + #define LYNX_INT_PHY_REG_RCVD (1<<29) + #define LYNX_INT_PHY_BUSRESET (1<<28) + #define LYNX_INT_TX_RDY (1<<26) + #define LYNX_INT_RX_DATA_RDY (1<<25) + #define LYNX_INT_IT_STUCK (1<<20) + #define LYNX_INT_AT_STUCK (1<<19) + #define LYNX_INT_SNTRJ (1<<17) + #define LYNX_INT_HDR_ERR (1<<16) + #define LYNX_INT_TC_ERR (1<<15) + #define LYNX_INT_CYC_SEC (1<<11) + #define LYNX_INT_CYC_STRT (1<<10) + #define LYNX_INT_CYC_DONE (1<<9) + #define LYNX_INT_CYC_PEND (1<<8) + #define LYNX_INT_CYC_LOST (1<<7) + #define LYNX_INT_CYC_ARB_FAILED (1<<6) + #define LYNX_INT_GRF_OVER_FLOW (1<<5) + #define LYNX_INT_ITF_UNDERFLOW (1<<4) + #define LYNX_INT_ATF_UNDERFLOW (1<<3) + #define LYNX_INT_IARB_FAILED (1<<0) + + lynxreg_t rty_cnt_int; /* Busy retry count 0xf1c */ + #define LYNX_BUSY_RETRY_DLY (255<<8) + #define LYNX_BUSY_RETRY_CNT (255<<0) + + lynxreg_t llc_state; /* LLC state monitor 0xf20 */ + #define LYNX_TX_IFC_STATE (15<<26) + #define LYNX_RX_ST_IFC_STATE (3<<24) + #define LYNX_RX_DT_IFC_STATE (7<<21) + #define LYNX_RCV_ACK_STATE (7<<18) + #define LYNX_LREQ_STATE (15<<14) + #define LYNX_RCV_STATE (31<<9) + #define LYNX_TRN_STATE (63<<3) + #define LYNX_CM_STATE (7<<0) + + lynxreg_t fifo_err; /* fifo error counter 0xf24 */ + #define LYNX_ITF_UNDERFLOW (255<<16) + #define LYNX_ATF_UNDERFLOW (255<<8) + #define LYNX_GRF_UNDERFLOW (255<<0) + }; + + struct lynxpcl_tr{ + struct lynxpcl_tr *next; + struct mbuf *mbhead; + struct lynxpcl *pcl; + caddr_t buf; + caddr_t buf2; + }; + + /* + * PCILynx info structure. + */ + struct lynx_softc { + struct fw_softc fc; + volatile struct tsb1221_registers *base; + int init; + u_int32_t flags; + struct lynxpcl_tr *pcl_tr[LYNX_MAX_DMA_CH]; + struct lynxpcl_tr *pcl_last[LYNX_MAX_DMA_CH]; + struct lynxpcl_tr *pcl_first[LYNX_MAX_DMA_CH]; + struct { + struct lynxpcl_tr *pcl_tr; + struct lynxpcl *prev_pcl; + }pcldvtx[16], pcldvrx[16]; + int npcl[LYNX_MAX_DMA_CH]; + int queued[LYNX_MAX_DMA_CH]; + int dma_ch[LYNX_MAX_DMA_CH]; + }; diff -r -c -N sys44.orig/dev/firewire/netfw.c sys/dev/firewire/netfw.c *** sys44.orig/dev/firewire/netfw.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/netfw.c Tue Oct 9 21:55:20 2001 *************** *** 0 **** --- 1,778 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: netfw.c,v 1.1.2.1 2000/06/04 17:19:06 ikob Exp $ + * + */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + + #include + #include + + static int n1394_usr_attach __P((struct socket *, int, struct proc *)); + static int n1394_usr_detach __P((struct socket *)); + static int n1394_usr_connect __P((struct socket *, struct sockaddr *, + struct proc *)); + static int n1394_usr_disconnect __P((struct socket *)); + static int n1394_usr_shutdown __P((struct socket *)); + static int n1394_usr_send __P((struct socket *, int, struct mbuf *, + struct sockaddr *, struct mbuf *, + struct proc *)); + static int n1394_usr_peeraddr __P((struct socket *, struct sockaddr **)); + static int n1394_usr_control __P((struct socket *, u_long, caddr_t, + struct ifnet *, struct proc *)); + static int n1394_usr_abort __P((struct socket *)); + static int n1394_usr_bind __P((struct socket *, struct sockaddr *, + struct proc *)); + static int n1394_usr_sockaddr __P((struct socket *, struct sockaddr **)); + + static int n1394_ioctl __P((struct socket *, int, caddr_t)); + + struct pr_usrreqs n1394_usrreqs = { + n1394_usr_abort, pru_accept_notsupp, n1394_usr_attach, n1394_usr_bind, + n1394_usr_connect, pru_connect2_notsupp, n1394_usr_control, + n1394_usr_detach, n1394_usr_disconnect, pru_listen_notsupp, + n1394_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, + n1394_usr_send, pru_sense_null, n1394_usr_shutdown, + n1394_usr_sockaddr, sosend, soreceive, sopoll + }; + + static int + n1394_usr_attach(struct socket *so, int proto, struct proc *p) + { + struct n1394pcb *n1394pcb; + int error = 0; + int s = splnet(); + + n1394pcb = (struct n1394pcb *) so->so_pcb; + + if (n1394pcb) { + error = EISCONN; + goto out; + } + + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, 4096, 4096); + if (error) + goto out; + } + + so->so_pcb = (caddr_t) (n1394pcb = n1394p_alloc(M_WAITOK)); + n1394pcb->n1394p_socket = so; + out: + splx(s); + return(error); + } + static int + n1394_usr_detach(struct socket *so) + { + struct n1394pcb *n1394pcb; + int error = 0; + int s = splnet(); + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + n1394pcb_free(n1394pcb, N1394P_DESTROY); /* drain */ + so->so_pcb = NULL; + sofree(so); + out: + splx(s); + return (error); + } + + void n1394pcb_free(n1394pcb, op) + struct n1394pcb *n1394pcb; + int op; + + { + int s, i; + struct ifnet *ifp; + struct fw_softc *fc; + struct fw_bind fwbind; + + ifp = n1394pcb->n1394p_ifp; + if (ifp != NULL && ifp->if_output == fw_output) { + fc = (struct fw_softc *)ifp->if_softc; + fwbind.type = FWBIND_PCB; + fwbind.resp.pcb = n1394pcb; + fw_bindremove(fc, fwbind); + /* + for( i = 0 ; i < FW_MAXREGBIND ; i ++){ + if( fc->bind_list[i].type == FWBIND_PCB && + fc->bind_list[i].resp.pcb == n1394pcb ){ + fc->bind_list[i].type = FWBIND_NULL; + break; + } + } + */ + } + + s = splimp(); + if ((n1394pcb->n1394p_flags & N1394P_FREE) == 0) { + LIST_REMOVE(n1394pcb, pcblist); + n1394pcb->n1394p_flags = N1394P_FREE; + } + if (op == N1394P_DESTROY) { + if (n1394pcb->n1394p_inq) { + n1394pcb->n1394p_flags = N1394P_DRAIN; + /* flag for distruction */ + } else { + FREE(n1394pcb, M_PCB); /* kill it! */ + } + } + splx(s); + } + + static int + n1394_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) + { + struct n1394pcb *n1394pcb; + struct sockaddr_n1394 *sn1394; + struct fwintreq lpi; + struct fwisohdr *ilh; + struct fwasyhdr *alh; + + struct ifnet *ifp; + + int error = 0; + int s2, s = splnet(); + int proto = so->so_proto->pr_protocol; + int type = so->so_proto->pr_type; + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + + /* + * validate nam and n1394pcb + */ + #if 0 + if (nam->m_len != sizeof(*sn1394)) { + error = EINVAL; + break; + } + #endif + sn1394 = (struct sockaddr_n1394 *)nam; + if (sn1394->sn1394_len != sizeof(*sn1394) || + (n1394pcb->n1394p_flags & N1394P_FREE) == 0) { + error = EINVAL; + goto out; + } + if (sn1394->sn1394_family != AF_N1394) { + error = EAFNOSUPPORT; + goto out; + } + + sn1394->sn1394_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination + since ifunit() uses strcmp */ + + + ifp = ifunit(sn1394->sn1394_if); + + if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { + error = ENXIO; + goto out; + } + if (ifp->if_output != fw_output) { + error = EAFNOSUPPORT; + goto out; + } + if( proto == PROTO_N1394ISOST){ + if (n1394isop_add(n1394pcb, ifp, sn1394->sn1394_fch, + sn1394->sn1394_ftag, sn1394->sn1394_mode) != n1394pcb) { + error = EADDRINUSE; + goto out; + } + + lpi.req.pcbreq.data = (n1394pcb->n1394p_fch & 0x3f) + | ((n1394pcb->n1394p_ftag & 0x3) << 6); + lpi.req.pcbreq.pcb = n1394pcb; + s2 = splimp(); + if (ifp->if_ioctl == NULL || + ifp->if_ioctl(ifp, SIOCISOENA, (caddr_t) &lpi) != 0) { + splx(s2); + n1394pcb_free(n1394pcb, N1394P_REMOVE); + error = EIO; + goto out; + } + splx(s2); + }else{ + if (n1394asyp_add(n1394pcb, ifp, sn1394->sn1394_mode) + != n1394pcb) { + error = EADDRINUSE; + goto out; + } + } + soisconnected(so); + out: + splx(s); + return (error); + } + static int + n1394_usr_disconnect(struct socket *so) + { + struct n1394pcb *n1394pcb; + struct sockaddr_n1394 *sn1394; + struct fwintreq lpi; + struct fwisohdr *ilh; + struct fwasyhdr *alh; + struct ifnet *ifp; + int error = 0; + int s2, s = splnet(); + int proto = so->so_proto->pr_protocol; + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + + if ((n1394pcb->n1394p_flags & N1394P_CONNECTED) == 0) { + error = EIO; + goto out; + } + ifp = n1394pcb->n1394p_ifp; + + if( proto == PROTO_N1394ISOST){ + lpi.req.pcbreq.data = (n1394pcb->n1394p_fch & 0x3f) + | ((n1394pcb->n1394p_ftag & 0x3) << 6); + s2 = splimp(); + if (ifp->if_ioctl != NULL) + ifp->if_ioctl(ifp, SIOCISODIS, (caddr_t) &lpi); + splx(s); + } + n1394pcb_free(n1394pcb, N1394P_REMOVE); + soisdisconnected(so); + out: + splx(s); + return (error); + } + + static int + n1394_usr_shutdown(struct socket *so) + { + socantsendmore(so); + return 0; + } + + static int + n1394_usr_send(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *nam, struct mbuf *control, struct proc *p) + { + struct n1394pcb *n1394pcb; + struct fwintreq lpi; + int error = 0; + struct ifnet *ifp; + int s = splnet(); + int s2; + int proto = so->so_proto->pr_protocol; + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + + ifp = n1394pcb->n1394p_ifp; + + if (control && control->m_len) { + m_freem(control); + m_freem(m); + error = EINVAL; + goto out; + } + if (!(m->m_pkthdr.len)) { + m_freem(control); + m_freem(m); + error = EIO; + goto out; + } + if(proto == PROTO_N1394ISOST){ + struct fwisohdr *ilh; + #ifdef PREVENTISOHDR + M_PREPEND(m, sizeof(fwcntl), M_WAITOK); + #else + M_PREPEND(m, sizeof(struct fwisohdr), M_WAITOK); + #endif + if (m == NULL) { + error = ENOBUFS; + goto out; + } + ilh = mtod(m, struct fwisohdr *); + ilh->cntl[0] = PROTO_N1394ISOST; + + ilh->data[0] = htonl((TCODE_STREAM << 4) | n1394pcb->n1394p_fch << 8 + | n1394pcb->n1394p_ftag << 14 + | ((m->m_pkthdr.len - 8 ) << 16 )); + }else{ + int8_t tcode; + int8_t tlabel; + int lnode; + struct fwasyhdr *alh; + /* + ** Application must ensure async packet format itself. + ** But, system requires control information moreover. + */ + M_PREPEND(m, sizeof(fwcntl), M_WAITOK); + + alh = mtod(m, struct fwasyhdr *); + alh->cntl[0] = PROTO_N1394ASYRQ; + tlabel = (ntohl(alh->data[0]) >> 10) & 0x3f; + tcode = (ntohl(alh->data[0]) >> 4) & 0xf; + + /* BAD header */ + if( tcode == 0x0a ){ + m_freem(control); + m_freem(m); + error = EINVAL; + goto out; + } + + lpi.req.mem.addr = NODE_IDS; + s2 = splimp(); + if (ifp->if_ioctl == NULL || + ifp->if_ioctl(ifp, SIOCRDCSR, (caddr_t) &lpi) != 0) { + splx(s2); + n1394pcb_free(n1394pcb, N1394P_REMOVE); + error = EIO; + goto out; + } + splx(s2); + lnode = ((lpi.req.mem.data) >> 16); + if((tcode < 0x0c ) && !(( tcode & 0x02)) ){ + if((tlabel = fw_get_tlabel(ifp, TLABEL_PCB, n1394pcb)) < 0 ){ + m_freem(control); + m_freem(m); + error = EIO; + goto out; + } + } + /* Override the src node information and tlabel */ + alh->data[0] &= htonl(0xffff03ff); + alh->data[0] |= htonl(tlabel << 10); + alh->data[1] &= htonl(0x0000ffff); + alh->data[1] |= htonl(lnode << 16 | tlabel << 10); + } + error = ifp->if_output(ifp, m, NULL, NULL); + out: + splx(s); + return (error); + } + static int + n1394_usr_peeraddr(struct socket *so, struct sockaddr **nam) + { + struct n1394pcb *n1394pcb; + struct sockaddr_n1394 *sn1394, ssn1394; + int error = 0; + int s = splnet(); + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + sn1394 = &ssn1394; + bzero(sn1394, sizeof(*sn1394)); + sn1394->sn1394_len = sizeof(*sn1394); + sn1394->sn1394_family = AF_N1394; + sprintf(sn1394->sn1394_if, "%s%d", n1394pcb->n1394p_ifp->if_name, + n1394pcb->n1394p_ifp->if_unit); + sn1394->sn1394_fch = n1394pcb->n1394p_fch; + *nam = dup_sockaddr((struct sockaddr *)sn1394, 0); + out: + splx(s); + return (error); + } + static int + n1394_usr_control(struct socket *so, u_long cmd, caddr_t arg, + struct ifnet *ifp, struct proc *p) + { + struct n1394pcb *n1394pcb; + int error = 0; + int s = splnet(); + + n1394pcb = (struct n1394pcb *) so->so_pcb; + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + error = n1394_ioctl(so, (int)cmd, arg); + out: + splx(s); + return (error); + } + + static int + n1394_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) + { + int error = 0; + int s, i; + int proto = so->so_proto->pr_protocol; + struct n1394pcb *n1394pcb = (struct n1394pcb *)so->so_pcb; + struct ifnet *ifp; + struct fw_softc *fc; + struct fw_bind fwbind; + struct sockaddr_n1394 *sn1394; + + s = splnet(); + if (n1394pcb == NULL) { + error = EINVAL; + goto out; + } + sn1394 = (struct sockaddr_n1394 *)nam; + if (sn1394->sn1394_len != sizeof(*sn1394) || + (n1394pcb->n1394p_flags & N1394P_FREE) == 0) { + error = EINVAL; + goto out; + } + if (sn1394->sn1394_family != AF_N1394) { + error = EAFNOSUPPORT; + goto out; + } + + sn1394->sn1394_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination + since ifunit() uses strcmp */ + + ifp = ifunit(sn1394->sn1394_if); + if( ifp == NULL ){ + error = ENXIO; + goto out; + } + if (ifp->if_output != fw_output) { + error = EAFNOSUPPORT; + goto out; + } + fc = (struct fw_softc *)ifp->if_softc; + + if(proto == PROTO_N1394ISOST){ + error = EINVAL; + } + + fwbind.type = FWBIND_PCB; + fwbind.resp.pcb = n1394pcb; + fwbind.start_hi = sn1394->sn1394_start_hi; + fwbind.start_lo = sn1394->sn1394_start_lo; + fwbind.addrlen = sn1394->sn1394_addrlen; + + if( fw_bindadd(fc, fwbind) < 0 ){ + error = EINVAL; + goto out; + } + /* + for( i = 0 ; i < FW_MAXREGBIND ; i ++){ + if( fc->bind_list[i].type == FWBIND_NULL) + break; + if( fc->bind_list[i].type == FWBIND_PCB){ + if( fc->bind_list[i].resp.pcb == n1394pcb ){ + error = EINVAL; + goto out; + } + } + if( fc->bind_list[i].start_hi == sn1394->sn1394_start_hi){ + if( + !((fc->bind_list[i].start_lo) > (sn1394->sn1394_start_lo + sn1394->sn1394_addrlen)) + ){ + if( + !((fc->bind_list[i].start_lo + fc->bind_list[i].addrlen ) < (sn1394->sn1394_start_lo )) + ){ + error = EINVAL; + goto out; + } + } + } + } + */ + /* + if(i == FW_MAXREGBIND){ + error = ENOBUFS; + goto out; + } + */ + if (n1394asyp_add(n1394pcb, ifp, sn1394->sn1394_mode) != n1394pcb) { fw_bindremove(fc, fwbind); + error = EADDRINUSE; + goto out; + } + /* + fc->bind_list[i].type = FWBIND_PCB; + fc->bind_list[i].resp.pcb = n1394pcb; + fc->bind_list[i].start_hi = sn1394->sn1394_start_hi; + fc->bind_list[i].start_lo = sn1394->sn1394_start_lo; + fc->bind_list[i].addrlen = sn1394->sn1394_addrlen; + */ + soisconnected(so); + out: + splx(s); + return(error); + } + + static int + n1394_usr_sockaddr(struct socket *so, struct sockaddr **nam) + { + return EOPNOTSUPP; + } + static int n1394_ioctl(so, cmd, data) + struct socket *so; + int cmd; + caddr_t data; + { + struct mbuf *m; + u_int tlabel, lnode; + int error = 0; + switch(cmd){ + default: + error = EOPNOTSUPP; + break; + } + return(error); + } + void + n1394intr() + { + int s; + struct mbuf *m; + struct socket *so; + struct n1394pcb *n1394pcb; + + u_int32_t *ld; + next: + s = splimp(); + IF_DEQUEUE(&n1394intrq, m); + splx(s); + if (m == NULL) + return; + + #ifdef DIAGNOSTIC + if ((m->m_flags & M_PKTHDR) == 0) + panic("n1394intr no HDR"); + #endif + + n1394pcb = (struct n1394pcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */ + so = n1394pcb->n1394p_socket; + + s = splimp(); + n1394pcb->n1394p_inq--; + splx(s); + + if (n1394pcb->n1394p_flags & N1394P_DRAIN) { + m_freem(m); + if (n1394pcb->n1394p_inq == 0) + FREE(n1394pcb, M_PCB); /* done! */ + goto next; + } + + if (n1394pcb->n1394p_flags & N1394P_FREE) { + m_freem(m); /* drop */ + goto next; + } + m->m_pkthdr.rcvif = n1394pcb->n1394p_ifp; + + m_adj(m, sizeof(fwcntl)); + + #ifndef PREVENTISOHDR + if(so->so_proto->pr_protocol == PROTO_N1394ISOST) + m_adj(m, 4); + #endif + + if (sbspace(&so->so_rcv) > m->m_pkthdr.len ) { + n1394_sookcnt++; + n1394_sookbytes += m->m_pkthdr.len; + sbappendrecord(&so->so_rcv, m); + sorwakeup(so); + }else{ + m_freem(m); + } + + goto next; + } + static int + n1394_usr_abort(struct socket *so) + { + return n1394_usr_shutdown(so); + } + + struct n1394pcb *n1394p_alloc(wait) + int wait; + + { + struct n1394pcb *n1394pcb; + + MALLOC(n1394pcb, struct n1394pcb *, sizeof(*n1394pcb), M_PCB, wait); + + if (n1394pcb) { + bzero(n1394pcb, sizeof(*n1394pcb)); + n1394pcb->n1394p_flags = N1394P_FREE; + } + return(n1394pcb); + } + + void n1394p_free(n1394pcb, op) + struct n1394pcb *n1394pcb; + int op; + { + int s = splimp(); + if ((n1394pcb->n1394p_flags & N1394P_FREE) == 0) { + LIST_REMOVE(n1394pcb, pcblist); + n1394pcb->n1394p_flags = N1394P_FREE; + } + if (op == N1394P_DESTROY) { + if (n1394pcb->n1394p_inq) { + n1394pcb->n1394p_flags = N1394P_DRAIN; + } else { + FREE(n1394pcb, M_PCB); + } + } + splx(s); + } + + struct n1394pcb *n1394asyp_add(n1394pcb, ifp, mode) + struct n1394pcb *n1394pcb; + struct ifnet *ifp; + u_int8_t mode; + { + struct n1394pcb *cpcb = NULL; /* current pcb */ + int s = splimp(); + + for (cpcb = n1394_pcbs.lh_first ; cpcb != NULL ; + cpcb = cpcb->pcblist.le_next) { + break; + } + + if (cpcb) { + cpcb = NULL; + goto done; + } + + if (n1394pcb == NULL) { + cpcb = n1394p_alloc(M_NOWAIT); + if (cpcb == NULL) + goto done; + } else { + cpcb = n1394pcb; + } + + cpcb->n1394p_ifp = ifp; + cpcb->n1394p_mode = mode; + cpcb->n1394p_flags = N1394P_CONNECTED; + + LIST_INSERT_HEAD(&n1394_pcbs, cpcb, pcblist); + done: + splx(s); + return(cpcb); + } + + struct n1394pcb *n1394isop_add(n1394pcb, ifp, fch, ftag, mode) + struct n1394pcb *n1394pcb; + struct ifnet *ifp; + u_int8_t fch, ftag; + u_int8_t mode; + { + struct n1394pcb *cpcb = NULL; /* current pcb */ + int s = splimp(); + + for (cpcb = n1394_pcbs.lh_first ; cpcb != NULL ; + cpcb = cpcb->pcblist.le_next) { + if (ifp == cpcb->n1394p_ifp && mode == cpcb->n1394p_mode) + break; + } + + if (cpcb) { + cpcb = NULL; + goto done; + } + + if (n1394pcb == NULL) { + cpcb = n1394p_alloc(M_NOWAIT); + if (cpcb == NULL) + goto done; + } else { + cpcb = n1394pcb; + } + + cpcb->n1394p_ifp = ifp; + cpcb->n1394p_fch = fch; + cpcb->n1394p_ftag = ftag; + cpcb->n1394p_mode = mode; + cpcb->n1394p_flags = N1394P_CONNECTED; + + LIST_INSERT_HEAD(&n1394_pcbs, cpcb, pcblist); + + done: + splx(s); + return(cpcb); + } + #ifdef DDB + int n1394p_dump __P((void)); + #endif + #if defined(__FreeBSD__) + static void + netisr_n1394_setup(void *dummy __unused) + { + + register_netisr(NETISR_1394, n1394intr); + } + SYSINIT(n1394_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_n1394_setup, NULL); + #endif diff -r -c -N sys44.orig/dev/firewire/netfw.h sys/dev/firewire/netfw.h *** sys44.orig/dev/firewire/netfw.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/netfw.h Tue Oct 9 21:55:20 2001 *************** *** 0 **** --- 1,123 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: netfw.h,v 1.1.2.1 2000/06/04 17:19:07 ikob Exp $ + * + */ + /* + * sockaddr_n1394 + */ + + struct sockaddr_n1394 { + u_int8_t sn1394_len; /* length */ + u_int8_t sn1394_family; + char sn1394_if[IFNAMSIZ]; /* interface name */ + u_int8_t sn1394_fch; + u_int8_t sn1394_ftag; + u_int8_t sn1394_mode; + u_int8_t sn1394_flags; + u_int8_t sn1394_sped; + u_int32_t sn1394_start_hi; + u_int32_t sn1394_start_lo; + u_int32_t sn1394_addrlen; + }; + + #define STATE_CLEAR 0x0000 + #define STATE_SET 0x0004 + #define NODE_IDS 0x0008 + #define RESET_START 0x000c + #define SPLIT_TIMEOUT_HI 0x0018 + #define SPLIT_TIMEOUT_LO 0x001c + #define CYCLE_TIME 0x0200 + #define BUS_TIME 0x0200 + #define BUS_MGR_ID 0x021c + #define BANDWIDTH_AV 0x0220 + #define CHANNELS_AV_HI 0x0224 + #define CHANNELS_AV_LO 0x0228 + + #define TOPOLOGY_MAP 0x1000 / 4 + #define SPEED_MAP 0x2000 / 4 + + #define oMPR 0x900 + + #define iMPR 0x980 + + #define IP_CHANNELS 0x0234 + #ifdef _KERNEL + + struct n1394pcb { + LIST_ENTRY(n1394pcb) pcblist; + u_int n1394p_inq; + struct socket *n1394p_socket; + struct ifnet *n1394p_ifp; + u_int8_t n1394p_fch; + u_int8_t n1394p_ftag; + u_int8_t n1394p_mode; + u_int8_t n1394p_flags; + }; + + /* flags */ + #define N1394P_FREE 0x01 /* free (not on any list) */ + #define N1394P_CONNECTED 0x02 /* connected */ + #define N1394P_NET 0x04 + #define N1394P_DRAIN 0x08 /* destory as soon as inq == 0 */ + + #define N1394P_REMOVE 0 /* remove from global list */ + #define N1394P_DESTROY 1 /* destroy and be free */ + + LIST_HEAD(n1394plist, n1394pcb); + + /* global data structures */ + + struct n1394plist n1394_pcbs; + extern struct ifqueue n1394intrq; + extern u_int n1394_sodropcnt, + n1394_sodropbytes; + extern u_int n1394_sookcnt, + n1394_sookbytes; + + struct n1394pcb *n1394p_alloc __P((int)); + void n1394p_free __P((struct n1394pcb *, int)); + struct n1394pcb *n1394isop_add __P((struct n1394pcb *, struct ifnet *, u_int8_t, u_int8_t, u_int8_t)); + struct n1394pcb *n1394asyp_add __P((struct n1394pcb *, struct ifnet *, u_int8_t)); + + extern struct pr_usrreqs n1394_usrreqs; + void n1394intr __P((void)); + + #endif /* _KERNEL */ diff -r -c -N sys44.orig/dev/firewire/netfw_proto.c sys/dev/firewire/netfw_proto.c *** sys44.orig/dev/firewire/netfw_proto.c Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/netfw_proto.c Tue Oct 9 21:55:21 2001 *************** *** 0 **** --- 1,108 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: netfw_proto.c,v 1.1.2.1 2000/06/04 17:19:07 ikob Exp $ + * + */ + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + #include + + extern struct domain n1394domain; + + static void n1394_init __P((void)); + + struct protosw n1394sw[] = { + { SOCK_DGRAM, &n1394domain, PROTO_N1394ASYRQ, PR_ATOMIC, + 0, 0, 0, 0, + 0, + 0, 0, 0, 0, + &n1394_usrreqs + }, + { SOCK_STREAM, &n1394domain, PROTO_N1394ASYRQ, PR_ATOMIC|PR_CONNREQUIRED, + 0, 0, 0, 0, + 0, + 0, 0, 0, 0, + &n1394_usrreqs + }, + { SOCK_DGRAM, &n1394domain, PROTO_N1394ISOST, PR_CONNREQUIRED, + 0, 0, 0, 0, + 0, + 0, 0, 0, 0, + &n1394_usrreqs + }, + }; + + struct domain n1394domain = + { AF_N1394, "n1394", n1394_init, 0, 0, + n1394sw, &n1394sw[sizeof(n1394sw)/sizeof(n1394sw[0])], 0, + 0, 0, 0}; + + struct ifqueue n1394intrq; + int n1394qmaxlen = 2000; + u_int n1394_sodropcnt = 0; /* # mbufs dropped due to full sb */ + u_int n1394_sodropbytes = 0; /* # of bytes dropped */ + u_int n1394_sookcnt = 0; /* # mbufs ok */ + u_int n1394_sookbytes = 0; /* # of bytes ok */ + + void n1394_init() + { + LIST_INIT(&n1394_pcbs); + bzero(&n1394intrq, sizeof(n1394intrq)); + n1394intrq.ifq_maxlen = n1394qmaxlen; + } + DOMAIN_SET(n1394); diff -r -c -N sys44.orig/dev/firewire/tsb21lv03.h sys/dev/firewire/tsb21lv03.h *** sys44.orig/dev/firewire/tsb21lv03.h Thu Jan 1 09:00:00 1970 --- sys/dev/firewire/tsb21lv03.h Tue Oct 9 21:55:21 2001 *************** *** 0 **** --- 1,132 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: tsb21lv03.h,v 1.1.2.1 2000/06/04 17:19:07 ikob Exp $ + * + */ + + #define FW_PHY_PHYSID_REG 0x00 + #define FW_PHY_PHYSID (63<<2) + #define FW_PHY_ROOT_REG 0x00 + #define FW_PHY_ROOT (1<<1) + #define FW_PHY_CPS_REG 0x00 + #define FW_PHY_CPS (1<<0) + + #define FW_PHY_RHB_REG 0x01 + #define FW_PHY_RHB (1<<7) + #define FW_PHY_IBR_REG 0x01 + #define FW_PHY_IBR (1<<6) + #define FW_PHY_GC_REG 0x01 + + #define FW_PHY_SPD_REG 0x02 + #define FW_PHY_SPD (3<<6) + #define FW_PHY_REV_REG 0x02 + #define FW_PHY_REV (3<<4) + #define FW_PHY_NP_REG 0x02 + #define FW_PHY_NP (15<<0) + + #define FW_PHY_P1_REG 0x03 + #define FW_PHY_P2_REG 0x04 + #define FW_PHY_P3_REG 0x05 + + #define FW_PHY_P_ASTAT (3<<6) + #define FW_PHY_P_BSTAT (3<<4) + #define FW_PHY_P_CH (1<<3) + #define FW_PHY_P_CON (1<<2) + + #define FW_PHY_LOOPINT_REG 0x06 + #define FW_PHY_LOOPINT (1<<7) + #define FW_PHY_CPSINT_REG 0x06 + #define FW_PHY_CPSNT (1<<6) + /* + #define FW_PHY_CPS_REG 0x06 + #define FW_PHY_CPS (1<<5) + */ + #define FW_PHY_IR_REG 0x06 + #define FW_PHY_IR (1<<4) + #define FW_PHY_C_REG 0x06 + #define FW_PHY_C (1<<0) + + #define FW_PHY_ESPD_REG 0x03 + #define FW_PHY_ESPD (7<<5) + + #define FW_PHY_EDEL_REG 0x03 + #define FW_PHY_EDEL 15<<0 + + static u_int tsb21lv_rddata(volatile u_int *, u_int); + static u_int tsb21lv_wrdata(volatile u_int *, u_int, u_int); + + static u_int tsb21lv_wrdata(volatile u_int *access, u_int addr, u_int data) + { + volatile u_int fun = *access; + + DELAY(10); + addr &= 0xf; + data &= 0xff; + + fun = (TSB21_WRPHY | (addr << TSB21_REGADDR) | (data << TSB21_WRDATA)); + *access = fun; + DELAY(100); + + return(tsb21lv_rddata( access, addr)); + + } + + static u_int tsb21lv_rddata(volatile u_int *access, u_int addr) + { + volatile u_int fun; + u_int i; + + /* fun = *access;*/ + DELAY(10); + addr &= 0xf; + fun = TSB21_RDPHY | (addr << TSB21_REGADDR); + *access = fun; + for ( i = 0 ; i < 10000 ; i ++ ){ + #ifdef TSB21_RDDONE + if(*access & TSB21_RDDONE) break; + #else + if(((*access >> TSB21_RDADDR) & 0xf) == addr ) break; + #endif + DELAY(100); + } + if( i == 1000) printf("error in reading phy\n"); + return((*access >> TSB21_RDDATA )& 0xff); + } + diff -r -c -N sys44.orig/i386/conf/firewire sys/i386/conf/firewire *** sys44.orig/i386/conf/firewire Thu Jan 1 09:00:00 1970 --- sys/i386/conf/firewire Tue Oct 9 22:28:43 2001 *************** *** 0 **** --- 1,235 ---- + # + # GENERIC -- Generic kernel configuration file for FreeBSD/i386 + # + # For more information on this file, please read the handbook section on + # Kernel Configuration Files: + # + # http://www.freebsd.org/handbook/kernelconfig-config.html + # + # The handbook is also available locally in /usr/share/doc/handbook + # if you've installed the doc distribution, otherwise always see the + # FreeBSD World Wide Web server (http://www.FreeBSD.ORG/) for the + # latest information. + # + # An exhaustive list of options and more detailed explanations of the + # device lines is also present in the ./LINT configuration file. If you are + # in doubt as to the purpose or necessity of a line, check first in LINT. + # + # $FreeBSD: src/sys/i386/conf/GENERIC,v 1.246 2000/03/09 16:32:55 jlemon Exp $ + + machine i386 + cpu I386_CPU + cpu I486_CPU + cpu I586_CPU + cpu I686_CPU + ident firewire + maxusers 256 + + #makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols + + options MATH_EMULATE #Support for x87 emulation + options INET #InterNETworking + options INET6 #IPv6 communications protocols + options FFS #Berkeley Fast Filesystem + options FFS_ROOT #FFS usable as root device [keep this!] + options MFS #Memory Filesystem + options MD_ROOT #MD is a potential root device + #options NFS #Network Filesystem + #options NFS_ROOT #NFS usable as root device, NFS required + options MSDOSFS #MSDOS Filesystem + options CD9660 #ISO 9660 Filesystem + options CD9660_ROOT #CD-ROM usable as root, CD9660 required + options PROCFS #Process filesystem + options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] + options SCSI_DELAY=15000 #Delay (in ms) before probing SCSI + options UCONSOLE #Allow users to grab the console + options USERCONFIG #boot -c editor + options VISUAL_USERCONFIG #visual boot -c editor + options KTRACE #ktrace(1) support + options SYSVSHM #SYSV-style shared memory + options SYSVMSG #SYSV-style message queues + options SYSVSEM #SYSV-style semaphores + options P1003_1B #Posix P1003_1B real-time extentions + options _KPOSIX_PRIORITY_SCHEDULING + #options ICMP_BANDLIM #Rate limit bad replies + options N1394 + + # To make an SMP kernel, the next two are needed + #options SMP # Symmetric MultiProcessor Kernel + #options APIC_IO # Symmetric (APIC) I/O + # Optionally these may need tweaked, (defaults shown): + #options NCPU=2 # number of CPUs + #options NBUS=4 # number of busses + #options NAPIC=1 # number of IO APICs + #options NINTR=24 # number of INTs + + device isa + device eisa + device pci + + # Floppy drives + device fdc0 at isa? port IO_FD1 irq 6 drq 2 + device fd0 at fdc0 drive 0 + device fd1 at fdc0 drive 1 + + # ATA and ATAPI devices + device ata0 at isa? port IO_WD1 irq 14 + device ata1 at isa? port IO_WD2 irq 15 + device ata + device atadisk # ATA disk drives + device atapicd # ATAPI CDROM drives + device atapifd # ATAPI floppy drives + device atapist # ATAPI tape drives + options ATA_STATIC_ID #Static device numbering + #options ATA_ENABLE_ATAPI_DMA #Enable DMA on ATAPI devices + + # SCSI Controllers + device ahb # EISA AHA1742 family + device ahc # AHA2940 and onboard AIC7xxx devices + device amd # AMD 53C974 (Teckram DC-390(T)) + device dpt # DPT Smartcache - See LINT for options! + device isp # Qlogic family + device ncr # NCR/Symbios Logic + device sym # NCR/Symbios Logic (newer chipsets) + + device adv0 at isa? + device adw + device bt0 at isa? + device aha0 at isa? + device aic0 at isa? + + # SCSI peripherals + device scbus # SCSI bus (required) + device da # Direct Access (disks) + device sa # Sequential Access (tape etc) + device cd # CD + device pass # Passthrough device (direct SCSI access) + + # RAID controllers + device ida # Compaq Smart RAID + device amr # AMI MegaRAID + device mlx # Mylex DAC960 family + + # atkbdc0 controls both the keyboard and the PS/2 mouse + device atkbdc0 at isa? port IO_KBD + device atkbd0 at atkbdc? irq 1 + device psm0 at atkbdc? irq 12 + + device vga0 at isa? + + # splash screen/screen saver + #pseudo-device splash + + # syscons is the default console driver, resembling an SCO console + device sc0 at isa? + + # Enable this and PCVT_FREEBSD for pcvt vt220 compatible console driver + #device vt0 at isa? + #options XSERVER # support for X server on a vt console + #options FAT_CURSOR # start with block cursor + # If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines + #options PCVT_SCANSET=2 # IBM keyboards are non-std + + # Floating point support - do not disable. + device npx0 at nexus? port IO_NPX irq 13 + + # Power management support (see LINT for more options) + device apm0 at nexus? disable flags 0x20 # Advanced Power Management + + # PCCARD (PCMCIA) support + device card + device pcic0 at isa? irq 10 port 0x3e0 iomem 0xd0000 + device pcic1 at isa? irq 11 port 0x3e2 iomem 0xd4000 disable + + # Serial (COM) ports + device sio0 at isa? port IO_COM1 flags 0x10 irq 4 + device sio1 at isa? port IO_COM2 irq 3 + device sio2 at isa? disable port IO_COM3 irq 5 + device sio3 at isa? disable port IO_COM4 irq 9 + + # Parallel port + device ppc0 at isa? irq 7 + device ppbus # Parallel port bus (required) + device lpt # Printer + device plip # TCP/IP over parallel + device ppi # Parallel port interface device + #device vpo # Requires scbus and da + + + # PCI Ethernet NICs. + device de # DEC/Intel DC21x4x (``Tulip'') + device fxp # Intel EtherExpress PRO/100B (82557, 82558) + device tx # SMC 9432TX (83c170 ``EPIC'') + device vx # 3Com 3c590, 3c595 (``Vortex'') + device wx # Intel Gigabit Ethernet Card (``Wiseman'') + + # PCI Ethernet NICs that use the common MII bus controller code. + device miibus # MII bus support + device dc # DEC/Intel 21143 and various workalikes + device rl # RealTek 8129/8139 + device sf # Adaptec AIC-6915 (``Starfire'') + device sis # Silicon Integrated Systems SiS 900/SiS 7016 + device ste # Sundance ST201 (D-Link DFE-550TX) + device tl # Texas Instruments ThunderLAN + device vr # VIA Rhine, Rhine II + device wb # Winbond W89C840F + device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') + + # FIREWIRE devices + device lynx + device ilink + device fwohci + + # ISA Ethernet NICs. + device ed0 at isa? port 0x280 irq 10 iomem 0xd8000 + device ex + device ep + # WaveLAN/IEEE 802.11 wireless NICs. Note: the WaveLAN/IEEE really + # exists only as a PCMCIA device, so there is no ISA attatement needed + # and resources will always be dynamically assigned by the pccard code. + device wi + # Aironet 4500/4800 802.11 wireless NICs. Note: the declaration below will + # work for PCMCIA and PCI cards, as well as ISA cards set to ISA PnP + # mode (the factory default). If you set the switches on your ISA + # card for a manually chosen I/O address and IRQ, you must specify + # those paremeters here. + device an + # The probe order of these is presently determined by i386/isa/isa_compat.c. + device ie0 at isa? port 0x300 irq 10 iomem 0xd0000 + device fe0 at isa? port 0x300 + device le0 at isa? port 0x300 irq 5 iomem 0xd0000 + device lnc0 at isa? port 0x280 irq 10 drq 0 + device cs0 at isa? port 0x300 + device sn0 at isa? port 0x300 irq 10 + # requires PCCARD (PCMCIA) support to be activated + #device xe0 at isa? + + # Pseudo devices - the number indicates how many units to allocated. + pseudo-device loop # Network loopback + pseudo-device ether # Ethernet support + #pseudo-device sl 1 # Kernel SLIP + #pseudo-device ppp 1 # Kernel PPP + #pseudo-device tun # Packet tunnel. + pseudo-device pty # Pseudo-ttys (telnet etc) + pseudo-device md # Memory "disks" + pseudo-device gif 2 # IPv6 and IPv4 tunneling + #pseudo-device faith 1 # IPv6-to-IPv4 relaying (translation) + + # The `bpf' pseudo-device enables the Berkeley Packet Filter. + # Be aware of the administrative consequences of enabling this! + pseudo-device bpf #Berkeley packet filter + + # USB support + #device uhci # UHCI PCI->USB interface + #device ohci # OHCI PCI->USB interface + #device usb # USB Bus (required) + #device ugen # Generic + #device uhid # "Human Interface Devices" + #device ukbd # Keyboard + #device ulpt # Printer + #device umass # Disks/Mass storage - Requires scbus and da + #device ums # Mouse + # USB Ethernet, requires mii + #device aue # ADMtek USB ethernet + #device cue # CATC USB ethernet + #device kue # Kawasaki LSI USB ethernet diff -r -c -N sys44.orig/net/ethernet.h sys/net/ethernet.h *** sys44.orig/net/ethernet.h Thu Sep 20 00:09:45 2001 --- sys/net/ethernet.h Tue Oct 9 21:55:23 2001 *************** *** 14,19 **** --- 14,24 ---- #define ETHER_ADDR_LEN 6 /* + * The number of bytes in an EUI64 address. + */ + #define EUI64_ADDR_LEN 8 + + /* * The number of bytes in the type field. */ #define ETHER_TYPE_LEN 2 diff -r -c -N sys44.orig/net/if_arp.h sys/net/if_arp.h *** sys44.orig/net/if_arp.h Thu Sep 20 00:09:45 2001 --- sys/net/if_arp.h Tue Oct 9 21:55:23 2001 *************** *** 50,55 **** --- 50,56 ---- struct arphdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ + #define ARPHRD_1394 0x18 /* firewire hardware format */ #define ARPHRD_IEEE802 6 /* token-ring hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ u_short ar_pro; /* format of protocol address */ *************** *** 100,111 **** * The ifnet struct _must_ be at the head of this structure. */ struct ifnet ac_if; /* network-visible interface */ ! u_char ac_enaddr[6]; /* ethernet hardware address */ ! int ac_multicnt; /* length of ac_multiaddrs list */ void *ac_netgraph; /* ng_ether(4) netgraph node info */ }; extern u_char etherbroadcastaddr[6]; #endif - #endif /* !_NET_IF_ARP_H_ */ --- 101,134 ---- * The ifnet struct _must_ be at the head of this structure. */ struct ifnet ac_if; /* network-visible interface */ ! ! union { ! struct { ! u_char eui48[6]; ! /* ethernet hardware address */ ! int multicnt; ! /* length of ac_multiaddrs list */ ! } ether; ! struct { ! u_char eui64[8]; ! struct ip1394arp { ! u_int16_t node; ! u_int16_t fifo_h; ! u_int32_t fifo_l; ! u_int8_t maxrec; ! u_int8_t spd; ! u_int16_t rsvd; ! } arpdata; ! int broadcast; ! } firewire; ! } media; ! void *ac_netgraph; /* ng_ether(4) netgraph node info */ }; + #define ac_enaddr media.ether.eui48 + #define ac_multicnt media.ether.multicnt + extern u_char etherbroadcastaddr[6]; #endif #endif /* !_NET_IF_ARP_H_ */ diff -r -c -N sys44.orig/net/if_fw.h sys/net/if_fw.h *** sys44.orig/net/if_fw.h Thu Jan 1 09:00:00 1970 --- sys/net/if_fw.h Tue Oct 9 21:55:23 2001 *************** *** 0 **** --- 1,409 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * + * $Id: if_fw.h,v 1.1.2.1 2000/06/04 17:19:14 ikob Exp $ + * + */ + + #ifndef _IOWR + #include + #endif + + #define SIOCFWRESET _IOWR('i', 201, struct ifreq) + #define SIOCDEBUGPHY _IOWR('i', 202, struct ifreq) + #define SIOCSNOOPON _IOWR('i', 203, struct ifreq) + #define SIOCSNOOPOFF _IOWR('i', 204, struct ifreq) + #define SIOCDEBUGON _IOWR('i', 205, struct ifreq) + #define SIOCDEBUGOFF _IOWR('i', 206, struct ifreq) + #define DUMPDMA _IOWR('i', 207, struct ifreq) + #define SIOCPCLSEQ _IOWR('i', 211, struct ifreq) + #define DUMPRCV _IOWR('i', 212, struct ifreq) + #define SIOCISOENA _IOWR('i', 213, struct ifreq) + #define SIOCISODIS _IOWR('i', 214, struct ifreq) + /* For peek/poke bridge-chip register */ + #define SIOCFWRDREG _IOWR('i', 215, struct ifreq) + #define SIOCFWWRREG _IOWR('i', 216, struct ifreq) + + #define SIOCGETTLABEL _IOWR('i', 217, struct ifreq) + #define SIOCRELTLABEL _IOWR('i', 218, struct ifreq) + #define SIOCRDCSR _IOWR('i', 219, struct ifreq) + #define SIOCSTARTDV _IOWR('i', 220, struct ifreq) + #define SIOCSTOPDV _IOWR('i', 221, struct ifreq) + #define SIOCCPDV _IOWR('i', 222, struct ifreq) + #define SIOCSNPM _IOWR('i', 223, u_int32_t) + #define SIOCWRCSR _IOWR('i', 224, struct ifreq) + + struct fwintreq{ + char ifr_name[IFNAMSIZ]; + union{ + u_int8_t ch; + struct { + u_int32_t data; + void *pcb; + } pcbreq; + struct{ + u_int32_t addr; + u_int32_t data; + u_int32_t mask; + } mem; + struct{ + u_int32_t addr; + u_int32_t len; + u_int32_t *data; + } area; + struct{ + int len; + u_int32_t *data; + } dv; + }req; + }; + struct sockaddr_fw{ + u_char fw_len; + u_char fw_family; + u_short fw_channel; + u_char fw_type; + u_char zeros[11]; + }; + struct fw_ip{ + u_int32_t link; + }; + struct fw_ip_frag{ + u_int32_t frag; + }; + + #define N1394_IP 1 + #define N1394_ROW 2 + + /* Some legacy chip requires CRC space and cntl made with software, + when sending asy-stream. */ + typedef u_int32_t fwcntl[2]; + + #define PSEUDOHDR + + struct fwhdr{ + fwcntl cntl; + u_int32_t data[4]; + }; + struct fwisohdr{ + fwcntl cntl; + u_int32_t data[1]; + }; + struct isohdr{ + u_int32_t hdr[1]; + }; + struct asyhdr{ + u_int32_t hdr[4]; + }; + struct fwasyhdr{ + fwcntl cntl; + u_int32_t data[4]; + #if 0 + u_int16_t dst; + u_char tl:6, + rt:2; + u_char tcode:4, + pri:4; + u_int16_t src; + u_int16_t offset[3]; + u_int16_t len; + u_int16_t e_tcode; + #else + #endif + }; + + #define S100 0 + #define S200 1 + #define S400 2 + #define S100_SZ 512 + #define S200_SZ 1024 + #define S400_SZ 2048 + + #define TL_MASK (0x3f << 10) + + #define STCH_MASK (0x3f << 8) + + #define RETRY_MASK (0x3 << 8) + #define RETRY_1 00 + #define RETRY_X 01 + #define RETRY_A 01 + #define RETRY_B 01 + + #define TCODE_MASK (0xf << 4) + #define TCODE_WRREQ 0x0 + #define TCODE_BLKWRREQ 0x1 + #define TCODE_WRRES 0x2 + #define TCODE_RDREQ 0x4 + #define TCODE_BLKRDREQ 0x5 + #define TCODE_RDRES 0x6 + #define TCODE_BLKRDRES 0x7 + #define TCODE_CYCST 0x8 + #define TCODE_LKREQ 0x9 + #define TCODE_STREAM 0xa + #define TCODE_LKRES 0xb + #define TCODE_SID 0xe + #define TCODE_PHCONF 0xf + + #define PROTO_N1394ASYRQ 0 + #define PROTO_N1394ISOST 1 + #define PROTO_N1394ASYST 2 + #define PROTO_N1394RAW 3 + + #ifdef _KERNEL + + struct fw_softc{ + struct arpcom ac; + struct resource *mem; /* resource descriptor for registers */ + struct resource *irq; /* resource descriptor for interrupt */ + void *ih; /* interrupt handler cookie */ + struct ifqueue fragq; + int irm; + int asyst; + struct callout_handle stat_ch; /* Handle for canceling our stat timeout */ + struct { + #define LYNX_ASY_TIMEOUT 1 + u_long expire; + u_int64_t addr;/* Dest addr info incl. */ + u_int8_t tcode; + u_int32_t type; + #define TLABEL_NULL 0 + #define TLABEL_HAND 1 + #define TLABEL_PCB 2 + #define TLABEL_WAIT 3 + union{ + void (*hand) __P((struct ifnet *, struct mbuf *)); + void *pcb; + caddr_t wait; + } resp; + caddr_t data; + } tlabel[0x40]; + struct { + u_int32_t type; + #define ISOSLOT_NULL 0 + #define ISOSLOT_HAND 1 + #define ISOSLOT_PCB 2 + #define ISOSLOT_DV 3 + union{ + void (*hand) __P((struct ifnet *, struct mbuf *)); + void *pcb; + }resp; + }isoslot[0x100]; + struct fw_bind { + u_int32_t start_hi, start_lo, addrlen; + u_int32_t type; + #define FWBIND_NULL 0 + #define FWBIND_HAND 1 + #define FWBIND_PCB 2 + union{ + void (*hand) __P((struct ifnet *, struct mbuf *)); + void *pcb; + } resp; + #define FW_MAXREGBIND 0x10 + }; + int fw_nbind; + struct fw_bind bind_list[FW_MAXREGBIND]; + struct mbuf *asyfrag[0x40]; + struct mbuf *isofrag[0x40]; + /* CSR + Serial Bus + ROM + Topology + Speed + DV specific */ + u_int32_t init_reg[0x3000/4]; + #define DV_ONLINE (1<<31) + #define DV_BROADCAST_ON (1<<30) + int tmpnpm; + u_int32_t max_node; + + u_int32_t *sid_buf; + u_int32_t sid_cnt; + + volatile u_int32_t *p_cycle_timer; + void (*fw_busreset) __P((struct fw_softc *)); + u_int32_t dv_flags; + u_int32_t dv_cycle; + int32_t dv_gap; + u_int32_t dv_start; + u_int32_t dv_end; + u_int32_t dv_intr; + struct { + int wklock, walock, rklock, ralock, dbc, queued, sync; + } dv; + volatile struct dv_data *dv_buf; + u_int32_t dv_buf_size; + #define MAX_DVFRAME 16 + #define DEF_FRAME 12 + u_int32_t *dv_write_buf[MAX_DVFRAME]; + struct proc *dv_write_proc; + int write_signal; + u_int32_t *dv_read_buf[MAX_DVFRAME]; + struct proc *dv_read_proc; + int read_signal; + struct cdevsw *cdev; + #define BMEPHASE 1 + #define NPMEPHASE 2 + #define FWIP_UP 4 + u_int32_t fw_flags; + struct callout_handle fw_bmrhandle; + struct callout_handle fw_npmhandle; + void (*txdv) __P((struct fw_softc *)); + void (*txstop) __P((struct fw_softc *)); + void (*rxdv) __P((struct fw_softc *)); + void (*rxstop) __P((struct fw_softc *)); + void (*set_irm) __P((struct fw_softc *)); + void (*set_bmr) __P((struct fw_softc *)); + }; + #define IPFIFO 0x478a6540 + + void if_fwbusreset __P((struct fw_softc *)); + void if_fwinit __P((struct fw_softc *)); + struct fw_bind *fw_bindlookup __P((struct fw_softc *, u_int32_t, u_int32_t)); + int fw_bindadd __P((struct fw_softc *, struct fw_bind)); + void fw_bindremove __P((struct fw_softc *, struct fw_bind)); + u_int32_t fw_setbmslot __P((struct ifnet *, u_int32_t)); + + int fw_get_tlabel __P((struct ifnet *, u_int, void*)); + int fw_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); + void fw_stream_input __P((struct ifnet *, struct mbuf *)); + /* + void fw_lock_request_input __P((struct ifnet *, struct mbuf *)); + */ + void fw_lock_responce_input __P((struct ifnet *, struct mbuf *)); + void asy_read_resp __P((struct ifnet *, struct fwasyhdr *, u_int32_t)); + void asy_lock_resp __P((struct ifnet *, struct fwasyhdr *, u_int32_t *, u_int32_t *)); + void fw_asy_input __P((struct ifnet *, struct mbuf *)); + void fw_asy_req_input __P((struct ifnet *, struct mbuf *)); + void fw_asy_resp_input __P((struct ifnet *, struct mbuf *)); + void fw_expire_tlabel __P((void *)); + #define SID_OTHERS 0 + #define SID_ALL 1 + void fw_sid_input __P((struct ifnet *, struct mbuf *)); + void fw_sid_set __P((struct ifnet *)); + void fw_try_bmr __P((void *)); + void fw_try_npm __P((void *)); + void reg_req_input __P((struct ifnet *, struct mbuf*)); + u_int16_t asy_lock_request __P((u_int16_t, u_int16_t, u_int32_t *, u_int32_t *, u_int32_t *)); + u_int32_t read_reg __P((struct fw_softc *, u_int32_t)); + u_int32_t write_reg __P((struct fw_softc *, u_int32_t, u_int32_t)); + + u_int32_t crcfw __P((struct mbuf *, u_int , u_int )); + + #endif /* _KERNEL */ + /* + * sockaddr_n1394 + */ + + struct sockaddr_n1394 { + u_int8_t sn1394_len; /* length */ + u_int8_t sn1394_family; + char sn1394_if[IFNAMSIZ]; /* interface name */ + u_int8_t sn1394_fch; + u_int8_t sn1394_ftag; + u_int8_t sn1394_mode; + u_int8_t sn1394_flags; + u_int8_t sn1394_sped; + u_int32_t sn1394_start_hi; + u_int32_t sn1394_start_lo; + u_int32_t sn1394_addrlen; + }; + + #define STATE_CLEAR 0x0000 + #define STATE_SET 0x0004 + #define NODE_IDS 0x0008 + #define RESET_START 0x000c + #define SPLIT_TIMEOUT_HI 0x0018 + #define SPLIT_TIMEOUT_LO 0x001c + #define CYCLE_TIME 0x0200 + #define BUS_TIME 0x0200 + #define BUS_MGR_ID 0x021c + #define BANDWIDTH_AV 0x0220 + #define CHANNELS_AV_HI 0x0224 + #define CHANNELS_AV_LO 0x0228 + + #define CONF_ROM 0x0400 + + #define TOPO_MAP 0x1000 + #define SPED_MAP 0x2000 + + #define oMPR 0x900 + #define oPCR 0x904 + + #define iMPR 0x980 + #define iPCR 0x984 + + #define IP_CHANNELS 0x0234 + #ifdef _KERNEL + + struct n1394pcb { + LIST_ENTRY(n1394pcb) pcblist; + u_int n1394p_inq; + struct socket *n1394p_socket; + struct ifnet *n1394p_ifp; + u_int8_t n1394p_fch; + u_int8_t n1394p_ftag; + u_int8_t n1394p_mode; + u_int8_t n1394p_flags; + }; + + /* flags */ + #define N1394P_FREE 0x01 /* free (not on any list) */ + #define N1394P_CONNECTED 0x02 /* connected */ + #define N1394P_NET 0x04 + #define N1394P_DRAIN 0x08 /* destory as soon as inq == 0 */ + + #define N1394P_REMOVE 0 /* remove from global list */ + #define N1394P_DESTROY 1 /* destroy and be free */ + + LIST_HEAD(n1394plist, n1394pcb); + + /* global data structures */ + + struct n1394plist n1394_pcbs; + extern struct ifqueue n1394intrq; + extern u_int n1394_sodropcnt, + n1394_sodropbytes; + extern u_int n1394_sookcnt, + n1394_sookbytes; + + struct n1394pcb *n1394p_alloc __P((int)); + void n1394p_free __P((struct n1394pcb *, int)); + struct n1394pcb *n1394isop_add __P((struct n1394pcb *, struct ifnet *, u_int8_t, u_int8_t, u_int8_t)); + struct n1394pcb *n1394asyp_add __P((struct n1394pcb *, struct ifnet *, u_int8_t)); + + extern struct pr_usrreqs n1394_usrreqs; + void n1394intr __P((void)); + #endif /* _KERNEL */ + + #define IP_CHANNELS 0x0234 + #define INITREG(sc, offset) (sc)->init_reg[(offset)/4] + diff -r -c -N sys44.orig/net/if_fwsubr.c sys/net/if_fwsubr.c *** sys44.orig/net/if_fwsubr.c Thu Jan 1 09:00:00 1970 --- sys/net/if_fwsubr.c Tue Oct 9 21:55:23 2001 *************** *** 0 **** --- 1,1824 ---- + /* + * Copyright (c) 1998 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by K. Kobayashi + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: if_fwsubr.c,v 1.1.2.1 2000/06/04 17:19:15 ikob Exp $ + * + */ + + #include "opt_inet.h" + + #define DDB(x) x + #define DEB(x) + #define DEBUG_PACKET + #undef DEBUG_PACKET + #define MAXIPFRAG 40 + + #define PREVENT_ISOHDR + #undef PREVENT_ISOHDR + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + + #include + + #ifdef INET + #include + #include + #include + #endif + #include + #include + #include + + + #ifdef __FreeBSD__ + #include /* for rdtsc proto for clock.h below */ + #include + #include + #include + #include /* for vtophys proto */ + #include + + /* #include */ + + char linkspeed[4][0x10]={"S100","S200","S400","Unknown"}; + char ackcode[32][0x20]={ + "Undef","Ret. overrun(LINK)","comp","Timeout(LINK)", + "pend","FIFO underrun(LINK)","Undef","RX CRC err(LINK)", + "bsy X","Lost EOT(DMA)","bsy A","Lost SOT(DMA)", + "bsy B","Pipeline err(DMA)","Undef","", + "Undef","","Undef","","Undef","","Undef","", + "Undef","","dt err","", + "ty err","Corrupt HDR(LINK)","Undef",""}; + + typedef int ioctl_cmd_t; + + + #define IFNAME(sc) (sc)->ac.ac_if.if_name + #define IFARG(sc) (sc)->ac.ac_if.if_unit + + #endif /* __FreeBSD__ */ + + #define senderr(e) { error = (e); goto bad;} + + typedef u_char bool_t; + + #define LYNXMTU 1500 + + static void fw_ip_input __P((struct ifnet *, struct mbuf *)); + static int fw_ip_output __P((struct ifnet *, + struct mbuf *, struct ip1394arp *)); + static void fw_bindinit __P((struct fw_softc *)); + static void fw_rcv_npm __P((struct ifnet *, struct mbuf *)); + static void fw_set_npm __P((struct ifnet *, u_int32_t)); + static void fw_rcv_bmr __P((struct ifnet *, struct mbuf *)); + static void fw_set_bmr __P((struct ifnet *, u_int32_t)); + static void fw_lock_request_input __P((struct ifnet *, struct mbuf *)); + + void fw_bindinit(fc) + struct fw_softc *fc; + { + int i; + fc->fw_nbind = 0; + for ( i = 0 ; i < FW_MAXREGBIND ; i++){ + fc->bind_list[i].type = FWBIND_NULL; + fc->bind_list[i].start_hi = 0; + fc->bind_list[i].start_lo = 0; + fc->bind_list[i].addrlen = 0; + } + } + + struct fw_bind *fw_bindlookup(fc, dest_hi, dest_lo) + struct fw_softc *fc; + u_int32_t dest_lo, dest_hi; + { + int i; + for(i = 0 ; i < FW_MAXREGBIND ; i++ ){ + if(fc->bind_list[i].type != FWBIND_NULL && + fc->bind_list[i].start_hi == dest_hi && + fc->bind_list[i].start_lo <= dest_lo && + (fc->bind_list[i].start_lo + + fc->bind_list[i].addrlen) > dest_lo){ + return(&fc->bind_list[i]); + } + } + return(NULL); + } + void fw_bindremove(fc, fwbind) + struct fw_softc *fc; + struct fw_bind fwbind; + { + int i = 0, j, s; + struct fw_bind *blist = fc->bind_list; + + for( i = 0 ; i < fc->fw_nbind ; i ++){ + if(fwbind.type == blist[i].type){ + if(fwbind.type == FWBIND_HAND){ + if(fwbind.resp.hand == blist[i].resp.hand ){ + break; + } + } + if(fwbind.type == FWBIND_PCB){ + if(fwbind.resp.pcb == blist[i].resp.pcb ){ + break; + } + } + + } + } + if( i == fc->fw_nbind) + return; + + s = splnet(); + + blist[fc->fw_nbind - 1].type = FWBIND_NULL; + for( j = i ; j < fc->fw_nbind - 1; j++){ + blist[j] = blist[j + 1]; + } + + fc->fw_nbind --; + splx(s); + + return; + } + + int fw_bindadd(fc, fwbind) + struct fw_softc *fc; + struct fw_bind fwbind; + { + int i, j, s; + struct fw_bind *blist = fc->bind_list; + + if(fc->fw_nbind >= FW_MAXREGBIND ) return -1; + for( i = 0 ; i < fc->fw_nbind ; i ++){ + if(fwbind.start_hi == blist[i].start_hi){ + if((fwbind.start_lo + fwbind.addrlen) < + blist[i].start_lo){ + if(fwbind.start_lo > + (blist[i].start_lo + blist[i].addrlen)){ + return -1; + }else{ + break; + } + } + }else if(fwbind.start_hi < blist[i].start_hi){ + break; + } + } + + s = splnet(); + + for( j = fc->fw_nbind; j > i ; j --){ + blist[j] = blist[j - 1]; + } + blist[i] = fwbind; + fc->fw_nbind ++; + splx(s); + return(fc->fw_nbind); + } + + u_int32_t fw_setbmslot(ifp, ch) + register struct ifnet *ifp; + u_int32_t ch; + { + struct fw_softc *fc = (struct fw_softc *)(ifp->if_softc); + struct arpcom *ac = (struct arpcom *)(ifp->if_softc); + u_int32_t och; + + och = ac->media.firewire.broadcast & 0x3f; + ch &= 0x3f; + + if( fc->isoslot[ch].type != ISOSLOT_NULL){ + if( fc->isoslot[och].type == ISOSLOT_HAND && + fc->isoslot[och].resp.hand == fw_ip_input ){ + return(och); + }else{ + return(-1); + } + } + if( fc->isoslot[och].type != ISOSLOT_NULL){ + fc->isoslot[och].type = ISOSLOT_NULL; + } + fc->isoslot[ch].type = ISOSLOT_HAND; + fc->isoslot[ch].resp.hand = fw_ip_input; + return(ch); + } + /* Call every after busreset */ + void if_fwbusreset(fc) + struct fw_softc *fc; + { + u_int i, node; + + + INITREG(fc, TOPO_MAP + 8) = 0; + fc->irm = -1; + + node = (INITREG(fc, NODE_IDS) >> 16) & 0x3f; + fc->max_node = node; + + for(i = 2; i < 0x100/4 - 2 ; i++){ + INITREG(fc, SPED_MAP + i * 4); + } + INITREG(fc, STATE_CLEAR) = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ; + INITREG(fc, STATE_SET) = INITREG(fc, STATE_CLEAR); + INITREG(fc, RESET_START) = 0; + INITREG(fc, SPLIT_TIMEOUT_HI) = 0; + INITREG(fc, SPLIT_TIMEOUT_LO) = 800 << 19; + INITREG(fc, CYCLE_TIME) = 0x0; + INITREG(fc, BUS_TIME) = 0x0; + INITREG(fc, BUS_MGR_ID) = 0x3f; + INITREG(fc, BANDWIDTH_AV) = 4915; + INITREG(fc, CHANNELS_AV_HI) = 0xffffffff; + INITREG(fc, CHANNELS_AV_LO) = 0xffffffff; + INITREG(fc, IP_CHANNELS) = (1 << 31); + + INITREG(fc, CONF_ROM) = 0x04 << 24; + INITREG(fc, CONF_ROM + 4) = 0x31333934; /* means strings 1394 */ + INITREG(fc, CONF_ROM + 8) = 1 << 31 | 1 << 30 | 1 << 29 | + 1 << 28 | 0xff << 16 | 0x09 << 8; + INITREG(fc, CONF_ROM + 0xc) = 0; + + /* DV depend CSRs see blue book */ + INITREG(fc, oPCR) &= ~DV_BROADCAST_ON; + INITREG(fc, iPCR) &= ~DV_BROADCAST_ON; + + /* IP arp data preparation */ + fc->ac.media.firewire.arpdata.node = (INITREG(fc, NODE_IDS) >> 16 ); + fc->ac.media.firewire.arpdata.fifo_h = 0; + fc->ac.media.firewire.arpdata.fifo_l = IPFIFO; + fc->ac.media.firewire.arpdata.maxrec = MAXREC_512; + fc->ac.media.firewire.arpdata.spd = S100; + } + + /* Call once after reboot, also call if_fwbusreset()*/ + void if_fwinit(fc) + struct fw_softc *fc; + { + int i; + struct fw_bind fwbind; + + fc->fw_flags = 0; + fc->txdv = NULL; + fc->txstop = NULL; + fc->rxdv = NULL; + fc->rxstop = NULL; + fc->set_bmr = NULL; + fc->set_irm = NULL; + /* Initialize csr registers */ + INITREG(fc, TOPO_MAP) = 0x3f1 << 16; + INITREG(fc, TOPO_MAP + 4) = 1; + INITREG(fc, SPED_MAP) = 0x3f1 << 16; + INITREG(fc, SPED_MAP + 4) = 1; + /* Initialize ISO handlers */ + for( i = 0 ; i < 0x40 ; i++){ + fc->isoslot[i].type = ISOSLOT_NULL; + } + + /* Initialize Async transaction handler */ + for( i = 0 ; i < 0x40 ; i++){ + fc->tlabel[i].type = TLABEL_NULL; + fc->tlabel[i].expire = 0; + } + + /* Initialize address bind list */ + fw_bindinit(fc); + + fwbind.type = FWBIND_HAND; + fwbind.start_hi = 0x0000ffff; + fwbind.start_lo = 0xf0000000; + fwbind.addrlen = 0x3000; + fwbind.resp.hand = reg_req_input; + + fw_bindadd(fc, fwbind); + + fwbind.type = FWBIND_HAND; + fwbind.start_hi = 0x0; + fwbind.start_lo = IPFIFO; + fwbind.addrlen = 0x4; + fwbind.resp.hand = fw_ip_input; + + fw_bindadd(fc, fwbind); + + /* DV depend CSRs see blue book */ + + INITREG(fc, oMPR) = 0x3fff0001; /* # output channel = 1 */ + INITREG(fc, oPCR) = 0x8000007a; + for(i = 4 ; i < 0x7c/4 ; i+=4){ + INITREG(fc, i + oPCR) = 0x8000007a; + } + + INITREG(fc, iMPR) = 0x00ff0001; /* # input channel = 1 */ + INITREG(fc, iPCR) = 0x803f0000; + for(i = 4 ; i < 0x7c/4 ; i+=4){ + INITREG(fc, i + iPCR) = 0x0; + } + + fc->dv_intr = 240; + + if_fwbusreset(fc); + fc->fw_bmrhandle = timeout(fw_expire_tlabel, (void *)fc, 1 * hz); + } + + static int fw_ip_output(ifp, m, dst) + register struct ifnet *ifp; + struct mbuf *m; + struct ip1394arp *dst; + { + u_int last = 0, speed, linkmtu, sz, frag = 0; + int error = 0, s, i; + struct fw_softc *sc = (struct fw_softc *)ifp->if_softc; + struct fwasyhdr *ald; + struct fwisohdr *ild; + u_int32_t *ld; + struct mbuf *fm[MAXIPFRAG]; + + speed = dst->spd; + linkmtu = 512;/* tentative , refer dst->maxrec*/ + if((ntohs(dst->node) & 0x3f ) != 0x3f){ + sz = sizeof(struct fwasyhdr); + }else{ + sz = sizeof(struct fwisohdr); + } + /* Header CRC + IP/1394 Hdr + DataCRC */ + linkmtu -= (4 + 4); + sz += sizeof(struct fw_ip); + if( linkmtu >= (sz + m->m_pkthdr.len + 4)){ + M_PREPEND(m, sz, M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + if((ntohs(dst->node) & 0x3f ) != 0x3f){ + ald = mtod(m, struct fwasyhdr *); + ald->cntl[0] = PROTO_N1394ASYRQ; + ald->data[0] = htonl (0x00000010 + | ntohs(dst->node) << 16); + ald->data[1] = htonl( + INITREG(sc, NODE_IDS)) | dst->fifo_h; + ald->data[2] = dst->fifo_l; + ald->data[3] = + htonl((m->m_pkthdr.len - sizeof(struct fwasyhdr)) << 16); + ld = mtod(m, u_int32_t *); + ld += sizeof(struct fwasyhdr)/4; + }else{ + ild = mtod(m, struct fwisohdr *); + ild->cntl[0] = PROTO_N1394ASYST; + ild->data[0] = + htonl ( 0x000000a0 + | (ntohs(dst->fifo_h) & 0xff )<< 8 + | ((m->m_pkthdr.len - sizeof(struct fwisohdr) ) << 16 )); + + ld = mtod(m, u_int32_t *); + ld += sizeof(struct fwisohdr)/4; + } + *ld = htonl(0x800); + }else{ + sz += sizeof(struct fw_ip_frag); + for(frag = 0 ; (frag < MAXIPFRAG) && (last == 0); frag++){ + fm[frag] = NULL; + M_PREPEND(m, sz, M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + if( linkmtu < (sz + m->m_pkthdr.len + 4)){ /* why 4 */ + fm[frag] = m; + m = m_split(m, linkmtu - 4 , M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + }else{ + last = 1; + fm[frag] = m; + } + if((ntohs(dst->node) & 0x3f ) != 0x3f){ + ald = mtod(fm[frag], struct fwasyhdr *); + ald->cntl[0] = PROTO_N1394ASYRQ; + ald->data[0] = htonl (0x00000010 | + ntohs(dst->node) << 16); + ald->data[1] = htonl((INITREG(sc, NODE_IDS))) + | dst->fifo_h; + ald->data[2] = dst->fifo_l; + ald->data[3] = + htonl((fm[frag]->m_pkthdr.len - sizeof(struct fwasyhdr)) << 16); + ld = mtod(fm[frag], u_int32_t *); + ld += sizeof(struct fwasyhdr)/4; + }else{ + ild = mtod(fm[frag], struct fwisohdr *); + ild->cntl[0] = PROTO_N1394ASYST; + ild->data[0] = + htonl ( 0x000000a0 | (ntohs(dst->fifo_h) & 0xff )<< 8 + | ((fm[frag]->m_pkthdr.len - sizeof(struct fwisohdr )) << 16 )); + ld = mtod(fm[frag], u_int32_t *); + ld += sizeof(struct fwisohdr)/4; + } + if(frag){ + *ld = htonl(3<<30 + | (fm[frag - 1]->m_pkthdr.len)); + if(last) + *ld &= ~htonl(1<<30); + }else{ + *ld = htonl(1<<30 | 0x800); + } + ld += 1; + *ld = htonl(INITREG(sc, NODE_IDS)| (ifp->if_opackets << 16 )); + } + if( frag >= MAXIPFRAG ){ + senderr(ENOBUFS); + } + } + if( frag == 0 ){ + s = splimp(); + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + splx(s); + senderr(ENOBUFS); + } + ifp->if_obytes += m->m_pkthdr.len; + IF_ENQUEUE(&ifp->if_snd, m); + }else{ + #define IF_QFULL_N(ifq, n) (((ifq)->ifq_len + (n)) > (ifq)->ifq_maxlen) + s = splimp(); + if (IF_QFULL_N(&ifp->if_snd, frag)) { + IF_DROP(&ifp->if_snd); + splx(s); + senderr(ENOBUFS); + } + for(i = 0 ; i < frag ; i ++){ + ifp->if_obytes += fm[i]->m_pkthdr.len; + IF_ENQUEUE(&ifp->if_snd, fm[i]); + } + } + if ((ifp->if_flags & IFF_OACTIVE) == 0) + (*ifp->if_start)(ifp); + splx(s); + + return(error); + bad: + for(i = 0 ; i < frag ; i++){ + if(fm[i] && (fm[i] != m)) + m_freem(fm[i]); + } + if(m) + m_freem(m); + return(error); + } + int fw_output (ifp, m0, dst, rt0) + register struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; + struct rtentry *rt0; + { + struct rtentry *rt; + struct mbuf *m = m0; + int error = 0; + struct ip1394arp fwdst; + int s; + u_int32_t *ld; + struct fw_softc * sc = (struct fw_softc *)ifp->if_softc; + + /* + * check route + */ + ld = mtod(m, u_int32_t *); + if ((rt = rt0) != NULL) { + if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ + if ((rt0 = rt = rtalloc1(dst, 0, 0)) != NULL) + rt->rt_refcnt--; + else + senderr(EHOSTUNREACH); + } + + if (rt->rt_flags & RTF_GATEWAY) { + if (rt->rt_gwroute == 0) + goto lookup; + if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { + rtfree(rt); rt = rt0; + lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 0, 0); + if ((rt = rt->rt_gwroute) == 0) + senderr(EHOSTUNREACH); + } + } + + /* XXX: put RTF_REJECT code here if doing ATMARP */ + + } + + if( dst ){ + if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != + (IFF_UP|IFF_RUNNING)){ + senderr(ENETDOWN); + } + } + getmicrotime(&ifp->if_lastchange); + + if(dst){ + switch(dst->sa_family){ + case AF_INET: + if (!firewireresolve((struct arpcom *)sc, + rt, m, dst, (u_char *)&fwdst)) { + return(0); + } + return(fw_ip_output(ifp, m, &fwdst)); + break; + case AF_UNSPEC: + printf("%s%d: can't handle AF_UNSPEC\n", ifp->if_name, + ifp->if_unit); + senderr(EAFNOSUPPORT); + break; + default: + printf("%s%d: can't handle af%d\n", ifp->if_name, + ifp->if_unit, dst->sa_family); + senderr(EAFNOSUPPORT); + break; + } + } + s = splimp(); + if (IF_QFULL(&ifp->if_snd)) { + IF_DROP(&ifp->if_snd); + splx(s); + senderr(ENOBUFS); + } + ifp->if_obytes += m->m_pkthdr.len; + IF_ENQUEUE(&ifp->if_snd, m); + if ((ifp->if_flags & IFF_OACTIVE) == 0) + (*ifp->if_start)(ifp); + splx(s); + + return(error); + bad: + if(m) + m_freem(m); + return(error); + } + void fw_try_npm(void *arg) + { + struct fw_softc *fc = (struct fw_softc *)arg; + struct mbuf *m; + struct fwasyhdr *ald; + u_int32_t ipch; + u_int16_t tlabel; + struct ifnet *ifp = (struct ifnet *)&fc->ac; + + if ( INITREG(fc, IP_CHANNELS) & ( 1 << 30)){ + goto out; + } + /* If IRM found, IP channel shall assign with checking CH_AV register.*/ + if ( fc->irm == ((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f)){ + fw_set_npm(ifp, (3 << 30) | (fc->irm << 24) | 0x1f) ; + goto out; + } + if(fc->tmpnpm < 0){ + return; + } + if ( fc->tmpnpm == ((INITREG(fc, NODE_IDS) >> 16 ) &0x3f)){ + fw_set_npm(ifp, (3 << 30) | (fc->tmpnpm << 24) | 0x1f) ; + goto out; + } + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return; + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return; + } + tlabel = fw_get_tlabel(ifp, TLABEL_HAND, fw_rcv_npm); + ald = mtod(m, struct fwasyhdr *); + ald->cntl[0] = PROTO_N1394ASYRQ; + ald->data[0] = htonl(0x3ff << 22 | fc->tmpnpm << 16 | tlabel << 10 | 4 << 4); + ald->data[1] = htonl(INITREG(fc, NODE_IDS) | 0xffff); + ald->data[2] = htonl( 0xf0000000 | IP_CHANNELS ); + m->m_pkthdr.len = m->m_len = sizeof(struct fwasyhdr) - 4; + fw_output(ifp, m, NULL, NULL); + out: + if ((!(INITREG(fc, IP_CHANNELS) & ( 1 << 30))) && ( fc->tmpnpm >= 0 )){ + fc->fw_flags |= NPMEPHASE; + fc->fw_npmhandle = timeout(fw_try_npm,(void *)fc, hz/10 ); + if(fc->tmpnpm == fc->irm){ + if( fc->irm != fc->max_node){ + fc->tmpnpm = fc->max_node; + }else{ + fc->tmpnpm--; + } + }else{ + fc->tmpnpm--; + if(fc->tmpnpm == fc->irm ) fc->tmpnpm--; + } + }else{ + fc->fw_flags &= ~NPMEPHASE; + } + } + void fw_rcv_npm(ifp, m) + struct ifnet *ifp; + struct mbuf *m; + { + struct fw_softc *sc = (struct fw_softc *)(ifp->if_softc); + struct fwasyhdr *ald; + u_int32_t ipch; + ald = mtod(m, struct fwasyhdr *); + fw_set_npm(ifp, ntohl(ald->data[3])); + } + void fw_try_bmr(void *arg) + { + struct fw_softc *fc = (struct fw_softc *)arg; + struct mbuf *m; + struct fwasyhdr *ald; + u_int16_t tlabel; + struct ifnet *ifp = (struct ifnet *)&fc->ac; + + if ( INITREG(fc, BUS_MGR_ID) != 0x3f ){ + goto out; + } + if ( fc->irm < 0 ){ + goto out; + } + if ( fc->irm == ((INITREG(fc, NODE_IDS) >> 16 )& 0x3f )){ + fw_set_bmr(ifp, fc->irm); + goto out; + } + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + goto out; + + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + goto out; + } + tlabel = fw_get_tlabel(ifp, TLABEL_HAND, fw_rcv_bmr); + ald = mtod(m, struct fwasyhdr *); + ald->cntl[0] = PROTO_N1394ASYRQ; + ald->data[0] = htonl(0x3ff << 22 | fc->irm << 16 | tlabel << 10 | 9 << 4); + ald->data[1] = htonl(INITREG(fc, NODE_IDS) | 0xffff); + ald->data[2] = htonl( 0xf000021c ); + ald->data[3] = htonl( 0x80002); + ald->data[4] = htonl( 0x3f ); + ald->data[5] = htonl((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f); + m->m_pkthdr.len = m->m_len = sizeof(struct fwasyhdr) + 8; + + fw_output(ifp, m, NULL, NULL); + out: + fc->fw_flags &= ~BMEPHASE; + } + void fw_set_npm(ifp, data) + struct ifnet *ifp; + u_int32_t data; + { + u_int32_t ipch; + struct fw_softc *fc = (struct fw_softc *)(ifp->if_softc); + if (!( INITREG(fc, IP_CHANNELS) & ( 1 << 30))){ + if(data & (3 << 30 )){ + INITREG(fc, IP_CHANNELS) = data; + ipch = INITREG(fc, IP_CHANNELS); + fc->ac.media.firewire.broadcast = ipch & 0xff; + (*ifp->if_ioctl)(ifp, SIOCSNPM, (caddr_t)&ipch); + printf("IP channel assigned as 0x%02x\n", INITREG(fc, IP_CHANNELS) & 0x3f); + fc->fw_flags &= ~NPMEPHASE; + } + } + } + void fw_set_bmr(ifp, node) + struct ifnet *ifp; + u_int32_t node; + { + struct fw_softc *fc = (struct fw_softc *)(ifp->if_softc); + if ( INITREG(fc, BUS_MGR_ID) != 0x3f ){ + return; + } + if((node & 0x3f) == 0x3f ){ + INITREG(fc, BUS_MGR_ID) + = (INITREG(fc, NODE_IDS) >> 16 ) & 0x3f; + }else{ + INITREG(fc, BUS_MGR_ID) = node & 0x3f; + if( fc->set_bmr != NULL ) + fc->set_bmr(fc); + } + printf("%s%d BMR = %x\n", + IFNAME(fc), IFARG(fc), INITREG(fc, BUS_MGR_ID)); + if (!( INITREG(fc, IP_CHANNELS) & ( 1 << 30))){ + if( fc->irm == ((INITREG(fc, NODE_IDS) >> 16 )& 0x3f)){ + fw_set_npm(ifp, (3 << 30) | (fc->irm << 24) | 0x1f) ; + return; + }else if(fc->irm != -1){ + fc->tmpnpm = fc->irm; + }else { + fc->tmpnpm = fc->max_node; + } + if(fc->fw_flags & NPMEPHASE){ + untimeout(fw_try_npm, (void *)fc, fc->fw_npmhandle); + } + fw_try_npm(fc); + } + } + void fw_rcv_bmr(ifp, m) + struct ifnet *ifp; + struct mbuf *m; + { + struct fwasyhdr *ald; + int node; + ald = mtod(m, struct fwasyhdr *); + node = ntohl(ald->data[4] & 0x3f); + fw_set_bmr(ifp, node); + } + void fw_stream_input(ifp, m) + struct ifnet *ifp; + struct mbuf *m; + { + register struct fwisohdr *ild; + register struct ifqueue *inq; + struct fw_softc *sc = (struct fw_softc *)(ifp->if_softc); + int ch, src; + int s; + + ild = mtod(m, struct fwisohdr *); + #if 0 + ch = (ntohl(ild->data[0]) >> 8) & 0x3f; + #else + ch = (ntohl(ild->data[0]) >> 8) & 0xff; + #endif + if(sc->isoslot[ch].type == ISOSLOT_PCB){ + m->m_pkthdr.rcvif = sc->isoslot[ch].resp.pcb; + + getmicrotime(&ifp->if_lastchange); + ifp->if_ibytes += m->m_pkthdr.len; + + schednetisr(NETISR_1394); + inq = &n1394intrq; + + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else { + IF_ENQUEUE(inq, m); + } + splx(s); + + }else if(sc->isoslot[ch].type == ISOSLOT_HAND){ + sc->isoslot[ch].resp.hand(ifp, m); + }else{ + #ifdef DEBUG_PACKET + printf("%s%d packet from unknown channel = 0x%2x\n", + IFNAME(sc), IFARG(sc), ch); + #endif + if(m) + m_freem(m); + return; + } + return; + } + void fw_ip_input(ifp, m) + struct ifnet *ifp; + struct mbuf *m; + { + register struct ifqueue *inq; + struct fw_softc *sc = (struct fw_softc *)(ifp->if_softc); + struct fwhdr *fld; + struct fwasyhdr *ald; + u_int32_t *ld; + u_int32_t link; + int s; + int frag; + int src; + struct mbuf **fm; + fld = mtod(m, struct fwhdr *); + + if(fld->cntl[0] == PROTO_N1394ISOST){ + src = ntohl(fld->data[2]) & 0x3f; + m_adj(m, sizeof(struct fwisohdr)); + fm = &sc->isofrag[src]; + }else{ + int tcode; + src = (ntohl(fld->data[1]) >>16 ) & 0x3f; + ald = mtod(m, struct fwasyhdr *); + tcode = (ntohl( ald->data[0]) >> 4 ) & 0xf; + if( tcode != TCODE_BLKWRREQ ) + goto bad; + m_adj(m, sizeof(struct fwasyhdr)); + fm = &sc->asyfrag[src]; + /* Block write only */ + } + + getmicrotime(&ifp->if_lastchange); + ifp->if_ibytes += m->m_pkthdr.len; + + ld = mtod(m, u_int32_t *); + + frag = ntohl(*ld) >> 30; + switch(frag){ + case 0: + /* only clear chain */ + *fm = 0; + break; + case 1: + if(*fm != 0){ + printf("%s%d 1394 reassembly error, first\n", + IFNAME(sc), IFARG(sc)); + } + *fm = m; + return; + break; + case 2: + if(*fm == 0){ + printf("%s%d 1394 reassembly error, last\n", + IFNAME(sc), IFARG(sc)); + *fm = 0; + goto bad; + } + m_adj(m, 8); + (*fm)->m_pkthdr.len += m->m_pkthdr.len; + m_cat(*fm, m); + m = *fm; + *fm = 0; + ld = mtod(m, u_int32_t *); + ld[1] = ld[0]; /* overide fragment hdr by ether hdr */ + m_adj(m, 4); + break; + case 3: + if(*fm == 0){ + printf("%s%d 1394 reassembly error, interium\n", + IFNAME(sc), IFARG(sc)); + *fm = 0; + goto bad; + } + m_adj(m, 8); + (*fm)->m_pkthdr.len += m->m_pkthdr.len; + m_cat(*fm, m); + return; + break; + default: + goto bad; + break; + } + /* Remove ether header or link header */ + ld = mtod(m, u_int32_t *); + link = ntohl(*ld) & 0xffff; + m_adj(m, 4); + switch(link){ + #ifdef INET + case 0x800: + schednetisr(NETISR_IP); + inq = &ipintrq; + break; + case 0x806: + schednetisr(NETISR_ARP); + inq = &arpintrq; + break; + #endif + default: + goto bad; + break; + } + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else { + IF_ENQUEUE(inq, m); + } + splx(s); + return; + bad: + if(m) + m_freem(m); + return; + } + u_int16_t asy_lock_request(op, len, old, arg_data, mask) + u_int16_t len; + u_int16_t op; + u_int32_t *old; + u_int32_t *arg_data; + u_int32_t *mask; + { + u_int32_t ret, temp; + u_int32_t *arg, *data; + switch(op){ + case 1: + switch(len){ + case 8: + arg = &arg_data[0]; + data = &arg_data[1]; + temp = data[0] | (old[0] & ~arg[0]); + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + ret = 4; + break; + case 16: + arg = &arg_data[0]; + data = &arg_data[2]; + temp = data[0] | (old[0] & ~arg[0]); + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + temp = data[1] | (old[1] & ~arg[1]); + old[1] = (temp & ~mask[1]) | ( old[1] & mask[1]); + ret = 8; + break; + default: + ret = 0; + break; + } + break; + case 2: + switch(len){ + case 8: + arg = &arg_data[0]; + data = &arg_data[1]; + if(old[0] == arg[0]){ + temp = data[0]; + }else{ + temp = old[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + ret = 4; + break; + case 16: + arg = &arg_data[0]; + data = &arg_data[2]; + if(old[0] == arg[0]){ + temp = data[0]; + }else{ + temp = old[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + if(old[1] == arg[1]){ + temp = data[1]; + }else{ + temp = old[1]; + } + old[1] = (temp & ~mask[1]) | ( old[1] & mask[1]); + ret = 8; + break; + default: + ret = 0; + break; + } + break; + case 3: + switch(len){ + case 4: + data = &arg_data[0]; + temp = old[0] + data[0]; + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + ret = 4; + break; + case 8: + data = &arg_data[0]; + temp = old[0] + data[0]; + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + temp = old[1] + data[1]; + old[1] = (temp & ~mask[1]) | ( old[0] & mask[1]); + ret = 8; + break; + default: + ret = 0; + break; + } + break; + case 5: + switch(len){ + case 8: + arg = &arg_data[0]; + data = &arg_data[1]; + if(old[0] != arg[0]){ + temp = old[0] + data[0]; + }else{ + temp = old[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + ret = 4; + break; + case 16: + arg = &arg_data[0]; + data = &arg_data[2]; + if(old[0] != arg[0]){ + temp = old[0] + data[0]; + }else{ + temp = old[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + if(old[1] != arg[1]){ + temp = old[1] + data[1]; + }else{ + temp = old[1]; + } + old[1] = (temp & ~mask[1]) | ( old[1] & mask[1]); + ret = 8; + break; + default: + ret = 0; + break; + } + break; + case 6: + switch(len){ + case 8: + arg = &arg_data[0]; + data = &arg_data[1]; + if(old[0] != arg[0]){ + temp = old[0] + data[0]; + }else{ + temp = data[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + ret = 4; + break; + case 16: + arg = &arg_data[0]; + data = &arg_data[2]; + if(old[0] != arg[0]){ + temp = old[0] + data[0]; + }else{ + temp = data[0]; + } + old[0] = (temp & ~mask[0]) | ( old[0] & mask[0]); + if(old[1] != arg[1]){ + temp = old[1] + data[1]; + }else{ + temp = data[1]; + } + old[1] = (temp & ~mask[1]) | ( old[1] & mask[1]); + ret = 8; + break; + default: + ret = 0; + break; + } + break; + case 4: + /* endian depend addition */ + default: + ret = 0; + break; + } + return ret; + } + void asy_read_resp(ifp, ald, data) + struct ifnet *ifp; + struct fwasyhdr *ald; + u_int32_t data; + { + struct mbuf *mm; + struct fwasyhdr *tld; + u_int16_t tlabel, retry; + + tlabel = (ntohl( ald->data[0]) >> 10 ) & 0x3f; + retry = (ntohl( ald->data[0]) >> 8 ) & 0x3; + + MGETHDR(mm, M_DONTWAIT, MT_DATA); + if (mm == NULL) + return; + MCLGET(mm, M_DONTWAIT); + if ((mm->m_flags & M_EXT) == 0) { + m_freem(mm); + return; + } + + tld = mtod(mm, struct fwasyhdr *); + tld->cntl[0] = PROTO_N1394ASYRQ; + tld->data[0] = htonl((ntohl(ald->data[1])) & 0xffff0000 | + tlabel << 10 | retry << 8 | 0x06 << 4 ); + tld->data[1] = htonl((ntohl(ald->data[0])) & 0xffff0000 ); + tld->data[2] = 0x0; + tld->data[3] = htonl(data); + /* + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[0])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[1])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[2])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[3])); + */ + mm->m_pkthdr.len = mm->m_len = sizeof(struct fwasyhdr); + + fw_output(ifp, mm, NULL, NULL); + return; + } + void asy_lock_resp(ifp, ald, data, mask) + struct ifnet *ifp; + struct fwasyhdr *ald; + u_int32_t mask[2], data[2]; + { + u_int32_t arg_data[4]; + u_int16_t ecode; + u_int32_t old[2]; + u_int16_t total_len, ret_len; + struct mbuf *mm; + struct fwasyhdr *tld; + u_int16_t tlabel, retry; + int i; + + tlabel = (ntohl( ald->data[0]) >> 10 ) & 0x3f; + retry = (ntohl( ald->data[0]) >> 8 ) & 0x3; + + ecode = ntohl(ald->data[3]) & 0xffff; + total_len = (ntohl(ald->data[3])>>16) & 0xffff; + for( i = 0 ; i < (total_len / 4); i++ ){ + arg_data[i] = ntohl(ald->data[i+4]); + } + old[0] = data[0]; + old[1] = data[1]; + mask[0] = mask[1] = 0; + ret_len = asy_lock_request(ecode, total_len, + data, arg_data, mask); + MGETHDR(mm, M_DONTWAIT, MT_DATA); + if (mm == NULL) + return; + MCLGET(mm, M_DONTWAIT); + if ((mm->m_flags & M_EXT) == 0) { + m_freem(mm); + return; + } + tld = mtod(mm, struct fwasyhdr *); + tld->cntl[0] = PROTO_N1394ASYRQ; + tld->data[0] = htonl((ntohl(ald->data[1])) & 0xffff0000 | + tlabel << 10 | retry << 8 | 0x0b << 4 ); + tld->data[1] = htonl((ntohl(ald->data[0])) & 0xffff0000 ); + tld->data[2] = 0x0; + tld->data[3] = htonl(ret_len << 16 | ecode); + if(ret_len == 4){ + tld->data[4] = htonl(old[0]); + }else if(ret_len == 8){ + tld->data[4] = htonl(old[0]); + tld->data[5] = htonl(old[1]); + } + /* + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[0])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[1])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[2])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[3])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[4])); + printf("%s%d tld = 0x%08x\n", IFNAME(sc), IFARG(sc), ntohl(tld[5])); + */ + mm->m_pkthdr.len = mm->m_len = sizeof (struct fwasyhdr) + ret_len; + fw_output(ifp, mm, NULL, NULL); + return; + } + void reg_req_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + struct fwasyhdr *ald; + struct fw_softc *sc = ifp->if_softc; + u_int32_t addr; + u_int32_t mask[2], *data; + u_int16_t tcode, tlabel, retry; + + ald = mtod(m, struct fwasyhdr *); + printf("Access CSR registers 0x%08lx\n", ntohl(ald->data[2])& 0xffff); + tcode = (ntohl( ald->data[0]) >> 4 ) & 0xf; + tlabel = (ntohl( ald->data[0]) >> 10 ) & 0x3f; + retry = (ntohl( ald->data[0]) >> 8 ) & 0x3; + + addr = 0xfffc & ntohl(ald->data[2]); /* Allign 4bytes boundary */ + + if(addr == BUS_TIME){ + printf("%s%d BUS_TIME\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_RDREQ: + INITREG(sc, addr) = *sc->p_cycle_timer >> 24; + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == CYCLE_TIME){ + printf("%s%d CYCLE_TIME\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_RDREQ: + INITREG(sc, addr) = *sc->p_cycle_timer; + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == RESET_START){ + printf("%s%d RESET_START\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_WRREQ: + sc->fw_busreset(sc); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == NODE_IDS){ + printf("%s%d NODE_IDS\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_WRREQ: + INITREG(sc, addr) + = ( 0x3ff << 22) & ntohl(ald->data[3]); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == STATE_CLEAR || addr == STATE_SET){ + printf("%s%d STATE_CLEAR or SET\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == SPLIT_TIMEOUT_HI|| addr == SPLIT_TIMEOUT_LO ){ + printf("%s%d SPLIT_TIMEOUT\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_WRREQ: + INITREG(sc, addr) = ntohl(ald->data[3]); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == BUS_MGR_ID){ + printf("%s%d BUS_MGR_ID\n", IFNAME(sc), IFARG(sc)); + if(sc->irm == ((INITREG(sc, NODE_IDS) >> 16 )&0x3f)){ + switch(tcode){ + case TCODE_LKREQ: + data = &INITREG(sc, addr); + mask[0] = mask[1] = 0; + asy_lock_resp(ifp, ald, data, mask); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + } + if(addr == BANDWIDTH_AV){ + printf("%s%d BW_AV_REG\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_LKREQ: + data = &INITREG(sc, addr); + mask[0] = mask[1] = 0; + asy_lock_resp(ifp, ald, data, mask); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + + } + } + if(addr == CHANNELS_AV_HI|| addr == CHANNELS_AV_LO){ + printf("%s%d CH_AV_REG\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_LKREQ: + data = &INITREG(sc, addr); + mask[0] = mask[1] = 0; + asy_lock_resp(ifp, ald, data, mask); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + + } + } + if( oMPR <= addr && addr <= (oMPR + 0x100)){ + printf("%s%d VIDEO control register\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_LKREQ: + data = &(INITREG(sc, addr)); + mask[0] = mask[1] = 0; + asy_lock_resp(ifp, ald, data, mask); + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + if(addr == IP_CHANNELS){ + u_int32_t tmp_ch = INITREG(sc, IP_CHANNELS); + printf("%s%d NPM register\n", IFNAME(sc), IFARG(sc)); + switch(tcode){ + case TCODE_LKREQ: + data = &INITREG(sc, addr); + mask[0] = mask[1] = 0; + asy_lock_resp(ifp, ald, data, mask); + if(tmp_ch != INITREG(sc, IP_CHANNELS) ){ + u_int32_t new_ch; + new_ch = INITREG(sc, IP_CHANNELS); + (*ifp->if_ioctl)(ifp, SIOCSNPM, (caddr_t)&new_ch); + printf("IP channel assigned as 0x%02x\n", INITREG(sc, IP_CHANNELS) & 0x3f); + } + return; + break; + case TCODE_RDREQ: + asy_read_resp(ifp, ald, INITREG(sc, addr)); + return; + break; + default: + printf("unknown \n"); + break; + } + } + + #ifdef DEBUG_PACKET + printf("%s%d Unknown request\n")} + printf("len = %d:0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", + IFNAME(sc), + IFARG(sc), + m->m_pkthdr.len, + ntohl(ald->data[0]), + ntohl(ald->data[1]), + ntohl(ald->data[2]), + ntohl(ald->data[3]), + ntohl(ald->data[4]), + ntohl(ald->data[5])); + #endif + return; + } + void fw_lock_responce_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + /* Checking a previous updation first */ + /* + timeout + corresponding src + corresponding dst + corresponding addr + corresponding etcode + */ + register struct fwasyhdr *ald; + struct fw_softc *sc = ifp->if_softc; + int src; + + ald = mtod(m, struct fwasyhdr *); + if((ntohl(ald->data[2]) == 0xf000021c ) && + (ntohl(ald->data[3]) == 0x40002 )){ + + src = (ntohl( ald->data[1]) >> 16) & 0x3f; + if(INITREG(sc, BUS_MGR_ID) == 0x3f){ + INITREG(sc, BUS_MGR_ID) = ntohl(ald->data[4]) & 0x3f; + printf("%s%d Bus master address is obtained %x\n", IFNAME(sc), IFARG(sc), INITREG(sc, BUS_MGR_ID)); + } + } + m_freem(m); + } + void fw_lock_request_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + register struct fwasyhdr *ald; + struct fw_softc *sc = ifp->if_softc; + struct fwasyhdr *tld; + int src; + + ald = mtod(m, struct fwasyhdr *); + if((ntohl(ald->data[2]) == 0xf000021c ) && + (ntohl(ald->data[3]) == 0x80002 )){ + struct mbuf *mm; + + src = (ntohl( ald->data[1]) >> 16) & 0x3f; + if(INITREG(sc, BUS_MGR_ID) == 0x3f){ + INITREG(sc, BUS_MGR_ID) = src; + } + MGETHDR(mm, M_DONTWAIT, MT_DATA); + if (mm == NULL){ + m_freem(m); + return; + } + MCLGET(mm, M_DONTWAIT); + if ((mm->m_flags & M_EXT) == 0) { + m_freem(m); + m_freem(mm); + return; + } + tld = mtod(mm, struct fwasyhdr *); + tld->cntl[0] = PROTO_N1394ASYRQ; + tld->data[0] = htonl(src << 16 | 0x0b << 4); + tld->data[1] = htonl(INITREG(sc, NODE_IDS) | 0xffff); + tld->data[2] = htonl( 0xf000021c ); + tld->data[3] = htonl( 0x40002); + tld->data[4] = htonl( INITREG(sc, BUS_MGR_ID) ); + mm->m_pkthdr.len = m->m_len = sizeof(struct fwasyhdr)+ 4; + fw_output(ifp, mm, NULL, NULL); + m_freem(m); + } + } + void fw_asy_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + register struct fwasyhdr *ald; + struct fw_softc *fc = ifp->if_softc; + u_int tcode; + u_int32_t dest_hi; + u_int32_t dest_lo; + + ald = mtod(m, struct fwasyhdr *); + tcode = (ntohl( ald->data[0]) >> 4 ) & 0xf; + + switch(tcode){ + /* PH config packet */ + case TCODE_PHCONF: + if(m) + m_freem(m); + return; + break; + /* if the request offset is CSR base entry, kernel respond itself. */ + case TCODE_WRREQ: + case TCODE_BLKWRREQ: + case TCODE_RDREQ: + case TCODE_BLKRDREQ: + case TCODE_LKREQ: + fw_asy_req_input(ifp, m); + return; + break; + + /* if the request offset is the respond of previous action, proceed it */ + case TCODE_WRRES: + case TCODE_RDRES: + case TCODE_BLKRDRES: + case TCODE_LKRES: + fw_asy_resp_input(ifp, m); + return; + break; + default: + goto bad; + break; + } + bad: + if(m) + m_freem(m); + return; + } + void fw_asy_req_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + register struct fwasyhdr *ald; + register struct ifqueue *inq; + struct fw_softc *fc = ifp->if_softc; + struct fw_bind *fwbind; + int s, i; + u_int32_t dest_hi; + u_int32_t dest_lo; + + ald = mtod(m, struct fwasyhdr *); + dest_hi = ntohl(ald->data[1]) & 0xffff; + dest_lo = ntohl(ald->data[2]) & ~0x3; + + fwbind = fw_bindlookup(fc, dest_hi, dest_lo); + if(fwbind != NULL){ + if( fwbind->type == FWBIND_HAND ){ + fwbind->resp.hand(ifp, m); + /* + if(m) + m_freem(m); + */ + return; + }else if( fwbind->type == FWBIND_PCB ){ + m->m_pkthdr.rcvif = fwbind->resp.pcb; + getmicrotime(&ifp->if_lastchange); + ifp->if_ibytes += m->m_pkthdr.len; + schednetisr(NETISR_1394); + inq = &n1394intrq; + + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); + return; + } + } + bad: + if(m) + m_freem(m); + return; + } + void fw_asy_resp_input(ifp, m ) + struct ifnet *ifp; + struct mbuf *m; + { + register struct ifqueue *inq; + register struct fwasyhdr *ald; + struct fw_softc *fc = ifp->if_softc; + u_int tlabel; + int s; + + ald = mtod(m, struct fwasyhdr *); + tlabel = (ntohl( ald->data[0]) >> 10 ) & 0x3f; + + /* if the request offset is the respond of previous action, proceed it */ + if(fc->tlabel[tlabel].expire >= time_second ){ + if(fc->tlabel[tlabel].type == TLABEL_HAND ){ + fc->tlabel[tlabel].resp.hand(ifp, m); + fc->tlabel[tlabel].resp.hand=NULL; + fc->tlabel[tlabel].type = TLABEL_NULL; + fc->tlabel[tlabel].expire = 0; + if(m) + m_freem(m); + return; + }else if(fc->tlabel[tlabel].type == TLABEL_PCB ){ + m->m_pkthdr.rcvif = fc->tlabel[tlabel].resp.pcb; + fc->tlabel[tlabel].expire = 0; + getmicrotime(&ifp->if_lastchange); + fc->tlabel[tlabel].type = 0; + ifp->if_ibytes += m->m_pkthdr.len; + schednetisr(NETISR_1394); + inq = &n1394intrq; + + s = splimp(); + if (IF_QFULL(inq)) { + IF_DROP(inq); + m_freem(m); + } else + IF_ENQUEUE(inq, m); + splx(s); + return; + } + } + bad: + if(m) + m_freem(m); + return; + } + void fw_sid_set(ifp) + struct ifnet *ifp; + { + u_int32_t *sid; + int i, ipch; + int node, n_node = 0, sped; + struct fw_softc *fc = ifp->if_softc; + + sid = fc->sid_buf; + for( i = 0 ; i < fc->sid_cnt ; i++){ + if(!((sid[0] ) & ( 1 << 23 ))){ + n_node ++; + node = (sid[0] >> 24) & 0x3f; + if(fc->max_node < node ){ + fc->max_node = node; + } + sped = (sid[0] >> 14) & 3; + INITREG(fc, SPED_MAP + node + 8) + = sped << ((3 - node%4) * 8); + if( node > fc->irm ){ + if(sid[0] & (1 << 22) ){ + if( sid[0] & (1 << 11)){ + fc->irm = node; + } + } + } + } + INITREG(fc, TOPO_MAP + i * 8 + 12) = sid[0]; + INITREG(fc, TOPO_MAP + i * 8 + 16) = sid[1]; + sid += 2; + } + INITREG(fc, TOPO_MAP + 4) += 1; + INITREG(fc, SPED_MAP + 4) += 1; + INITREG(fc, TOPO_MAP + 8) = (n_node << 16) | fc->sid_cnt; + + + if(fc->irm == -1 ){ + printf("%s%d Not found IRM capable node\n", + IFNAME(fc), IFARG(fc)); + }else{ + printf("%s%d cable IRM = %d\n", + IFNAME(fc), IFARG(fc), fc->irm); + } + if(( fc->irm != -1 ) && ( INITREG(fc, BUS_MGR_ID) == 0x3f) ){ + if( fc->irm == ((INITREG(fc, NODE_IDS) >> 16 ) & 0x3f)){ + fw_set_bmr(ifp, fc->irm); + }else{ + if(fc->fw_flags & BMEPHASE){ + untimeout(fw_try_bmr, (void *)fc, fc->fw_bmrhandle); + } + fc->fw_flags |= BMEPHASE; + timeout(fw_try_bmr,(void *)fc, hz / 2); + } + }else{ + printf("%s%d BMR = %x\n", IFNAME(fc), + IFARG(fc), INITREG(fc, BUS_MGR_ID)); + } + return; + } + void fw_sid_input(ifp, m) + struct ifnet *ifp; + struct mbuf *m; + { + u_int32_t *sid; + int i; + struct fw_softc *fc = ifp->if_softc; + + if(m == NULL) + goto bad; + + m_adj(m, sizeof(fwcntl)); + + if( m->m_pkthdr.len < 8 ){ + if(m) + m_freem(m); + return; + } + #if 0 + printf("%s%d Self-ID %d\n", IFNAME(fc), IFARG(fc), m->m_pkthdr.len); + sid = mtod(m, u_int32_t *); + printf("0x%08x ", ntohl(sid[0])); + printf("0x%08x ", ntohl(sid[1])); + printf("0x%08x ", ntohl(sid[2])); + printf("0x%08x ", ntohl(sid[3])); + printf("0x%08x ", ntohl(sid[4])); + printf("0x%08x ", ntohl(sid[5])); + printf("0x%08x ", ntohl(sid[6])); + printf("0x%08x ", ntohl(sid[7])); + printf("\n"); + #endif + if( m->m_pkthdr.len > 8 * 0x40 ) goto bad; + sid = mtod(m, u_int32_t *); + for( i = 0 ; i < m->m_pkthdr.len ; i+= 8){ + if((ntohl(sid[0]) & 3 << 30) != (1 << 31)) goto bad; + if(sid[0] != ~sid[1]) goto bad; + fc->sid_buf[2 * fc->sid_cnt] = ntohl(sid[0]); + fc->sid_buf[2 * fc->sid_cnt + 1] = ntohl(sid[1]); + fc->sid_cnt ++; + sid += 2; + } + fw_sid_set(ifp); + bad: + if(m) + m_freem(m); + return; + } + int fw_get_tlabel(ifp, type, resp) + struct ifnet *ifp; + u_int type; + void *resp; + { + struct fw_softc *sc = (struct fw_softc *)ifp->if_softc; + u_int i; + for( i = 0 ; i < 0x3f ; i ++){ + if( sc->tlabel[i].expire == 0 ){ + switch( type ){ + case TLABEL_HAND: + sc->tlabel[i].resp.hand = resp; + break; + case TLABEL_PCB: + sc->tlabel[i].resp.pcb = resp; + break; + case TLABEL_WAIT: + sc->tlabel[i].resp.wait =(caddr_t) resp; + break; + default: + return(-1); + } + sc->tlabel[i].type = type; + sc->tlabel[i].expire = time_second + 1; + return(i); + } + } + return(-1); + } + void fw_expire_tlabel( void *fc) + { + int i; + for( i = 0 ; i < 0x3f ; i ++){ + if(((struct fw_softc *)fc)->tlabel[i].expire != 0 ){ + if(((struct fw_softc *)fc)->tlabel[i].expire + < time_second ){ + ((struct fw_softc *)fc)->tlabel[i].expire = 0; + } + } + } + timeout(fw_expire_tlabel, fc, 1 * hz); + } + u_int32_t read_reg(struct fw_softc *sc, u_int32_t addr) + { + if( addr < 0x3000) { + if( addr == CYCLE_TIME ) + return(*sc->p_cycle_timer); + return(INITREG(sc, addr)); + } + return 0; + } + u_int32_t write_reg(struct fw_softc *sc, u_int32_t addr, u_int32_t data) + { + if( addr < 0x3000) { + if( addr == CYCLE_TIME ) + return(*sc->p_cycle_timer); + INITREG(sc, addr) = data; + return(INITREG(sc, addr)); + } + return 0; + } + #define MSB32 (0x1ul << 31) + #define ONE32 0xfffffffful + #define CRC_COMPUTE 0x04c11db7uL + u_int32_t crcfw(struct mbuf *m, u_int len, u_int offset) + { + u_int32_t inQ, crc, newM, *ld; + u_int i, j, oldBit, newBit, sumBit; + struct mbuf *mm; + crc = ONE32; + if( offset > (m->m_pkthdr.len)/4) offset = 0; + if((offset + len) > (m->m_pkthdr.len)/4) + len = m->m_pkthdr.len/4 - offset; + if(len == 0) len = m->m_pkthdr.len/4 - offset; + + for( mm = m, j = 0; mm != NULL ; mm = mm->m_next, j += (mm->m_len) /4 ) + if((j + (mm->m_len)/4) >= offset) + break; + for(i = offset - j, j = offset ; mm != NULL ; mm = mm->m_next){ + ld = mtod(mm, u_int32_t *); + for( ; i < (mm->m_len)/4 ; i ++){ + inQ = ntohl(ld[i]); + for( newM = MSB32 ; newM != 0 ; newM >>= 1){ + newBit = (( inQ & newM) != 0 ); + oldBit = (( crc & MSB32) != 0 ); + sumBit = oldBit ^ newBit; + crc = ((crc << 1) & ONE32 ) ^ + ( sumBit ? CRC_COMPUTE : 0 ); + } + j++; + if( j >= (len + offset) ) return(~crc); + } + i = 0; + } + return(~crc); + } diff -r -c -N sys44.orig/net/if_types.h sys/net/if_types.h *** sys44.orig/net/if_types.h Thu Sep 20 00:09:46 2001 --- sys/net/if_types.h Tue Oct 9 21:55:24 2001 *************** *** 100,105 **** --- 100,106 ---- #define IFT_GIF 0x37 /*0xf0*/ #define IFT_FAITH 0x38 /*0xf2*/ #define IFT_STF 0x39 /*0xf3*/ + #define IFT_IEEE1394 0x40 #define IFT_L2VLAN 0x87 /* Layer 2 Virtual LAN using 802.1Q */ #define IFT_IEEE1394 0x90 /* IEEE1394 High Performance SerialBus*/ diff -r -c -N sys44.orig/net/netisr.h sys/net/netisr.h *** sys44.orig/net/netisr.h Thu Sep 20 00:09:47 2001 --- sys/net/netisr.h Tue Oct 9 21:55:24 2001 *************** *** 62,67 **** --- 62,68 ---- #define NETISR_IPV6 28 /* same as AF_INET6 */ #define NETISR_NATM 29 /* same as AF_NATM */ #define NETISR_NETGRAPH 31 /* same as AF_NETGRAPH */ + #define NETISR_1394 3 #ifndef LOCORE diff -r -c -N sys44.orig/netinet/if_ether.c sys/netinet/if_ether.c *** sys44.orig/netinet/if_ether.c Thu Sep 20 00:09:28 2001 --- sys/netinet/if_ether.c Tue Oct 9 21:55:24 2001 *************** *** 67,72 **** --- 67,74 ---- #include #include #include + #include + #include #include *************** *** 113,119 **** &useloopback, 0, ""); SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, &arp_proxyall, 0, ""); - static void arp_rtrequest __P((int, struct rtentry *, struct sockaddr *)); static void arprequest __P((struct arpcom *, struct in_addr *, struct in_addr *, u_char *)); --- 115,120 ---- *************** *** 126,131 **** --- 127,136 ---- static void in_arpinput __P((struct mbuf *)); #endif + static void firewirearprequest __P((struct arpcom *, + struct in_addr *, struct in_addr *)); + static void in_firewirearpinput __P((struct mbuf *)); + /* * Timeout routine. Age arp_tab entries periodically. */ *************** *** 463,469 **** ar = mtod(m, struct arphdr *); if (ntohs(ar->ar_hrd) != ARPHRD_ETHER ! && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) { log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n", (unsigned char *)&ar->ar_hrd, ""); --- 468,475 ---- ar = mtod(m, struct arphdr *); if (ntohs(ar->ar_hrd) != ARPHRD_ETHER ! && !((ntohs(ar->ar_hrd) == ARPHRD_IEEE802) ! || (ntohs(ar->ar_hrd) == ARPHRD_1394))) { log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n", (unsigned char *)&ar->ar_hrd, ""); *************** *** 481,487 **** switch (ntohs(ar->ar_pro)) { #ifdef INET case ETHERTYPE_IP: ! in_arpinput(m); continue; #endif } --- 487,501 ---- switch (ntohs(ar->ar_pro)) { #ifdef INET case ETHERTYPE_IP: ! switch(ntohs(ar->ar_hrd)){ ! case ARPHRD_1394: ! in_firewirearpinput(m); ! break; ! case ARPHRD_ETHER: ! in_arpinput(m); ! break; ! } ! continue; #endif } *************** *** 815,818 **** --- 829,1105 ---- &IA_SIN(ifa)->sin_addr, ac->ac_enaddr); ifa->ifa_rtrequest = arp_rtrequest; ifa->ifa_flags |= RTF_CLONING; + } + void + firewire_ifinit(ac, ifa) + struct arpcom *ac; + struct ifaddr *ifa; + { + /* + if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) + arprequest(ac, &(IA_SIN(ifa)->sin_addr.s_addr), + &(IA_SIN(ifa)->sin_addr.s_addr), ac->ac_enaddr); + */ + ifa->ifa_rtrequest = arp_rtrequest; + ifa->ifa_flags |= RTF_CLONING; + } + int + firewireresolve(ac, rt, m, dst, desten) + struct arpcom *ac; + register struct rtentry *rt; + struct mbuf *m; + register struct sockaddr *dst; + register u_char *desten; /* OUT */ + { + register struct llinfo_arp *la; + struct sockaddr_dl *sdl; + struct ip1394arp *fwdst = (struct ip1394arp *)desten; + + if (m->m_flags & (M_BCAST|M_MCAST)) { + fwdst->node = htons(0x3f); + fwdst->fifo_h = htons(ac->media.firewire.broadcast); + fwdst->spd = S100; + return(1); + } + + if (rt) + la = (struct llinfo_arp *)rt->rt_llinfo; + else { + la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); + if (la) + rt = la->la_rt; + } + if (la == 0 || rt == 0) { + log(LOG_DEBUG, "fireqirearpresolve: can't allocate llinfo for %s%s%s\n", + inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", + rt ? "rt" : ""); + m_freem(m); + return (0); + } + sdl = SDL(rt->rt_gateway); + /* + * Check the address family and length is valid, the address + * is resolved; otherwise, try to resolve. + */ + if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && + sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { + bcopy(LLADDR(sdl), desten, sdl->sdl_alen); + return 1; + } + /* + * There is an arptab entry, but no ethernet address + * response yet. Replace the held mbuf with this + * latest one. + */ + if (la->la_hold) + m_freem(la->la_hold); + la->la_hold = m; + if (rt->rt_expire) { + rt->rt_flags &= ~RTF_REJECT; + if (la->la_asked == 0 || rt->rt_expire != time_second) { + rt->rt_expire = time_second; + if (la->la_asked++ < arp_maxtries){ + firewirearprequest(ac, + &(SIN(rt->rt_ifa->ifa_addr)->sin_addr), + &(SIN(dst)->sin_addr)); + } else { + rt->rt_flags |= RTF_REJECT; + rt->rt_expire += arpt_down; + la->la_asked = 0; + } + + } + } + return (0); + } + static void + firewirearprequest(ac, sip, tip) + register struct arpcom *ac; + register struct in_addr *sip, *tip; + { + register struct mbuf *m; + register struct firewire_arp *fa; + struct fwisohdr *ild; + u_int32_t *fh; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return; + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return; + } + /* + if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) + return; + */ + m->m_pkthdr.len = m->m_len = sizeof(struct fwisohdr) + + sizeof(*fh) + sizeof(*fa); + ild = mtod(m, struct fwisohdr *); + + fh = &(ild->data[1]); + fa = (struct firewire_arp *)&(ild->data[2]); + bzero((caddr_t)fa, sizeof (*fa) + sizeof(struct isohdr)); + ild->cntl[0] = PROTO_N1394ASYST; + ild->data[0] = htonl( (sizeof(*fa) + sizeof(struct isohdr)) << 16 | + ac->media.firewire.broadcast << 8 | (TCODE_STREAM <<4)); + + *fh = htonl(ETHERTYPE_ARP); + + fa->arp_hrd = htons(ARPHRD_1394); + fa->arp_pro = htons(ETHERTYPE_IP); + fa->arp_hln = sizeof(fa->arp_sha); + fa->arp_pln = sizeof(fa->arp_spa); + fa->arp_op = htons(ARPOP_REQUEST); + (void)memcpy(&fa->arp_sha, ac->media.firewire.eui64, sizeof(fa->arp_sha)); + fa->arp_snid = htons(ac->media.firewire.arpdata.node); + fa->arp_sfifo_h = htons(ac->media.firewire.arpdata.fifo_h); + fa->arp_sfifo_l = htonl(ac->media.firewire.arpdata.fifo_l); + fa->arp_smaxrec = ac->media.firewire.arpdata.maxrec; + fa->arp_sspd = ac->media.firewire.arpdata.spd; + (void)memcpy(fa->arp_spa, sip, sizeof(fa->arp_spa)); + (void)memcpy(fa->arp_tpa, tip, sizeof(fa->arp_tpa)); + (*ac->ac_if.if_output)(&ac->ac_if, m, 0, (struct rtentry *)0); + } + + static void + in_firewirearpinput(m) + struct mbuf *m; + { + struct firewire_arp *fa, fa0; + register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; + register struct llinfo_arp *la = 0; + register struct rtentry *rt; + struct ifnet *ifp = m->m_pkthdr.rcvif; + struct in_ifaddr *ia, *maybe_ia = 0; + struct sockaddr_dl *sdl; + struct in_addr isaddr, itaddr, myaddr; + struct mbuf *m1; + struct fwisohdr *ild; + struct fwasyhdr *ald; + int op; + struct ip1394arp firewireaddr; + u_int32_t *fh; + + fa = mtod(m, struct firewire_arp *); + op = ntohs(fa->arp_op); + (void)memcpy(&isaddr, fa->arp_spa, sizeof (isaddr)); + (void)memcpy(&itaddr, fa->arp_tpa, sizeof (itaddr)); + + for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) + if (ia->ia_ifp == &ac->ac_if) { + maybe_ia = ia; + if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || + (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) + break; + } + if (maybe_ia == 0) { + m_freem(m); + return; + } + myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; + + firewireaddr.maxrec = fa->arp_smaxrec; + firewireaddr.spd = fa->arp_sspd; + + firewireaddr.node = fa->arp_snid; + + firewireaddr.fifo_h = fa->arp_sfifo_h; + firewireaddr.fifo_l = fa->arp_sfifo_l; + #if 0 + if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)specify EUI64 field, + sizeof (ea->arp_sha))) { + m_freem(m); /* it's from me, ignore it. */ + return; + } + #endif + if (isaddr.s_addr == myaddr.s_addr) { + log(LOG_ERR, + "firewirearp: %6D is using my IP address %s!\n", + fa->arp_snid, ":", inet_ntoa(isaddr)); + itaddr = myaddr; + goto reply; + } + la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); + if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { + if (sdl->sdl_alen && + bcmp((caddr_t)&firewireaddr, LLADDR(sdl), sdl->sdl_alen)) + log(LOG_INFO, "arp: %s moved from %6D to %6D\n", + inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":", + &firewireaddr, ":"); + (void)memcpy(LLADDR(sdl), &firewireaddr, sizeof(firewireaddr)); + sdl->sdl_alen = sizeof(firewireaddr); + sdl->sdl_index = ifp->if_index; + if (rt->rt_expire) + rt->rt_expire = time_second + arpt_keep; + rt->rt_flags &= ~RTF_REJECT; + la->la_asked = 0; + if (la->la_hold) { + (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold, + rt_key(rt), rt); + la->la_hold = 0; + } + } + reply: + if (op != ARPOP_REQUEST) { + m_freem(m); + return; + } + if (itaddr.s_addr != myaddr.s_addr) { + m_freem(m); + return; + } + /* I am the target */ + + (void)memcpy( &fa0, fa, sizeof(*fa)); + m_freem(m); + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return; + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + return; + } + + m->m_pkthdr.len = m->m_len = + sizeof(struct fwasyhdr) + sizeof(*fh) + sizeof(*fa); + + ald = mtod(m, struct fwasyhdr *); + ald->cntl[0] = PROTO_N1394ASYRQ; + + fa = (struct firewire_arp *)&(ald->data[5]); + (void)memcpy( fa, &fa0, sizeof(*fa)); + + fa->arp_tnid = fa->arp_snid; + fa->arp_snid = htons(ac->media.firewire.arpdata.node); + + fa->arp_tfifo_h = fa->arp_sfifo_h; + fa->arp_sfifo_h = htons(ac->media.firewire.arpdata.fifo_h); + + fa->arp_tfifo_l = fa->arp_sfifo_l; + fa->arp_sfifo_l = htonl(ac->media.firewire.arpdata.fifo_l); + + fa->arp_tmaxrec = fa->arp_smaxrec; + fa->arp_smaxrec = htons(MAXREC_512); + + fa->arp_tspd = fa->arp_sspd; + fa->arp_sspd = htons(S100); + + (void)memcpy(fa->arp_tpa, fa->arp_spa, sizeof(fa->arp_spa)); + (void)memcpy(fa->arp_spa, &itaddr, sizeof(fa->arp_spa)); + + fa->arp_op = htons(ARPOP_REPLY); + fa->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */ + + ald->data[0] = htonl((TCODE_BLKWRREQ << 4) | (ntohs(fa->arp_tnid) << 16)); + ald->data[1] = htonl(ntohs(fa->arp_snid) << 16 | ntohs(fa->arp_tfifo_h)); + ald->data[2] = fa->arp_tfifo_l; + ald->data[3] = htonl((m->m_pkthdr.len - sizeof(struct fwasyhdr)) << 16); + + ald->data[4] = htonl(ETHERTYPE_ARP); + (*ac->ac_if.if_output)(&ac->ac_if, m, 0, (struct rtentry *)0); + return; } diff -r -c -N sys44.orig/netinet/if_firewire.h sys/netinet/if_firewire.h *** sys44.orig/netinet/if_firewire.h Thu Jan 1 09:00:00 1970 --- sys/netinet/if_firewire.h Tue Oct 9 21:55:26 2001 *************** *** 0 **** --- 1,85 ---- + /* + * Copyright (c) 1998,1999,2000 Katsushi Kobayashi. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the acknowledgement as bellow: + * + * This product includes software developed by K. Kobayashi + * + * And the paper of the driver code can be found at: + * + * Katsushi Kobayashi, + * "Design and Implementation of Firewire Device Driver on FreeBSD", + * Proc. of the FREENIX track: 1999 USENIX Annual Technical Coference, + * pp 41-51,(1999) + * + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: if_firewire.h,v 1.1.2.1 2000/06/04 17:19:19 ikob Exp $ + * + */ + + #ifndef _NETINET_IF_FIREWIRE_H_ + #define _NETINET_IF_FIREWIRE_H_ + + #include + + #define MAXREC_4 0x1 + #define MAXREC_8 0x2 + #define MAXREC_16 0x3 + #define MAXREC_32 0x4 + #define MAXREC_64 0x5 + #define MAXREC_128 0x6 + #define MAXREC_256 0x7 + #define MAXREC_512 0x8 + #define MAXREC_1024 0x9 + #define MAXREC_2048 0x10 + + struct firewire_arp { + struct arphdr ea_hdr; /* fixed-size header */ + u_int64_t arp_sha; + u_int16_t arp_snid; + u_int16_t arp_sfifo_h; + u_int32_t arp_sfifo_l; + u_int8_t arp_smaxrec; + u_int8_t arp_sspd; + u_int16_t arp_srsvd; + u_int8_t arp_spa[4]; + u_int64_t arp_tha; + u_int16_t arp_tnid; + u_int16_t arp_tfifo_h; + u_int32_t arp_tfifo_l; + u_int8_t arp_tmaxrec; + u_int8_t arp_tspd; + u_int16_t arp_trsvd; + u_int8_t arp_tpa[4]; + }; + #ifdef _KERNEL + int firewireresolve __P((struct arpcom *, struct rtentry *, struct mbuf *, + struct sockaddr *, u_char *)); + void firewire_ifinit __P((struct arpcom *, struct ifaddr *)); + #endif + + #endif diff -r -c -N sys44.orig/nwfs/nwfs_vfsops.c sys/nwfs/nwfs_vfsops.c *** sys44.orig/nwfs/nwfs_vfsops.c Thu Sep 20 00:09:37 2001 --- sys/nwfs/nwfs_vfsops.c Tue Oct 9 22:31:32 2001 *************** *** 429,435 **** struct ncp_volume_info vi; if (np == NULL) return EINVAL; ! error = ncp_get_volume_info_with_number(NWFSTOCONN(nmp), nmp->n_volume, &vi,p,p->p_ucred); if (error) return error; secsize = 512; /* XXX how to get real value ??? */ sbp->f_spare2=0; /* placeholder */ --- 429,435 ---- struct ncp_volume_info vi; if (np == NULL) return EINVAL; ! error = ncpget_volume_info_with_number(NWFSTOCONN(nmp), nmp->n_volume, &vi,p,p->p_ucred); if (error) return error; secsize = 512; /* XXX how to get real value ??? */ sbp->f_spare2=0; /* placeholder */ diff -r -c -N sys44.orig/pci/pcireg.h sys/pci/pcireg.h *** sys44.orig/pci/pcireg.h Thu Sep 20 00:09:35 2001 --- sys/pci/pcireg.h Tue Oct 9 21:55:35 2001 *************** *** 56,61 **** --- 56,62 ---- #define PCIM_CMD_PORTEN 0x0001 #define PCIM_CMD_MEMEN 0x0002 #define PCIM_CMD_BUSMASTEREN 0x0004 + #define PCIM_CMD_MWIEN 0x0010 #define PCIM_CMD_MWRICEN 0x0010 #define PCIM_CMD_PERRESPEN 0x0040 #define PCIR_STATUS 0x06 diff -r -c -N sys44.orig/sys/socket.h sys/sys/socket.h *** sys44.orig/sys/socket.h Thu Sep 20 00:09:44 2001 --- sys/sys/socket.h Tue Oct 9 21:55:35 2001 *************** *** 152,157 **** --- 152,158 ---- * in interface output routine */ #define AF_NETGRAPH 32 /* Netgraph sockets */ + #define AF_N1394 3 #define AF_MAX 33 diff -r -c -N sys44.orig/vm/vm_page.c sys/vm/vm_page.c *** sys44.orig/vm/vm_page.c Thu Sep 20 00:09:22 2001 --- sys/vm/vm_page.c Tue Oct 9 21:55:35 2001 *************** *** 1175,1181 **** * will clear the flag. * * This routine is used by OBJT_PHYS objects - objects using unswappable ! * physical memory as backing store rather then swap-backed memory and * will eventually be extended to support 4MB unmanaged physical * mappings. */ --- 1175,1181 ---- * will clear the flag. * * This routine is used by OBJT_PHYS objects - objects using unswappable ! * physical memory as backing store`rather then swap-backed memory and * will eventually be extended to support 4MB unmanaged physical * mappings. */