[BACK]Return to if_tl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Annotation of src/sys/dev/pci/if_tl.c, Revision 1.64.2.1

1.64.2.1! tron        1: /*     $NetBSD$        */
1.1       bouyer      2:
                      3: /*
                      4:  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
                     16:  *  This product includes software developed by Manuel Bouyer.
                     17:  * 4. The name of the author may not be used to endorse or promote products
                     18:  *    derived from this software without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     23:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     25:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     29:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
1.2       bouyer     33:  * Texas Instruments ThunderLAN ethernet controller
1.1       bouyer     34:  * ThunderLAN Programmer's Guide (TI Literature Number SPWU013A)
                     35:  * available from www.ti.com
                     36:  */
1.47      lukem      37:
                     38: #include <sys/cdefs.h>
1.64.2.1! tron       39: __KERNEL_RCSID(0, "$NetBSD$");
1.1       bouyer     40:
                     41: #undef TLDEBUG
                     42: #define TL_PRIV_STATS
                     43: #undef TLDEBUG_RX
                     44: #undef TLDEBUG_TX
                     45: #undef TLDEBUG_ADDR
1.12      jonathan   46:
                     47: #include "opt_inet.h"
1.13      jonathan   48: #include "opt_ns.h"
1.1       bouyer     49:
                     50: #include <sys/param.h>
                     51: #include <sys/systm.h>
                     52: #include <sys/mbuf.h>
                     53: #include <sys/protosw.h>
                     54: #include <sys/socket.h>
                     55: #include <sys/ioctl.h>
                     56: #include <sys/errno.h>
                     57: #include <sys/malloc.h>
                     58: #include <sys/kernel.h>
                     59: #include <sys/proc.h>  /* only for declaration of wakeup() used by vm.h */
                     60: #include <sys/device.h>
                     61:
                     62: #include <net/if.h>
                     63: #if defined(SIOCSIFMEDIA)
                     64: #include <net/if_media.h>
                     65: #endif
                     66: #include <net/if_types.h>
                     67: #include <net/if_dl.h>
                     68: #include <net/route.h>
                     69: #include <net/netisr.h>
                     70:
                     71: #include "bpfilter.h"
                     72: #if NBPFILTER > 0
                     73: #include <net/bpf.h>
                     74: #include <net/bpfdesc.h>
                     75: #endif
                     76:
                     77: #ifdef INET
                     78: #include <netinet/in.h>
                     79: #include <netinet/in_systm.h>
                     80: #include <netinet/in_var.h>
                     81: #include <netinet/ip.h>
                     82: #endif
                     83:
                     84: #ifdef NS
                     85: #include <netns/ns.h>
                     86: #include <netns/ns_if.h>
                     87: #endif
                     88:
                     89: #if defined(__NetBSD__)
                     90: #include <net/if_ether.h>
1.34      mrg        91: #include <uvm/uvm_extern.h>
1.1       bouyer     92: #if defined(INET)
                     93: #include <netinet/if_inarp.h>
                     94: #endif
1.4       thorpej    95:
1.1       bouyer     96: #include <machine/bus.h>
                     97: #include <machine/intr.h>
1.4       thorpej    98:
1.1       bouyer     99: #include <dev/pci/pcireg.h>
                    100: #include <dev/pci/pcivar.h>
                    101: #include <dev/pci/pcidevs.h>
1.15      thorpej   102:
1.58      thorpej   103: #include <dev/i2c/i2cvar.h>
                    104: #include <dev/i2c/i2c_bitbang.h>
                    105: #include <dev/i2c/at24cxxvar.h>
1.15      thorpej   106:
                    107: #include <dev/mii/mii.h>
                    108: #include <dev/mii/miivar.h>
                    109:
                    110: #include <dev/mii/tlphyvar.h>
                    111:
1.1       bouyer    112: #include <dev/pci/if_tlregs.h>
1.15      thorpej   113: #include <dev/pci/if_tlvar.h>
1.1       bouyer    114: #endif /* __NetBSD__ */
                    115:
                    116: /* number of transmit/receive buffers */
1.59      tsutsui   117: #ifndef TL_NBUF
1.62      tsutsui   118: #define TL_NBUF 32
1.1       bouyer    119: #endif
                    120:
1.7       drochner  121: static int tl_pci_match __P((struct device *, struct cfdata *, void *));
1.1       bouyer    122: static void tl_pci_attach __P((struct device *, struct device *, void *));
                    123: static int tl_intr __P((void *));
                    124:
                    125: static int tl_ifioctl __P((struct ifnet *, ioctl_cmd_t, caddr_t));
                    126: static int tl_mediachange __P((struct ifnet *));
                    127: static void tl_mediastatus __P((struct ifnet *, struct ifmediareq *));
                    128: static void tl_ifwatchdog __P((struct ifnet *));
                    129: static void tl_shutdown __P((void*));
                    130:
                    131: static void tl_ifstart __P((struct ifnet *));
                    132: static void tl_reset __P((tl_softc_t*));
1.46      bouyer    133: static int  tl_init __P((struct ifnet *));
                    134: static void tl_stop __P((struct ifnet *, int));
1.1       bouyer    135: static void tl_restart __P((void  *));
1.43      bouyer    136: static int  tl_add_RxBuff __P((tl_softc_t*, struct Rx_list*, struct mbuf*));
1.1       bouyer    137: static void tl_read_stats __P((tl_softc_t*));
                    138: static void tl_ticks __P((void*));
                    139: static int tl_multicast_hash __P((u_int8_t*));
                    140: static void tl_addr_filter __P((tl_softc_t*));
                    141:
                    142: static u_int32_t tl_intreg_read __P((tl_softc_t*, u_int32_t));
                    143: static void tl_intreg_write __P((tl_softc_t*, u_int32_t, u_int32_t));
                    144: static u_int8_t tl_intreg_read_byte __P((tl_softc_t*, u_int32_t));
                    145: static void tl_intreg_write_byte __P((tl_softc_t*, u_int32_t, u_int8_t));
                    146:
1.28      tron      147: void   tl_mii_sync __P((struct tl_softc *));
                    148: void   tl_mii_sendbits __P((struct tl_softc *, u_int32_t, int));
                    149:
                    150:
1.59      tsutsui   151: #if defined(TLDEBUG_RX)
1.1       bouyer    152: static void ether_printheader __P((struct ether_header*));
                    153: #endif
                    154:
1.15      thorpej   155: int tl_mii_read __P((struct device *, int, int));
                    156: void tl_mii_write __P((struct device *, int, int, int));
                    157:
                    158: void tl_statchg __P((struct device *));
1.1       bouyer    159:
1.58      thorpej   160:        /* I2C glue */
                    161: static int tl_i2c_acquire_bus(void *, int);
                    162: static void tl_i2c_release_bus(void *, int);
                    163: static int tl_i2c_send_start(void *, int);
                    164: static int tl_i2c_send_stop(void *, int);
                    165: static int tl_i2c_initiate_xfer(void *, i2c_addr_t, int);
                    166: static int tl_i2c_read_byte(void *, uint8_t *, int);
                    167: static int tl_i2c_write_byte(void *, uint8_t, int);
                    168:
                    169:        /* I2C bit-bang glue */
                    170: static void tl_i2cbb_set_bits(void *, uint32_t);
                    171: static void tl_i2cbb_set_dir(void *, uint32_t);
                    172: static uint32_t tl_i2cbb_read(void *);
                    173: static const struct i2c_bitbang_ops tl_i2cbb_ops = {
                    174:        tl_i2cbb_set_bits,
                    175:        tl_i2cbb_set_dir,
                    176:        tl_i2cbb_read,
                    177:        {
                    178:                TL_NETSIO_EDATA,        /* SDA */
                    179:                TL_NETSIO_ECLOCK,       /* SCL */
                    180:                TL_NETSIO_ETXEN,        /* SDA is output */
                    181:                0,                      /* SDA is input */
                    182:        }
                    183: };
1.1       bouyer    184:
                    185: static __inline void netsio_clr __P((tl_softc_t*, u_int8_t));
                    186: static __inline void netsio_set __P((tl_softc_t*, u_int8_t));
                    187: static __inline u_int8_t netsio_read __P((tl_softc_t*, u_int8_t));
                    188: static __inline void netsio_clr(sc, bits)
                    189:        tl_softc_t* sc;
                    190:        u_int8_t bits;
                    191: {
                    192:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetSio,
1.17      bouyer    193:            tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetSio) & (~bits));
1.1       bouyer    194: }
                    195: static __inline void netsio_set(sc, bits)
                    196:        tl_softc_t* sc;
                    197:        u_int8_t bits;
                    198: {
                    199:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetSio,
1.17      bouyer    200:            tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetSio) | bits);
1.1       bouyer    201: }
                    202: static __inline u_int8_t netsio_read(sc, bits)
                    203:        tl_softc_t* sc;
                    204:        u_int8_t bits;
                    205: {
1.4       thorpej   206:        return (tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetSio) & bits);
1.1       bouyer    207: }
                    208:
1.55      thorpej   209: CFATTACH_DECL(tl, sizeof(tl_softc_t),
1.56      thorpej   210:     tl_pci_match, tl_pci_attach, NULL, NULL);
1.1       bouyer    211:
1.4       thorpej   212: const struct tl_product_desc tl_compaq_products[] = {
1.15      thorpej   213:        { PCI_PRODUCT_COMPAQ_N100TX, TLPHY_MEDIA_NO_10_T,
1.22      tron      214:          "Compaq Netelligent 10/100 TX" },
1.64.2.1! tron      215:        { PCI_PRODUCT_COMPAQ_INT100TX, TLPHY_MEDIA_NO_10_T,
        !           216:          "Integrated Compaq Netelligent 10/100 TX" },
1.15      thorpej   217:        { PCI_PRODUCT_COMPAQ_N10T, TLPHY_MEDIA_10_5,
1.22      tron      218:          "Compaq Netelligent 10 T" },
1.15      thorpej   219:        { PCI_PRODUCT_COMPAQ_IntNF3P, TLPHY_MEDIA_10_2,
1.22      tron      220:          "Compaq Integrated NetFlex 3/P" },
1.15      thorpej   221:        { PCI_PRODUCT_COMPAQ_IntPL100TX, TLPHY_MEDIA_10_2|TLPHY_MEDIA_NO_10_T,
1.22      tron      222:          "Compaq ProLiant Integrated Netelligent 10/100 TX" },
1.15      thorpej   223:        { PCI_PRODUCT_COMPAQ_DPNet100TX, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T,
1.22      tron      224:          "Compaq Dual Port Netelligent 10/100 TX" },
1.40      bouyer    225:        { PCI_PRODUCT_COMPAQ_DP4000, TLPHY_MEDIA_10_5|TLPHY_MEDIA_NO_10_T,
1.22      tron      226:          "Compaq Deskpro 4000 5233MMX" },
1.15      thorpej   227:        { PCI_PRODUCT_COMPAQ_NF3P_BNC, TLPHY_MEDIA_10_2,
1.22      tron      228:          "Compaq NetFlex 3/P w/ BNC" },
1.15      thorpej   229:        { PCI_PRODUCT_COMPAQ_NF3P, TLPHY_MEDIA_10_5,
1.22      tron      230:          "Compaq NetFlex 3/P" },
1.4       thorpej   231:        { 0, 0, NULL },
                    232: };
                    233:
                    234: const struct tl_product_desc tl_ti_products[] = {
1.10      thorpej   235:        /*
                    236:         * Built-in Ethernet on the TI TravelMate 5000
                    237:         * docking station; better product description?
                    238:         */
1.15      thorpej   239:        { PCI_PRODUCT_TI_TLAN, 0,
1.22      tron      240:          "Texas Instruments ThunderLAN" },
1.4       thorpej   241:        { 0, 0, NULL },
                    242: };
                    243:
                    244: struct tl_vendor_desc {
                    245:        u_int32_t tv_vendor;
                    246:        const struct tl_product_desc *tv_products;
                    247: };
                    248:
                    249: const struct tl_vendor_desc tl_vendors[] = {
                    250:        { PCI_VENDOR_COMPAQ, tl_compaq_products },
                    251:        { PCI_VENDOR_TI, tl_ti_products },
                    252:        { 0, NULL },
                    253: };
                    254:
                    255: const struct tl_product_desc *tl_lookup_product __P((u_int32_t));
                    256:
                    257: const struct tl_product_desc *
                    258: tl_lookup_product(id)
                    259:        u_int32_t id;
                    260: {
                    261:        const struct tl_product_desc *tp;
                    262:        const struct tl_vendor_desc *tv;
                    263:
                    264:        for (tv = tl_vendors; tv->tv_products != NULL; tv++)
                    265:                if (PCI_VENDOR(id) == tv->tv_vendor)
                    266:                        break;
                    267:
                    268:        if ((tp = tv->tv_products) == NULL)
                    269:                return (NULL);
                    270:
                    271:        for (; tp->tp_desc != NULL; tp++)
                    272:                if (PCI_PRODUCT(id) == tp->tp_product)
                    273:                        break;
                    274:
                    275:        if (tp->tp_desc == NULL)
                    276:                return (NULL);
                    277:
                    278:        return (tp);
                    279: }
                    280:
1.1       bouyer    281: static int
1.4       thorpej   282: tl_pci_match(parent, match, aux)
1.1       bouyer    283:        struct device *parent;
1.7       drochner  284:        struct cfdata *match;
1.1       bouyer    285:        void *aux;
                    286: {
                    287:        struct pci_attach_args *pa = (struct pci_attach_args *) aux;
                    288:
1.4       thorpej   289:        if (tl_lookup_product(pa->pa_id) != NULL)
                    290:                return (1);
                    291:
                    292:        return (0);
1.1       bouyer    293: }
                    294:
                    295: static void
                    296: tl_pci_attach(parent, self, aux)
                    297:        struct device * parent;
                    298:        struct device * self;
                    299:        void * aux;
                    300: {
                    301:        tl_softc_t *sc = (tl_softc_t *)self;
                    302:        struct pci_attach_args * const pa = (struct pci_attach_args *) aux;
1.4       thorpej   303:        const struct tl_product_desc *tp;
1.1       bouyer    304:        struct ifnet * const ifp = &sc->tl_if;
                    305:        bus_space_tag_t iot, memt;
                    306:        bus_space_handle_t ioh, memh;
                    307:        pci_intr_handle_t intrhandle;
1.4       thorpej   308:        const char *intrstr;
1.58      thorpej   309:        int ioh_valid, memh_valid;
1.23      bouyer    310:        int reg_io, reg_mem;
                    311:        pcireg_t reg10, reg14;
1.4       thorpej   312:        pcireg_t csr;
                    313:
                    314:        printf("\n");
                    315:
1.32      thorpej   316:        callout_init(&sc->tl_tick_ch);
                    317:        callout_init(&sc->tl_restart_ch);
                    318:
1.10      thorpej   319:        tp = tl_lookup_product(pa->pa_id);
                    320:        if (tp == NULL)
                    321:                panic("tl_pci_attach: impossible");
1.15      thorpej   322:        sc->tl_product = tp;
1.10      thorpej   323:
1.23      bouyer    324:        /*
1.52      wiz       325:         * Map the card space. First we have to find the I/O and MEM
1.59      tsutsui   326:         * registers. I/O is supposed to be at 0x10, MEM at 0x14,
1.23      bouyer    327:         * but some boards (Compaq Netflex 3/P PCI) seem to have it reversed.
                    328:         * The ThunderLAN manual is not consistent about this either (there
                    329:         * are both cases in code examples).
                    330:         */
                    331:        reg10 = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x10);
                    332:        reg14 = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x14);
                    333:        if (PCI_MAPREG_TYPE(reg10) == PCI_MAPREG_TYPE_IO)
                    334:                reg_io = 0x10;
                    335:        else if (PCI_MAPREG_TYPE(reg14) == PCI_MAPREG_TYPE_IO)
                    336:                reg_io = 0x14;
                    337:        else
                    338:                reg_io = 0;
                    339:        if (PCI_MAPREG_TYPE(reg10) == PCI_MAPREG_TYPE_MEM)
                    340:                reg_mem = 0x10;
                    341:        else if (PCI_MAPREG_TYPE(reg14) == PCI_MAPREG_TYPE_MEM)
                    342:                reg_mem = 0x14;
                    343:        else
                    344:                reg_mem = 0;
                    345:
                    346:        if (reg_io != 0)
                    347:                ioh_valid = (pci_mapreg_map(pa, reg_io, PCI_MAPREG_TYPE_IO,
                    348:                    0, &iot, &ioh, NULL, NULL) == 0);
                    349:        else
                    350:                ioh_valid = 0;
                    351:        if (reg_mem != 0)
                    352:                memh_valid = (pci_mapreg_map(pa, PCI_CBMA,
                    353:                    PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
                    354:                    0, &memt, &memh, NULL, NULL) == 0);
                    355:        else
                    356:                memh_valid = 0;
1.4       thorpej   357:
1.22      tron      358:        if (ioh_valid) {
                    359:                sc->tl_bustag = iot;
                    360:                sc->tl_bushandle = ioh;
                    361:        } else if (memh_valid) {
1.4       thorpej   362:                sc->tl_bustag = memt;
                    363:                sc->tl_bushandle = memh;
1.1       bouyer    364:        } else {
1.4       thorpej   365:                printf("%s: unable to map device registers\n",
                    366:                    sc->sc_dev.dv_xname);
                    367:                return;
1.1       bouyer    368:        }
1.43      bouyer    369:        sc->tl_dmatag = pa->pa_dmat;
1.1       bouyer    370:
1.4       thorpej   371:        /* Enable the device. */
                    372:        csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
                    373:        pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
                    374:            csr | PCI_COMMAND_MASTER_ENABLE);
1.1       bouyer    375:
1.4       thorpej   376:        printf("%s: %s\n", sc->sc_dev.dv_xname, tp->tp_desc);
1.1       bouyer    377:
                    378:        tl_reset(sc);
                    379:
1.58      thorpej   380:        /* fill in the i2c tag */
                    381:        sc->sc_i2c.ic_cookie = sc;
                    382:        sc->sc_i2c.ic_acquire_bus = tl_i2c_acquire_bus;
                    383:        sc->sc_i2c.ic_release_bus = tl_i2c_release_bus;
                    384:        sc->sc_i2c.ic_send_start = tl_i2c_send_start;
                    385:        sc->sc_i2c.ic_send_stop = tl_i2c_send_stop;
                    386:        sc->sc_i2c.ic_initiate_xfer = tl_i2c_initiate_xfer;
                    387:        sc->sc_i2c.ic_read_byte = tl_i2c_read_byte;
                    388:        sc->sc_i2c.ic_write_byte = tl_i2c_write_byte;
1.1       bouyer    389:
                    390: #ifdef TLDEBUG
                    391:        printf("default values of INTreg: 0x%x\n",
1.17      bouyer    392:            tl_intreg_read(sc, TL_INT_Defaults));
1.1       bouyer    393: #endif
                    394:
                    395:        /* read mac addr */
1.58      thorpej   396:        if (seeprom_bootstrap_read(&sc->sc_i2c, 0x50, 0x83, 512/*?*/,
                    397:                                   sc->tl_enaddr, ETHER_ADDR_LEN)) {
1.64      wiz       398:                printf("%s: error reading Ethernet address\n",
1.58      thorpej   399:                    sc->sc_dev.dv_xname);
1.1       bouyer    400:                        return;
                    401:        }
1.4       thorpej   402:        printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
1.17      bouyer    403:            ether_sprintf(sc->tl_enaddr));
1.1       bouyer    404:
1.4       thorpej   405:        /* Map and establish interrupts */
1.39      sommerfe  406:        if (pci_intr_map(pa, &intrhandle)) {
1.4       thorpej   407:                printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
                    408:                return;
                    409:        }
                    410:        intrstr = pci_intr_string(pa->pa_pc, intrhandle);
1.49      christos  411:        sc->tl_if.if_softc = sc;
1.4       thorpej   412:        sc->tl_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_NET,
1.17      bouyer    413:            tl_intr, sc);
1.4       thorpej   414:        if (sc->tl_ih == NULL) {
                    415:                printf("%s: couldn't establish interrupt",
                    416:                    sc->sc_dev.dv_xname);
                    417:                if (intrstr != NULL)
                    418:                        printf(" at %s", intrstr);
                    419:                printf("\n");
                    420:                return;
                    421:        }
                    422:        printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
                    423:
1.43      bouyer    424:        /* init these pointers, so that tl_shutdown won't try to read them */
                    425:        sc->Rx_list = NULL;
                    426:        sc->Tx_list = NULL;
                    427:
1.46      bouyer    428:        /* allocate DMA-safe memory for control structs */
                    429:        if (bus_dmamem_alloc(sc->tl_dmatag,
                    430:                PAGE_SIZE, 0, PAGE_SIZE,
                    431:                &sc->ctrl_segs, 1, &sc->ctrl_nsegs, BUS_DMA_NOWAIT) != 0 ||
                    432:            bus_dmamem_map(sc->tl_dmatag, &sc->ctrl_segs,
                    433:                sc->ctrl_nsegs, PAGE_SIZE, (caddr_t*)&sc->ctrl,
                    434:                BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0) {
                    435:                        printf("%s: can't allocate DMA memory for lists\n",
                    436:                            sc->sc_dev.dv_xname);
                    437:                        return;
                    438:        }
1.4       thorpej   439:        /*
                    440:         * Add shutdown hook so that DMA is disabled prior to reboot. Not
1.59      tsutsui   441:         * doing
1.4       thorpej   442:         * reboot before the driver initializes.
                    443:         */
1.46      bouyer    444:        (void) shutdownhook_establish(tl_shutdown, ifp);
1.4       thorpej   445:
1.15      thorpej   446:        /*
                    447:         * Initialize our media structures and probe the MII.
                    448:         *
                    449:         * Note that we don't care about the media instance.  We
                    450:         * are expecting to have multiple PHYs on the 10/100 cards,
                    451:         * and on those cards we exclude the internal PHY from providing
                    452:         * 10baseT.  By ignoring the instance, it allows us to not have
                    453:         * to specify it on the command line when switching media.
                    454:         */
                    455:        sc->tl_mii.mii_ifp = ifp;
                    456:        sc->tl_mii.mii_readreg = tl_mii_read;
                    457:        sc->tl_mii.mii_writereg = tl_mii_write;
                    458:        sc->tl_mii.mii_statchg = tl_statchg;
                    459:        ifmedia_init(&sc->tl_mii.mii_media, IFM_IMASK, tl_mediachange,
                    460:            tl_mediastatus);
1.29      thorpej   461:        mii_attach(self, &sc->tl_mii, 0xffffffff, MII_PHY_ANY,
1.30      thorpej   462:            MII_OFFSET_ANY, 0);
1.59      tsutsui   463:        if (LIST_FIRST(&sc->tl_mii.mii_phys) == NULL) {
1.15      thorpej   464:                ifmedia_add(&sc->tl_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
                    465:                ifmedia_set(&sc->tl_mii.mii_media, IFM_ETHER|IFM_NONE);
                    466:        } else
                    467:                ifmedia_set(&sc->tl_mii.mii_media, IFM_ETHER|IFM_AUTO);
1.57      bouyer    468:
1.59      tsutsui   469:        /*
1.57      bouyer    470:         * We can support 802.1Q VLAN-sized frames.
                    471:         */
                    472:        sc->tl_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
1.1       bouyer    473:
1.41      thorpej   474:        strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
1.1       bouyer    475:        ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
                    476:        ifp->if_ioctl = tl_ifioctl;
                    477:        ifp->if_start = tl_ifstart;
                    478:        ifp->if_watchdog = tl_ifwatchdog;
1.46      bouyer    479:        ifp->if_init = tl_init;
                    480:        ifp->if_stop = tl_stop;
1.1       bouyer    481:        ifp->if_timer = 0;
1.50      itojun    482:        IFQ_SET_READY(&ifp->if_snd);
1.1       bouyer    483:        if_attach(ifp);
                    484:        ether_ifattach(&(sc)->tl_if, (sc)->tl_enaddr);
                    485: }
                    486:
                    487: static void
                    488: tl_reset(sc)
                    489:        tl_softc_t *sc;
                    490: {
                    491:        int i;
                    492:
                    493:        /* read stats */
                    494:        if (sc->tl_if.if_flags & IFF_RUNNING) {
1.32      thorpej   495:                callout_stop(&sc->tl_tick_ch);
1.1       bouyer    496:                tl_read_stats(sc);
                    497:        }
                    498:        /* Reset adapter */
                    499:        TL_HR_WRITE(sc, TL_HOST_CMD,
1.17      bouyer    500:            TL_HR_READ(sc, TL_HOST_CMD) | HOST_CMD_Ad_Rst);
1.1       bouyer    501:        DELAY(100000);
                    502:        /* Disable interrupts */
                    503:        TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_IntOff);
                    504:        /* setup aregs & hash */
                    505:        for (i = TL_INT_Areg0; i <= TL_INT_HASH2; i = i + 4)
                    506:                tl_intreg_write(sc, i, 0);
                    507: #ifdef TLDEBUG_ADDR
                    508:        printf("Areg & hash registers: \n");
                    509:        for (i = TL_INT_Areg0; i <= TL_INT_HASH2; i = i + 4)
                    510:                printf("    reg %x: %x\n", i, tl_intreg_read(sc, i));
                    511: #endif
                    512:        /* Setup NetConfig */
                    513:        tl_intreg_write(sc, TL_INT_NetConfig,
1.17      bouyer    514:            TL_NETCONFIG_1F | TL_NETCONFIG_1chn | TL_NETCONFIG_PHY_EN);
1.1       bouyer    515:        /* Bsize: accept default */
                    516:        /* TX commit in Acommit: accept default */
                    517:        /* Load Ld_tmr and Ld_thr */
                    518:        /* Ld_tmr = 3 */
                    519:        TL_HR_WRITE(sc, TL_HOST_CMD, 0x3 | HOST_CMD_LdTmr);
                    520:        /* Ld_thr = 0 */
                    521:        TL_HR_WRITE(sc, TL_HOST_CMD, 0x0 | HOST_CMD_LdThr);
                    522:        /* Unreset MII */
                    523:        netsio_set(sc, TL_NETSIO_NMRST);
                    524:        DELAY(100000);
1.15      thorpej   525:        sc->tl_mii.mii_media_status &= ~IFM_ACTIVE;
1.1       bouyer    526: }
                    527:
                    528: static void tl_shutdown(v)
                    529:        void *v;
                    530: {
1.46      bouyer    531:        tl_stop(v, 1);
                    532: }
                    533:
                    534: static void tl_stop(ifp, disable)
                    535:        struct ifnet *ifp;
                    536:        int disable;
                    537: {
                    538:        tl_softc_t *sc = ifp->if_softc;
1.1       bouyer    539:        struct Tx_list *Tx;
                    540:        int i;
1.59      tsutsui   541:
1.46      bouyer    542:        if ((ifp->if_flags & IFF_RUNNING) == 0)
1.1       bouyer    543:                return;
                    544:        /* disable interrupts */
1.17      bouyer    545:        TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_IntOff);
1.1       bouyer    546:        /* stop TX and RX channels */
                    547:        TL_HR_WRITE(sc, TL_HOST_CMD,
1.17      bouyer    548:            HOST_CMD_STOP | HOST_CMD_RT | HOST_CMD_Nes);
1.1       bouyer    549:        TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_STOP);
                    550:        DELAY(100000);
                    551:
1.59      tsutsui   552:        /* stop statistics reading loop, read stats */
1.32      thorpej   553:        callout_stop(&sc->tl_tick_ch);
1.1       bouyer    554:        tl_read_stats(sc);
1.26      thorpej   555:
                    556:        /* Down the MII. */
                    557:        mii_down(&sc->tl_mii);
1.1       bouyer    558:
                    559:        /* deallocate memory allocations */
1.43      bouyer    560:        if (sc->Rx_list) {
                    561:                for (i=0; i< TL_NBUF; i++) {
                    562:                        if (sc->Rx_list[i].m) {
                    563:                                bus_dmamap_unload(sc->tl_dmatag,
                    564:                                    sc->Rx_list[i].m_dmamap);
                    565:                                m_freem(sc->Rx_list[i].m);
                    566:                        }
1.59      tsutsui   567:                        bus_dmamap_destroy(sc->tl_dmatag,
1.44      bouyer    568:                            sc->Rx_list[i].m_dmamap);
1.43      bouyer    569:                        sc->Rx_list[i].m = NULL;
                    570:                }
                    571:                free(sc->Rx_list, M_DEVBUF);
                    572:                sc->Rx_list = NULL;
                    573:                bus_dmamap_unload(sc->tl_dmatag, sc->Rx_dmamap);
1.44      bouyer    574:                bus_dmamap_destroy(sc->tl_dmatag, sc->Rx_dmamap);
1.43      bouyer    575:                sc->hw_Rx_list = NULL;
                    576:                while ((Tx = sc->active_Tx) != NULL) {
                    577:                        Tx->hw_list->stat = 0;
                    578:                        bus_dmamap_unload(sc->tl_dmatag, Tx->m_dmamap);
1.44      bouyer    579:                        bus_dmamap_destroy(sc->tl_dmatag, Tx->m_dmamap);
1.43      bouyer    580:                        m_freem(Tx->m);
                    581:                        sc->active_Tx = Tx->next;
                    582:                        Tx->next = sc->Free_Tx;
                    583:                        sc->Free_Tx = Tx;
                    584:                }
                    585:                sc->last_Tx = NULL;
                    586:                free(sc->Tx_list, M_DEVBUF);
                    587:                sc->Tx_list = NULL;
                    588:                bus_dmamap_unload(sc->tl_dmatag, sc->Tx_dmamap);
1.44      bouyer    589:                bus_dmamap_destroy(sc->tl_dmatag, sc->Tx_dmamap);
1.43      bouyer    590:                sc->hw_Tx_list = NULL;
1.1       bouyer    591:        }
1.46      bouyer    592:        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
                    593:        ifp->if_timer = 0;
1.15      thorpej   594:        sc->tl_mii.mii_media_status &= ~IFM_ACTIVE;
1.1       bouyer    595: }
                    596:
                    597: static void tl_restart(v)
                    598:        void *v;
                    599: {
                    600:        tl_init(v);
                    601: }
                    602:
1.46      bouyer    603: static int tl_init(ifp)
                    604:        struct ifnet *ifp;
1.1       bouyer    605: {
1.46      bouyer    606:        tl_softc_t *sc = ifp->if_softc;
1.43      bouyer    607:        int i, s, error;
                    608:        char *errstring;
1.44      bouyer    609:        char *nullbuf;
1.1       bouyer    610:
1.14      mycroft   611:        s = splnet();
1.1       bouyer    612:        /* cancel any pending IO */
1.46      bouyer    613:        tl_stop(ifp, 1);
1.1       bouyer    614:        tl_reset(sc);
                    615:        if ((sc->tl_if.if_flags & IFF_UP) == 0) {
                    616:                splx(s);
                    617:                return 0;
                    618:        }
                    619:        /* Set various register to reasonable value */
                    620:        /* setup NetCmd in promisc mode if needed */
                    621:        i = (ifp->if_flags & IFF_PROMISC) ? TL_NETCOMMAND_CAF : 0;
                    622:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetCmd,
1.17      bouyer    623:            TL_NETCOMMAND_NRESET | TL_NETCOMMAND_NWRAP | i);
1.1       bouyer    624:        /* Max receive size : MCLBYTES */
                    625:        tl_intreg_write_byte(sc, TL_INT_MISC + TL_MISC_MaxRxL, MCLBYTES & 0xff);
                    626:        tl_intreg_write_byte(sc, TL_INT_MISC + TL_MISC_MaxRxH,
1.17      bouyer    627:            (MCLBYTES >> 8) & 0xff);
1.1       bouyer    628:
                    629:        /* init MAC addr */
                    630:        for (i = 0; i < ETHER_ADDR_LEN; i++)
                    631:                tl_intreg_write_byte(sc, TL_INT_Areg0 + i , sc->tl_enaddr[i]);
                    632:        /* add multicast filters */
                    633:        tl_addr_filter(sc);
                    634: #ifdef TLDEBUG_ADDR
                    635:        printf("Wrote Mac addr, Areg & hash registers are now: \n");
                    636:        for (i = TL_INT_Areg0; i <= TL_INT_HASH2; i = i + 4)
                    637:                printf("    reg %x: %x\n", i, tl_intreg_read(sc, i));
                    638: #endif
                    639:
                    640:        /* Pre-allocate receivers mbuf, make the lists */
1.17      bouyer    641:        sc->Rx_list = malloc(sizeof(struct Rx_list) * TL_NBUF, M_DEVBUF,
1.48      tsutsui   642:            M_NOWAIT|M_ZERO);
1.17      bouyer    643:        sc->Tx_list = malloc(sizeof(struct Tx_list) * TL_NBUF, M_DEVBUF,
1.48      tsutsui   644:            M_NOWAIT|M_ZERO);
1.1       bouyer    645:        if (sc->Rx_list == NULL || sc->Tx_list == NULL) {
1.43      bouyer    646:                errstring = "out of memory for lists";
                    647:                error = ENOMEM;
                    648:                goto bad;
                    649:        }
                    650:        error = bus_dmamap_create(sc->tl_dmatag,
                    651:            sizeof(struct tl_Rx_list) * TL_NBUF, 1,
                    652:            sizeof(struct tl_Rx_list) * TL_NBUF, 0, BUS_DMA_WAITOK,
                    653:            &sc->Rx_dmamap);
                    654:        if (error == 0)
                    655:                error = bus_dmamap_create(sc->tl_dmatag,
                    656:                    sizeof(struct tl_Tx_list) * TL_NBUF, 1,
                    657:                    sizeof(struct tl_Tx_list) * TL_NBUF, 0, BUS_DMA_WAITOK,
                    658:                    &sc->Tx_dmamap);
1.59      tsutsui   659:        if (error == 0)
1.44      bouyer    660:                error = bus_dmamap_create(sc->tl_dmatag, ETHER_MIN_TX, 1,
                    661:                    ETHER_MIN_TX, 0, BUS_DMA_WAITOK,
                    662:                    &sc->null_dmamap);
1.43      bouyer    663:        if (error) {
                    664:                errstring = "can't allocate DMA maps for lists";
                    665:                goto bad;
                    666:        }
1.46      bouyer    667:        memset(sc->ctrl, 0, PAGE_SIZE);
                    668:        sc->hw_Rx_list = (void *)sc->ctrl;
                    669:        sc->hw_Tx_list =
                    670:            (void *)(sc->ctrl + sizeof(struct tl_Rx_list) * TL_NBUF);
                    671:        nullbuf = sc->ctrl + sizeof(struct tl_Rx_list) * TL_NBUF +
1.44      bouyer    672:            sizeof(struct tl_Tx_list) * TL_NBUF;
                    673:        error = bus_dmamap_load(sc->tl_dmatag, sc->Rx_dmamap,
                    674:            sc->hw_Rx_list, sizeof(struct tl_Rx_list) * TL_NBUF, NULL,
                    675:            BUS_DMA_WAITOK);
1.43      bouyer    676:        if (error == 0)
                    677:                error = bus_dmamap_load(sc->tl_dmatag, sc->Tx_dmamap,
                    678:                    sc->hw_Tx_list, sizeof(struct tl_Tx_list) * TL_NBUF, NULL,
                    679:                    BUS_DMA_WAITOK);
1.44      bouyer    680:        if (error == 0)
                    681:                error = bus_dmamap_load(sc->tl_dmatag, sc->null_dmamap,
                    682:                    nullbuf, ETHER_MIN_TX, NULL, BUS_DMA_WAITOK);
1.43      bouyer    683:        if (error) {
1.44      bouyer    684:                errstring = "can't DMA map DMA memory for lists";
1.43      bouyer    685:                goto bad;
1.1       bouyer    686:        }
                    687:        for (i=0; i< TL_NBUF; i++) {
1.43      bouyer    688:                error = bus_dmamap_create(sc->tl_dmatag, MCLBYTES,
                    689:                    1, MCLBYTES, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
                    690:                    &sc->Rx_list[i].m_dmamap);
                    691:                if (error == 0) {
                    692:                        error = bus_dmamap_create(sc->tl_dmatag, MCLBYTES,
                    693:                            TL_NSEG, MCLBYTES, 0,
                    694:                            BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
                    695:                            &sc->Tx_list[i].m_dmamap);
                    696:                }
                    697:                if (error) {
                    698:                        errstring = "can't allocate DMA maps for mbufs";
                    699:                        goto bad;
                    700:                }
                    701:                sc->Rx_list[i].hw_list = &sc->hw_Rx_list[i];
                    702:                sc->Rx_list[i].hw_listaddr = sc->Rx_dmamap->dm_segs[0].ds_addr
                    703:                    + sizeof(struct tl_Rx_list) * i;
                    704:                sc->Tx_list[i].hw_list = &sc->hw_Tx_list[i];
                    705:                sc->Tx_list[i].hw_listaddr = sc->Tx_dmamap->dm_segs[0].ds_addr
                    706:                    + sizeof(struct tl_Tx_list) * i;
                    707:                if (tl_add_RxBuff(sc, &sc->Rx_list[i], NULL) == 0) {
                    708:                        errstring = "out of mbuf for receive list";
                    709:                        error = ENOMEM;
                    710:                        goto bad;
1.1       bouyer    711:                }
                    712:                if (i > 0) { /* chain the list */
1.59      tsutsui   713:                        sc->Rx_list[i - 1].next = &sc->Rx_list[i];
                    714:                        sc->hw_Rx_list[i - 1].fwd =
1.43      bouyer    715:                            htole32(sc->Rx_list[i].hw_listaddr);
1.59      tsutsui   716:                        sc->Tx_list[i - 1].next = &sc->Tx_list[i];
1.1       bouyer    717:                }
                    718:        }
1.59      tsutsui   719:        sc->hw_Rx_list[TL_NBUF - 1].fwd = 0;
1.60      tsutsui   720:        sc->Rx_list[TL_NBUF - 1].next = NULL;
1.59      tsutsui   721:        sc->hw_Tx_list[TL_NBUF - 1].fwd = 0;
                    722:        sc->Tx_list[TL_NBUF - 1].next = NULL;
1.1       bouyer    723:
                    724:        sc->active_Rx = &sc->Rx_list[0];
1.59      tsutsui   725:        sc->last_Rx   = &sc->Rx_list[TL_NBUF - 1];
1.1       bouyer    726:        sc->active_Tx = sc->last_Tx = NULL;
                    727:        sc->Free_Tx   = &sc->Tx_list[0];
1.43      bouyer    728:        bus_dmamap_sync(sc->tl_dmatag, sc->Rx_dmamap, 0,
                    729:            sizeof(struct tl_Rx_list) * TL_NBUF,
                    730:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    731:        bus_dmamap_sync(sc->tl_dmatag, sc->Tx_dmamap, 0,
                    732:            sizeof(struct tl_Tx_list) * TL_NBUF,
                    733:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.44      bouyer    734:        bus_dmamap_sync(sc->tl_dmatag, sc->null_dmamap, 0, ETHER_MIN_TX,
1.43      bouyer    735:            BUS_DMASYNC_PREWRITE);
1.1       bouyer    736:
1.15      thorpej   737:        /* set media */
                    738:        mii_mediachg(&sc->tl_mii);
1.1       bouyer    739:
                    740:        /* start ticks calls */
1.32      thorpej   741:        callout_reset(&sc->tl_tick_ch, hz, tl_ticks, sc);
1.64      wiz       742:        /* write address of Rx list and enable interrupts */
1.43      bouyer    743:        TL_HR_WRITE(sc, TL_HOST_CH_PARM, sc->Rx_list[0].hw_listaddr);
1.1       bouyer    744:        TL_HR_WRITE(sc, TL_HOST_CMD,
1.17      bouyer    745:            HOST_CMD_GO | HOST_CMD_RT | HOST_CMD_Nes | HOST_CMD_IntOn);
1.1       bouyer    746:        sc->tl_if.if_flags |= IFF_RUNNING;
                    747:        sc->tl_if.if_flags &= ~IFF_OACTIVE;
                    748:        return 0;
1.43      bouyer    749: bad:
                    750:        printf("%s: %s\n", sc->sc_dev.dv_xname, errstring);
                    751:        splx(s);
                    752:        return error;
1.1       bouyer    753: }
                    754:
                    755:
                    756: static u_int32_t
                    757: tl_intreg_read(sc, reg)
                    758:        tl_softc_t *sc;
                    759:        u_int32_t reg;
                    760: {
                    761:        TL_HR_WRITE(sc, TL_HOST_INTR_DIOADR, reg & TL_HOST_DIOADR_MASK);
                    762:        return TL_HR_READ(sc, TL_HOST_DIO_DATA);
                    763: }
                    764:
                    765: static u_int8_t
                    766: tl_intreg_read_byte(sc, reg)
                    767:        tl_softc_t *sc;
                    768:        u_int32_t reg;
                    769: {
                    770:        TL_HR_WRITE(sc, TL_HOST_INTR_DIOADR,
1.17      bouyer    771:            (reg & (~0x07)) & TL_HOST_DIOADR_MASK);
1.1       bouyer    772:        return TL_HR_READ_BYTE(sc, TL_HOST_DIO_DATA + (reg & 0x07));
                    773: }
                    774:
                    775: static void
                    776: tl_intreg_write(sc, reg, val)
                    777:        tl_softc_t *sc;
                    778:        u_int32_t reg;
                    779:        u_int32_t val;
                    780: {
                    781:        TL_HR_WRITE(sc, TL_HOST_INTR_DIOADR, reg & TL_HOST_DIOADR_MASK);
                    782:        TL_HR_WRITE(sc, TL_HOST_DIO_DATA, val);
                    783: }
                    784:
                    785: static void
                    786: tl_intreg_write_byte(sc, reg, val)
                    787:        tl_softc_t *sc;
                    788:        u_int32_t reg;
                    789:        u_int8_t val;
                    790: {
                    791:        TL_HR_WRITE(sc, TL_HOST_INTR_DIOADR,
1.17      bouyer    792:            (reg & (~0x03)) & TL_HOST_DIOADR_MASK);
1.1       bouyer    793:        TL_HR_WRITE_BYTE(sc, TL_HOST_DIO_DATA + (reg & 0x03), val);
                    794: }
                    795:
1.28      tron      796: void
                    797: tl_mii_sync(sc)
                    798:        struct tl_softc *sc;
1.1       bouyer    799: {
1.28      tron      800:        int i;
1.1       bouyer    801:
1.28      tron      802:        netsio_clr(sc, TL_NETSIO_MTXEN);
                    803:        for (i = 0; i < 32; i++) {
                    804:                netsio_clr(sc, TL_NETSIO_MCLK);
                    805:                netsio_set(sc, TL_NETSIO_MCLK);
                    806:        }
1.1       bouyer    807: }
                    808:
1.15      thorpej   809: void
1.28      tron      810: tl_mii_sendbits(sc, data, nbits)
                    811:        struct tl_softc *sc;
                    812:        u_int32_t data;
                    813:        int nbits;
1.1       bouyer    814: {
1.28      tron      815:        int i;
1.1       bouyer    816:
1.28      tron      817:        netsio_set(sc, TL_NETSIO_MTXEN);
                    818:        for (i = 1 << (nbits - 1); i; i = i >>  1) {
                    819:                netsio_clr(sc, TL_NETSIO_MCLK);
                    820:                netsio_read(sc, TL_NETSIO_MCLK);
                    821:                if (data & i)
                    822:                        netsio_set(sc, TL_NETSIO_MDATA);
                    823:                else
                    824:                        netsio_clr(sc, TL_NETSIO_MDATA);
                    825:                netsio_set(sc, TL_NETSIO_MCLK);
                    826:                netsio_read(sc, TL_NETSIO_MCLK);
                    827:        }
1.1       bouyer    828: }
                    829:
1.15      thorpej   830: int
                    831: tl_mii_read(self, phy, reg)
                    832:        struct device *self;
                    833:        int phy, reg;
1.1       bouyer    834: {
1.28      tron      835:        struct tl_softc *sc = (struct tl_softc *)self;
                    836:        int val = 0, i, err;
                    837:
                    838:        /*
                    839:         * Read the PHY register by manually driving the MII control lines.
                    840:         */
1.1       bouyer    841:
1.28      tron      842:        tl_mii_sync(sc);
                    843:        tl_mii_sendbits(sc, MII_COMMAND_START, 2);
                    844:        tl_mii_sendbits(sc, MII_COMMAND_READ, 2);
                    845:        tl_mii_sendbits(sc, phy, 5);
                    846:        tl_mii_sendbits(sc, reg, 5);
                    847:
                    848:        netsio_clr(sc, TL_NETSIO_MTXEN);
                    849:        netsio_clr(sc, TL_NETSIO_MCLK);
                    850:        netsio_set(sc, TL_NETSIO_MCLK);
                    851:        netsio_clr(sc, TL_NETSIO_MCLK);
                    852:
                    853:        err = netsio_read(sc, TL_NETSIO_MDATA);
                    854:        netsio_set(sc, TL_NETSIO_MCLK);
                    855:
                    856:        /* Even if an error occurs, must still clock out the cycle. */
                    857:        for (i = 0; i < 16; i++) {
                    858:                val <<= 1;
                    859:                netsio_clr(sc, TL_NETSIO_MCLK);
                    860:                if (err == 0 && netsio_read(sc, TL_NETSIO_MDATA))
                    861:                        val |= 1;
                    862:                netsio_set(sc, TL_NETSIO_MCLK);
                    863:        }
                    864:        netsio_clr(sc, TL_NETSIO_MCLK);
                    865:        netsio_set(sc, TL_NETSIO_MCLK);
                    866:
                    867:        return (err ? 0 : val);
1.15      thorpej   868: }
                    869:
                    870: void
                    871: tl_mii_write(self, phy, reg, val)
                    872:        struct device *self;
                    873:        int phy, reg, val;
                    874: {
1.28      tron      875:        struct tl_softc *sc = (struct tl_softc *)self;
                    876:
                    877:        /*
                    878:         * Write the PHY register by manually driving the MII control lines.
                    879:         */
                    880:
                    881:        tl_mii_sync(sc);
                    882:        tl_mii_sendbits(sc, MII_COMMAND_START, 2);
                    883:        tl_mii_sendbits(sc, MII_COMMAND_WRITE, 2);
                    884:        tl_mii_sendbits(sc, phy, 5);
                    885:        tl_mii_sendbits(sc, reg, 5);
                    886:        tl_mii_sendbits(sc, MII_COMMAND_ACK, 2);
                    887:        tl_mii_sendbits(sc, val, 16);
1.15      thorpej   888:
1.28      tron      889:        netsio_clr(sc, TL_NETSIO_MCLK);
                    890:        netsio_set(sc, TL_NETSIO_MCLK);
1.15      thorpej   891: }
                    892:
                    893: void
                    894: tl_statchg(self)
                    895:        struct device *self;
                    896: {
                    897:        tl_softc_t *sc = (struct tl_softc *)self;
                    898:        u_int32_t reg;
                    899:
                    900: #ifdef TLDEBUG
                    901:        printf("tl_statchg, media %x\n", sc->tl_ifmedia.ifm_media);
                    902: #endif
                    903:
                    904:        /*
                    905:         * We must keep the ThunderLAN and the PHY in sync as
                    906:         * to the status of full-duplex!
                    907:         */
                    908:        reg = tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetCmd);
                    909:        if (sc->tl_mii.mii_media_active & IFM_FDX)
                    910:                reg |= TL_NETCOMMAND_DUPLEX;
                    911:        else
                    912:                reg &= ~TL_NETCOMMAND_DUPLEX;
                    913:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetCmd, reg);
1.1       bouyer    914: }
                    915:
1.58      thorpej   916: /********** I2C glue **********/
                    917:
                    918: static int
                    919: tl_i2c_acquire_bus(void *cookie, int flags)
                    920: {
                    921:
                    922:        /* private bus */
                    923:        return (0);
                    924: }
                    925:
                    926: static void
                    927: tl_i2c_release_bus(void *cookie, int flags)
                    928: {
                    929:
                    930:        /* private bus */
                    931: }
                    932:
                    933: static int
                    934: tl_i2c_send_start(void *cookie, int flags)
                    935: {
                    936:
                    937:        return (i2c_bitbang_send_start(cookie, flags, &tl_i2cbb_ops));
                    938: }
                    939:
                    940: static int
                    941: tl_i2c_send_stop(void *cookie, int flags)
                    942: {
                    943:
                    944:        return (i2c_bitbang_send_stop(cookie, flags, &tl_i2cbb_ops));
                    945: }
                    946:
                    947: static int
                    948: tl_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
                    949: {
                    950:
                    951:        return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &tl_i2cbb_ops));
                    952: }
                    953:
                    954: static int
                    955: tl_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
                    956: {
                    957:
                    958:        return (i2c_bitbang_read_byte(cookie, valp, flags, &tl_i2cbb_ops));
                    959: }
                    960:
                    961: static int
                    962: tl_i2c_write_byte(void *cookie, uint8_t val, int flags)
                    963: {
                    964:
                    965:        return (i2c_bitbang_write_byte(cookie, val, flags, &tl_i2cbb_ops));
                    966: }
                    967:
                    968: /********** I2C bit-bang glue **********/
                    969:
                    970: static void
                    971: tl_i2cbb_set_bits(void *cookie, uint32_t bits)
1.1       bouyer    972: {
1.58      thorpej   973:        struct tl_softc *sc = cookie;
                    974:        uint8_t reg;
1.1       bouyer    975:
1.58      thorpej   976:        reg = tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetSio);
                    977:        reg = (reg & ~(TL_NETSIO_EDATA|TL_NETSIO_ECLOCK)) | bits;
                    978:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetSio, reg);
1.1       bouyer    979: }
                    980:
1.58      thorpej   981: static void
                    982: tl_i2cbb_set_dir(void *cookie, uint32_t bits)
1.1       bouyer    983: {
1.58      thorpej   984:        struct tl_softc *sc = cookie;
                    985:        uint8_t reg;
1.1       bouyer    986:
1.58      thorpej   987:        reg = tl_intreg_read_byte(sc, TL_INT_NET + TL_INT_NetSio);
                    988:        reg = (reg & ~TL_NETSIO_ETXEN) | bits;
                    989:        tl_intreg_write_byte(sc, TL_INT_NET + TL_INT_NetSio, reg);
1.1       bouyer    990: }
                    991:
1.58      thorpej   992: static uint32_t
                    993: tl_i2cbb_read(void *cookie)
1.1       bouyer    994: {
                    995:
1.58      thorpej   996:        return (tl_intreg_read_byte(cookie, TL_INT_NET + TL_INT_NetSio));
1.1       bouyer    997: }
1.58      thorpej   998:
                    999: /********** End of I2C stuff **********/
1.1       bouyer   1000:
                   1001: static int
                   1002: tl_intr(v)
                   1003:        void *v;
                   1004: {
                   1005:        tl_softc_t *sc = v;
                   1006:        struct ifnet *ifp = &sc->tl_if;
                   1007:        struct Rx_list *Rx;
                   1008:        struct Tx_list *Tx;
                   1009:        struct mbuf *m;
                   1010:        u_int32_t int_type, int_reg;
                   1011:        int ack = 0;
                   1012:        int size;
                   1013:
1.59      tsutsui  1014:        int_reg = TL_HR_READ(sc, TL_HOST_INTR_DIOADR);
1.1       bouyer   1015:        int_type = int_reg  & TL_INTR_MASK;
                   1016:        if (int_type == 0)
                   1017:                return 0;
                   1018: #if defined(TLDEBUG_RX) || defined(TLDEBUG_TX)
                   1019:        printf("%s: interrupt type %x, intr_reg %x\n", sc->sc_dev.dv_xname,
1.17      bouyer   1020:            int_type, int_reg);
1.1       bouyer   1021: #endif
                   1022:        /* disable interrupts */
                   1023:        TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_IntOff);
                   1024:        switch(int_type & TL_INTR_MASK) {
                   1025:        case TL_INTR_RxEOF:
1.43      bouyer   1026:                bus_dmamap_sync(sc->tl_dmatag, sc->Rx_dmamap, 0,
                   1027:                    sizeof(struct tl_Rx_list) * TL_NBUF,
                   1028:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                   1029:                while(le32toh(sc->active_Rx->hw_list->stat) &
                   1030:                    TL_RX_CSTAT_CPLT) {
1.1       bouyer   1031:                        /* dequeue and requeue at end of list */
                   1032:                        ack++;
                   1033:                        Rx = sc->active_Rx;
                   1034:                        sc->active_Rx = Rx->next;
1.43      bouyer   1035:                        bus_dmamap_sync(sc->tl_dmatag, Rx->m_dmamap, 0,
1.61      tsutsui  1036:                            Rx->m_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
1.43      bouyer   1037:                        bus_dmamap_unload(sc->tl_dmatag, Rx->m_dmamap);
1.1       bouyer   1038:                        m = Rx->m;
1.43      bouyer   1039:                        size = le32toh(Rx->hw_list->stat) >> 16;
1.1       bouyer   1040: #ifdef TLDEBUG_RX
1.17      bouyer   1041:                        printf("tl_intr: RX list complete, Rx %p, size=%d\n",
                   1042:                            Rx, size);
1.1       bouyer   1043: #endif
1.43      bouyer   1044:                        if (tl_add_RxBuff(sc, Rx, m ) == 0) {
1.17      bouyer   1045:                                /*
                   1046:                                 * No new mbuf, reuse the same. This means
                   1047:                                 * that this packet
                   1048:                                 * is lost
                   1049:                                 */
1.1       bouyer   1050:                                m = NULL;
                   1051: #ifdef TL_PRIV_STATS
                   1052:                                sc->ierr_nomem++;
                   1053: #endif
                   1054: #ifdef TLDEBUG
                   1055:                                printf("%s: out of mbuf, lost input packet\n",
1.17      bouyer   1056:                                    sc->sc_dev.dv_xname);
1.1       bouyer   1057: #endif
                   1058:                        }
                   1059:                        Rx->next = NULL;
1.43      bouyer   1060:                        Rx->hw_list->fwd = 0;
                   1061:                        sc->last_Rx->hw_list->fwd = htole32(Rx->hw_listaddr);
1.1       bouyer   1062:                        sc->last_Rx->next = Rx;
                   1063:                        sc->last_Rx = Rx;
                   1064:
                   1065:                        /* deliver packet */
                   1066:                        if (m) {
                   1067:                                if (size < sizeof(struct ether_header)) {
                   1068:                                        m_freem(m);
                   1069:                                        continue;
                   1070:                                }
                   1071:                                m->m_pkthdr.rcvif = ifp;
1.24      thorpej  1072:                                m->m_pkthdr.len = m->m_len = size;
1.1       bouyer   1073: #ifdef TLDEBUG_RX
1.36      thorpej  1074:                                { struct ether_header *eh =
                   1075:                                    mtod(m, struct ether_header *);
1.1       bouyer   1076:                                printf("tl_intr: Rx packet:\n");
1.36      thorpej  1077:                                ether_printheader(eh); }
1.1       bouyer   1078: #endif
                   1079: #if NBPFILTER > 0
1.36      thorpej  1080:                                if (ifp->if_bpf)
                   1081:                                        bpf_mtap(ifp->if_bpf, m);
1.1       bouyer   1082: #endif /* NBPFILTER > 0 */
1.24      thorpej  1083:                                (*ifp->if_input)(ifp, m);
1.1       bouyer   1084:                        }
                   1085:                }
1.43      bouyer   1086:                bus_dmamap_sync(sc->tl_dmatag, sc->Rx_dmamap, 0,
                   1087:                    sizeof(struct tl_Rx_list) * TL_NBUF,
                   1088:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1089: #ifdef TLDEBUG_RX
                   1090:                printf("TL_INTR_RxEOF: ack %d\n", ack);
                   1091: #else
                   1092:                if (ack == 0) {
                   1093:                        printf("%s: EOF intr without anything to read !\n",
1.17      bouyer   1094:                            sc->sc_dev.dv_xname);
1.1       bouyer   1095:                        tl_reset(sc);
                   1096:                        /* shedule reinit of the board */
1.32      thorpej  1097:                        callout_reset(&sc->tl_restart_ch, 1, tl_restart, sc);
1.1       bouyer   1098:                        return(1);
                   1099:                }
                   1100: #endif
                   1101:                break;
                   1102:        case TL_INTR_RxEOC:
                   1103:                ack++;
1.43      bouyer   1104:                bus_dmamap_sync(sc->tl_dmatag, sc->Rx_dmamap, 0,
                   1105:                    sizeof(struct tl_Rx_list) * TL_NBUF,
                   1106:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.1       bouyer   1107: #ifdef TLDEBUG_RX
                   1108:                printf("TL_INTR_RxEOC: ack %d\n", ack);
                   1109: #endif
                   1110: #ifdef DIAGNOSTIC
1.43      bouyer   1111:                if (le32toh(sc->active_Rx->hw_list->stat) & TL_RX_CSTAT_CPLT) {
                   1112:                        printf("%s: Rx EOC interrupt and active Tx list not "
1.17      bouyer   1113:                            "cleared\n", sc->sc_dev.dv_xname);
1.1       bouyer   1114:                        return 0;
                   1115:                } else
1.59      tsutsui  1116: #endif
1.1       bouyer   1117:                {
1.17      bouyer   1118:                /*
1.64      wiz      1119:                 * write address of Rx list and send Rx GO command, ack
1.17      bouyer   1120:                 * interrupt and enable interrupts in one command
                   1121:                 */
1.43      bouyer   1122:                TL_HR_WRITE(sc, TL_HOST_CH_PARM, sc->active_Rx->hw_listaddr);
1.1       bouyer   1123:                TL_HR_WRITE(sc, TL_HOST_CMD,
1.17      bouyer   1124:                    HOST_CMD_GO | HOST_CMD_RT | HOST_CMD_Nes | ack | int_type |
                   1125:                    HOST_CMD_ACK | HOST_CMD_IntOn);
1.1       bouyer   1126:                return 1;
                   1127:                }
                   1128:        case TL_INTR_TxEOF:
                   1129:        case TL_INTR_TxEOC:
1.43      bouyer   1130:                bus_dmamap_sync(sc->tl_dmatag, sc->Tx_dmamap, 0,
                   1131:                    sizeof(struct tl_Tx_list) * TL_NBUF,
                   1132:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.1       bouyer   1133:                while ((Tx = sc->active_Tx) != NULL) {
1.43      bouyer   1134:                        if((le32toh(Tx->hw_list->stat) & TL_TX_CSTAT_CPLT) == 0)
1.1       bouyer   1135:                                break;
                   1136:                        ack++;
                   1137: #ifdef TLDEBUG_TX
1.44      bouyer   1138:                        printf("TL_INTR_TxEOC: list 0x%x done\n",
                   1139:                            (int)Tx->hw_listaddr);
1.1       bouyer   1140: #endif
1.43      bouyer   1141:                        Tx->hw_list->stat = 0;
                   1142:                        bus_dmamap_sync(sc->tl_dmatag, Tx->m_dmamap, 0,
1.61      tsutsui  1143:                            Tx->m_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1.43      bouyer   1144:                        bus_dmamap_unload(sc->tl_dmatag, Tx->m_dmamap);
1.1       bouyer   1145:                        m_freem(Tx->m);
                   1146:                        Tx->m = NULL;
                   1147:                        sc->active_Tx = Tx->next;
                   1148:                        if (sc->active_Tx == NULL)
                   1149:                                sc->last_Tx = NULL;
                   1150:                        Tx->next = sc->Free_Tx;
                   1151:                        sc->Free_Tx = Tx;
                   1152:                }
1.43      bouyer   1153:                bus_dmamap_sync(sc->tl_dmatag, sc->Tx_dmamap, 0,
                   1154:                    sizeof(struct tl_Tx_list) * TL_NBUF,
                   1155:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1156:                /* if this was an EOC, ACK immediatly */
1.45      bouyer   1157:                if (ack)
                   1158:                        sc->tl_if.if_flags &= ~IFF_OACTIVE;
1.1       bouyer   1159:                if (int_type == TL_INTR_TxEOC) {
                   1160: #ifdef TLDEBUG_TX
1.17      bouyer   1161:                        printf("TL_INTR_TxEOC: ack %d (will be set to 1)\n",
                   1162:                            ack);
1.1       bouyer   1163: #endif
1.17      bouyer   1164:                        TL_HR_WRITE(sc, TL_HOST_CMD, 1 | int_type |
                   1165:                            HOST_CMD_ACK | HOST_CMD_IntOn);
                   1166:                        if ( sc->active_Tx != NULL) {
                   1167:                                /* needs a Tx go command */
1.1       bouyer   1168:                                TL_HR_WRITE(sc, TL_HOST_CH_PARM,
1.43      bouyer   1169:                                    sc->active_Tx->hw_listaddr);
1.1       bouyer   1170:                                TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_GO);
                   1171:                        }
                   1172:                        sc->tl_if.if_timer = 0;
1.50      itojun   1173:                        if (IFQ_IS_EMPTY(&sc->tl_if.if_snd) == 0)
1.1       bouyer   1174:                                tl_ifstart(&sc->tl_if);
                   1175:                        return 1;
                   1176:                }
                   1177: #ifdef TLDEBUG
                   1178:                else {
                   1179:                        printf("TL_INTR_TxEOF: ack %d\n", ack);
                   1180:                }
                   1181: #endif
                   1182:                sc->tl_if.if_timer = 0;
1.50      itojun   1183:                if (IFQ_IS_EMPTY(&sc->tl_if.if_snd) == 0)
1.1       bouyer   1184:                        tl_ifstart(&sc->tl_if);
                   1185:                break;
                   1186:        case TL_INTR_Stat:
                   1187:                ack++;
                   1188: #ifdef TLDEBUG
                   1189:                printf("TL_INTR_Stat: ack %d\n", ack);
                   1190: #endif
                   1191:                tl_read_stats(sc);
                   1192:                break;
                   1193:        case TL_INTR_Adc:
                   1194:                if (int_reg & TL_INTVec_MASK) {
                   1195:                        /* adapter check conditions */
1.17      bouyer   1196:                        printf("%s: check condition, intvect=0x%x, "
                   1197:                            "ch_param=0x%x\n", sc->sc_dev.dv_xname,
                   1198:                            int_reg & TL_INTVec_MASK,
                   1199:                            TL_HR_READ(sc, TL_HOST_CH_PARM));
1.1       bouyer   1200:                        tl_reset(sc);
                   1201:                        /* shedule reinit of the board */
1.32      thorpej  1202:                        callout_reset(&sc->tl_restart_ch, 1, tl_restart, sc);
1.1       bouyer   1203:                        return(1);
                   1204:                } else {
                   1205:                        u_int8_t netstat;
                   1206:                        /* Network status */
1.17      bouyer   1207:                        netstat =
                   1208:                            tl_intreg_read_byte(sc, TL_INT_NET+TL_INT_NetSts);
1.1       bouyer   1209:                        printf("%s: network status, NetSts=%x\n",
1.17      bouyer   1210:                            sc->sc_dev.dv_xname, netstat);
1.1       bouyer   1211:                        /* Ack interrupts */
1.17      bouyer   1212:                        tl_intreg_write_byte(sc, TL_INT_NET+TL_INT_NetSts,
1.59      tsutsui  1213:                            netstat);
1.1       bouyer   1214:                        ack++;
                   1215:                }
                   1216:                break;
                   1217:        default:
                   1218:                printf("%s: unhandled interrupt code %x!\n",
1.17      bouyer   1219:                    sc->sc_dev.dv_xname, int_type);
1.1       bouyer   1220:                ack++;
                   1221:        }
                   1222:
                   1223:        if (ack) {
                   1224:                /* Ack the interrupt and enable interrupts */
1.59      tsutsui  1225:                TL_HR_WRITE(sc, TL_HOST_CMD, ack | int_type | HOST_CMD_ACK |
1.17      bouyer   1226:                    HOST_CMD_IntOn);
1.1       bouyer   1227:                return 1;
                   1228:        }
                   1229:        /* ack = 0 ; interrupt was perhaps not our. Just enable interrupts */
                   1230:        TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_IntOn);
                   1231:        return 0;
                   1232: }
                   1233:
                   1234: static int
1.59      tsutsui  1235: tl_ifioctl(ifp, cmd, data)
                   1236:        struct ifnet *ifp;
1.1       bouyer   1237:        ioctl_cmd_t cmd;
                   1238:        caddr_t data;
                   1239: {
                   1240:        struct tl_softc *sc = ifp->if_softc;
                   1241:        struct ifreq *ifr = (struct ifreq *)data;
                   1242:        int s, error;
1.59      tsutsui  1243:
1.14      mycroft  1244:        s = splnet();
1.1       bouyer   1245:        switch(cmd) {
1.46      bouyer   1246:        case SIOCSIFMEDIA:
                   1247:        case SIOCGIFMEDIA:
                   1248:                error = ifmedia_ioctl(ifp, ifr, &sc->tl_mii.mii_media, cmd);
1.1       bouyer   1249:                break;
1.46      bouyer   1250:        default:
                   1251:                error = ether_ioctl(ifp, cmd, data);
1.1       bouyer   1252:                if (error == ENETRESET) {
                   1253:                        tl_addr_filter(sc);
                   1254:                        error = 0;
                   1255:                }
                   1256:        }
                   1257:        splx(s);
                   1258:        return error;
                   1259: }
                   1260:
                   1261: static void
                   1262: tl_ifstart(ifp)
                   1263:        struct ifnet *ifp;
                   1264: {
                   1265:        tl_softc_t *sc = ifp->if_softc;
1.43      bouyer   1266:        struct mbuf *mb_head;
1.1       bouyer   1267:        struct Tx_list *Tx;
                   1268:        int segment, size;
1.45      bouyer   1269:        int again, error;
1.59      tsutsui  1270:
1.45      bouyer   1271:        if ((sc->tl_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
                   1272:                return;
1.1       bouyer   1273: txloop:
                   1274:        /* If we don't have more space ... */
                   1275:        if (sc->Free_Tx == NULL) {
                   1276: #ifdef TLDEBUG
                   1277:                printf("tl_ifstart: No free TX list\n");
                   1278: #endif
1.45      bouyer   1279:                sc->tl_if.if_flags |= IFF_OACTIVE;
1.1       bouyer   1280:                return;
                   1281:        }
                   1282:        /* Grab a paquet for output */
1.50      itojun   1283:        IFQ_DEQUEUE(&ifp->if_snd, mb_head);
1.1       bouyer   1284:        if (mb_head == NULL) {
                   1285: #ifdef TLDEBUG_TX
                   1286:                printf("tl_ifstart: nothing to send\n");
                   1287: #endif
                   1288:                return;
                   1289:        }
                   1290:        Tx = sc->Free_Tx;
                   1291:        sc->Free_Tx = Tx->next;
1.43      bouyer   1292:        Tx->next = NULL;
1.45      bouyer   1293:        again = 0;
1.1       bouyer   1294:        /*
                   1295:         * Go through each of the mbufs in the chain and initialize
                   1296:         * the transmit list descriptors with the physical address
                   1297:         * and size of the mbuf.
                   1298:         */
                   1299: tbdinit:
1.43      bouyer   1300:        memset(Tx->hw_list, 0, sizeof(struct tl_Tx_list));
1.1       bouyer   1301:        Tx->m = mb_head;
1.43      bouyer   1302:        size = mb_head->m_pkthdr.len;
                   1303:        if ((error = bus_dmamap_load_mbuf(sc->tl_dmatag, Tx->m_dmamap, mb_head,
                   1304:            BUS_DMA_NOWAIT)) || (size < ETHER_MIN_TX &&
                   1305:            Tx->m_dmamap->dm_nsegs == TL_NSEG)) {
                   1306:                struct mbuf *mn;
1.1       bouyer   1307:                /*
1.17      bouyer   1308:                 * We ran out of segments, or we will. We have to recopy this
                   1309:                 * mbuf chain first.
1.1       bouyer   1310:                 */
1.43      bouyer   1311:                 if (error == 0)
                   1312:                        bus_dmamap_unload(sc->tl_dmatag, Tx->m_dmamap);
                   1313:                 if (again) {
                   1314:                        /* already copyed, can't do much more */
                   1315:                        m_freem(mb_head);
                   1316:                        goto bad;
                   1317:                }
                   1318:                again = 1;
1.1       bouyer   1319: #ifdef TLDEBUG_TX
                   1320:                printf("tl_ifstart: need to copy mbuf\n");
                   1321: #endif
                   1322: #ifdef TL_PRIV_STATS
                   1323:                sc->oerr_mcopy++;
                   1324: #endif
                   1325:                MGETHDR(mn, M_DONTWAIT, MT_DATA);
                   1326:                if (mn == NULL) {
                   1327:                        m_freem(mb_head);
                   1328:                        goto bad;
                   1329:                }
                   1330:                if (mb_head->m_pkthdr.len > MHLEN) {
                   1331:                        MCLGET(mn, M_DONTWAIT);
                   1332:                        if ((mn->m_flags & M_EXT) == 0) {
                   1333:                                m_freem(mn);
                   1334:                                m_freem(mb_head);
                   1335:                                goto bad;
                   1336:                        }
                   1337:                }
                   1338:                m_copydata(mb_head, 0, mb_head->m_pkthdr.len,
1.17      bouyer   1339:                    mtod(mn, caddr_t));
1.1       bouyer   1340:                mn->m_pkthdr.len = mn->m_len = mb_head->m_pkthdr.len;
                   1341:                m_freem(mb_head);
                   1342:                mb_head = mn;
                   1343:                goto tbdinit;
                   1344:        }
1.43      bouyer   1345:        for (segment = 0; segment < Tx->m_dmamap->dm_nsegs; segment++) {
                   1346:                Tx->hw_list->seg[segment].data_addr =
                   1347:                    htole32(Tx->m_dmamap->dm_segs[segment].ds_addr);
1.59      tsutsui  1348:                Tx->hw_list->seg[segment].data_count =
                   1349:                    htole32(Tx->m_dmamap->dm_segs[segment].ds_len);
1.43      bouyer   1350:        }
1.61      tsutsui  1351:        bus_dmamap_sync(sc->tl_dmatag, Tx->m_dmamap, 0,
                   1352:            Tx->m_dmamap->dm_mapsize,
1.43      bouyer   1353:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1354:        /* We are at end of mbuf chain. check the size and
                   1355:         * see if it needs to be extended
1.59      tsutsui  1356:         */
1.1       bouyer   1357:        if (size < ETHER_MIN_TX) {
                   1358: #ifdef DIAGNOSTIC
                   1359:                if (segment >= TL_NSEG) {
1.53      provos   1360:                        panic("tl_ifstart: to much segmets (%d)", segment);
1.1       bouyer   1361:                }
                   1362: #endif
                   1363:                /*
                   1364:                 * add the nullbuf in the seg
                   1365:                 */
1.43      bouyer   1366:                Tx->hw_list->seg[segment].data_count =
                   1367:                    htole32(ETHER_MIN_TX - size);
1.44      bouyer   1368:                Tx->hw_list->seg[segment].data_addr =
                   1369:                    htole32(sc->null_dmamap->dm_segs[0].ds_addr);
1.1       bouyer   1370:                size = ETHER_MIN_TX;
                   1371:                segment++;
                   1372:        }
                   1373:        /* The list is done, finish the list init */
1.59      tsutsui  1374:        Tx->hw_list->seg[segment - 1].data_count |=
1.43      bouyer   1375:            htole32(TL_LAST_SEG);
                   1376:        Tx->hw_list->stat = htole32((size << 16) | 0x3000);
1.1       bouyer   1377: #ifdef TLDEBUG_TX
                   1378:        printf("%s: sending, Tx : stat = 0x%x\n", sc->sc_dev.dv_xname,
1.43      bouyer   1379:            le32toh(Tx->hw_list->stat));
1.59      tsutsui  1380: #if 0
1.1       bouyer   1381:        for(segment = 0; segment < TL_NSEG; segment++) {
                   1382:                printf("    seg %d addr 0x%x len 0x%x\n",
1.17      bouyer   1383:                    segment,
1.43      bouyer   1384:                    le32toh(Tx->hw_list->seg[segment].data_addr),
                   1385:                    le32toh(Tx->hw_list->seg[segment].data_count));
1.1       bouyer   1386:        }
                   1387: #endif
                   1388: #endif
                   1389:        if (sc->active_Tx == NULL) {
                   1390:                sc->active_Tx = sc->last_Tx = Tx;
                   1391: #ifdef TLDEBUG_TX
1.44      bouyer   1392:                printf("%s: Tx GO, addr=0x%ux\n", sc->sc_dev.dv_xname,
                   1393:                    (int)Tx->hw_listaddr);
1.1       bouyer   1394: #endif
1.43      bouyer   1395:                bus_dmamap_sync(sc->tl_dmatag, sc->Tx_dmamap, 0,
                   1396:                    sizeof(struct tl_Tx_list) * TL_NBUF,
                   1397:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                   1398:                TL_HR_WRITE(sc, TL_HOST_CH_PARM, Tx->hw_listaddr);
1.1       bouyer   1399:                TL_HR_WRITE(sc, TL_HOST_CMD, HOST_CMD_GO);
                   1400:        } else {
                   1401: #ifdef TLDEBUG_TX
1.44      bouyer   1402:                printf("%s: Tx addr=0x%ux queued\n", sc->sc_dev.dv_xname,
                   1403:                    (int)Tx->hw_listaddr);
1.1       bouyer   1404: #endif
1.43      bouyer   1405:                sc->last_Tx->hw_list->fwd = htole32(Tx->hw_listaddr);
1.45      bouyer   1406:                bus_dmamap_sync(sc->tl_dmatag, sc->Tx_dmamap, 0,
                   1407:                    sizeof(struct tl_Tx_list) * TL_NBUF,
                   1408:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1409:                sc->last_Tx->next = Tx;
                   1410:                sc->last_Tx = Tx;
                   1411: #ifdef DIAGNOSTIC
1.43      bouyer   1412:                if (sc->last_Tx->hw_list->fwd & 0x7)
1.17      bouyer   1413:                        printf("%s: physical addr 0x%x of list not properly "
                   1414:                           "aligned\n",
1.43      bouyer   1415:                           sc->sc_dev.dv_xname, sc->last_Rx->hw_list->fwd);
1.1       bouyer   1416: #endif
                   1417:        }
                   1418: #if NBPFILTER > 0
                   1419:        /* Pass packet to bpf if there is a listener */
                   1420:        if (ifp->if_bpf)
                   1421:                bpf_mtap(ifp->if_bpf, mb_head);
                   1422: #endif
1.17      bouyer   1423:        /*
                   1424:         * Set a 5 second timer just in case we don't hear from the card again.
                   1425:         */
1.1       bouyer   1426:        ifp->if_timer = 5;
                   1427:        goto txloop;
                   1428: bad:
                   1429: #ifdef TLDEBUG
                   1430:        printf("tl_ifstart: Out of mbuf, Tx pkt lost\n");
                   1431: #endif
                   1432:        Tx->next = sc->Free_Tx;
                   1433:        sc->Free_Tx = Tx;
                   1434:        return;
                   1435: }
                   1436:
                   1437: static void
                   1438: tl_ifwatchdog(ifp)
                   1439:        struct ifnet *ifp;
                   1440: {
                   1441:        tl_softc_t *sc = ifp->if_softc;
                   1442:
                   1443:        if ((ifp->if_flags & IFF_RUNNING) == 0)
                   1444:                return;
                   1445:        printf("%s: device timeout\n", sc->sc_dev.dv_xname);
                   1446:        ifp->if_oerrors++;
1.46      bouyer   1447:        tl_init(ifp);
1.1       bouyer   1448: }
                   1449:
                   1450: static int
                   1451: tl_mediachange(ifp)
                   1452:        struct ifnet *ifp;
                   1453: {
1.15      thorpej  1454:
                   1455:        if (ifp->if_flags & IFF_UP)
1.51      christos 1456:                tl_init(ifp);
1.15      thorpej  1457:        return (0);
1.1       bouyer   1458: }
                   1459:
                   1460: static void
                   1461: tl_mediastatus(ifp, ifmr)
                   1462:        struct ifnet *ifp;
                   1463:        struct ifmediareq *ifmr;
                   1464: {
                   1465:        tl_softc_t *sc = ifp->if_softc;
1.15      thorpej  1466:
                   1467:        mii_pollstat(&sc->tl_mii);
                   1468:        ifmr->ifm_active = sc->tl_mii.mii_media_active;
                   1469:        ifmr->ifm_status = sc->tl_mii.mii_media_status;
1.1       bouyer   1470: }
                   1471:
1.43      bouyer   1472: static int tl_add_RxBuff(sc, Rx, oldm)
                   1473:        tl_softc_t *sc;
1.1       bouyer   1474:        struct Rx_list *Rx;
                   1475:        struct mbuf *oldm;
                   1476: {
                   1477:        struct mbuf *m;
1.43      bouyer   1478:        int error;
1.1       bouyer   1479:
                   1480:        MGETHDR(m, M_DONTWAIT, MT_DATA);
                   1481:        if (m != NULL) {
                   1482:                MCLGET(m, M_DONTWAIT);
                   1483:                if ((m->m_flags & M_EXT) == 0) {
                   1484:                        m_freem(m);
                   1485:                        if (oldm == NULL)
                   1486:                                return 0;
                   1487:                        m = oldm;
                   1488:                        m->m_data = m->m_ext.ext_buf;
                   1489:                }
                   1490:        } else {
                   1491:                if (oldm == NULL)
                   1492:                        return 0;
                   1493:                m = oldm;
                   1494:                m->m_data = m->m_ext.ext_buf;
                   1495:        }
1.43      bouyer   1496:
                   1497:        /* (re)init the Rx_list struct */
                   1498:
                   1499:        Rx->m = m;
                   1500:        if ((error = bus_dmamap_load(sc->tl_dmatag, Rx->m_dmamap,
                   1501:            m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT)) != 0) {
                   1502:                printf("%s: bus_dmamap_load() failed (error %d) for "
                   1503:                    "tl_add_RxBuff\n", sc->sc_dev.dv_xname, error);
                   1504:                printf("size %d (%d)\n", m->m_pkthdr.len, MCLBYTES);
                   1505:                m_freem(m);
                   1506:                Rx->m = NULL;
                   1507:                return 0;
                   1508:        }
                   1509:        bus_dmamap_sync(sc->tl_dmatag, Rx->m_dmamap, 0,
1.61      tsutsui  1510:            Rx->m_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
1.1       bouyer   1511:        /*
                   1512:         * Move the data pointer up so that the incoming data packet
                   1513:         * will be 32-bit aligned.
                   1514:         */
                   1515:        m->m_data += 2;
                   1516:
1.43      bouyer   1517:        Rx->hw_list->stat =
1.59      tsutsui  1518:            htole32(((Rx->m_dmamap->dm_segs[0].ds_len - 2) << 16) | 0x3000);
1.43      bouyer   1519:        Rx->hw_list->seg.data_count =
1.59      tsutsui  1520:            htole32(Rx->m_dmamap->dm_segs[0].ds_len - 2);
1.43      bouyer   1521:        Rx->hw_list->seg.data_addr =
                   1522:            htole32(Rx->m_dmamap->dm_segs[0].ds_addr + 2);
1.1       bouyer   1523:        return (m != oldm);
                   1524: }
                   1525:
                   1526: static void tl_ticks(v)
                   1527:        void *v;
                   1528: {
                   1529:        tl_softc_t *sc = v;
                   1530:
                   1531:        tl_read_stats(sc);
1.19      thorpej  1532:
                   1533:        /* Tick the MII. */
                   1534:        mii_tick(&sc->tl_mii);
                   1535:
1.17      bouyer   1536:        /* read statistics every seconds */
1.32      thorpej  1537:        callout_reset(&sc->tl_tick_ch, hz, tl_ticks, sc);
1.17      bouyer   1538: }
                   1539:
                   1540: static void
                   1541: tl_read_stats(sc)
                   1542:        tl_softc_t *sc;
                   1543: {
                   1544:        u_int32_t reg;
                   1545:        int ierr_overr;
                   1546:        int ierr_code;
                   1547:        int ierr_crc;
                   1548:        int oerr_underr;
1.63      wiz      1549:        int oerr_deferred;
1.17      bouyer   1550:        int oerr_coll;
                   1551:        int oerr_multicoll;
                   1552:        int oerr_exesscoll;
                   1553:        int oerr_latecoll;
                   1554:        int oerr_carrloss;
                   1555:        struct ifnet *ifp = &sc->tl_if;
                   1556:
                   1557:        reg =  tl_intreg_read(sc, TL_INT_STATS_TX);
                   1558:        ifp->if_opackets += reg & 0x00ffffff;
                   1559:        oerr_underr = reg >> 24;
                   1560:
                   1561:        reg =  tl_intreg_read(sc, TL_INT_STATS_RX);
                   1562:        ifp->if_ipackets += reg & 0x00ffffff;
                   1563:        ierr_overr = reg >> 24;
                   1564:
                   1565:        reg =  tl_intreg_read(sc, TL_INT_STATS_FERR);
                   1566:        ierr_crc = (reg & TL_FERR_CRC) >> 16;
                   1567:        ierr_code = (reg & TL_FERR_CODE) >> 24;
1.63      wiz      1568:        oerr_deferred = (reg & TL_FERR_DEF);
1.17      bouyer   1569:
                   1570:        reg =  tl_intreg_read(sc, TL_INT_STATS_COLL);
                   1571:        oerr_multicoll = (reg & TL_COL_MULTI);
                   1572:        oerr_coll = (reg & TL_COL_SINGLE) >> 16;
                   1573:
                   1574:        reg =  tl_intreg_read(sc, TL_INT_LERR);
                   1575:        oerr_exesscoll = (reg & TL_LERR_ECOLL);
                   1576:        oerr_latecoll = (reg & TL_LERR_LCOLL) >> 8;
                   1577:        oerr_carrloss = (reg & TL_LERR_CL) >> 16;
                   1578:
                   1579:
                   1580:        ifp->if_oerrors += oerr_underr + oerr_exesscoll + oerr_latecoll +
                   1581:           oerr_carrloss;
                   1582:        ifp->if_collisions += oerr_coll + oerr_multicoll;
                   1583:        ifp->if_ierrors += ierr_overr + ierr_code + ierr_crc;
                   1584:
                   1585:        if (ierr_overr)
                   1586:                printf("%s: receiver ring buffer overrun\n",
                   1587:                    sc->sc_dev.dv_xname);
                   1588:        if (oerr_underr)
                   1589:                printf("%s: transmit buffer underrun\n",
                   1590:                    sc->sc_dev.dv_xname);
                   1591: #ifdef TL_PRIV_STATS
                   1592:        sc->ierr_overr          += ierr_overr;
                   1593:        sc->ierr_code           += ierr_code;
                   1594:        sc->ierr_crc            += ierr_crc;
                   1595:        sc->oerr_underr         += oerr_underr;
1.63      wiz      1596:        sc->oerr_deferred       += oerr_deferred;
1.17      bouyer   1597:        sc->oerr_coll           += oerr_coll;
                   1598:        sc->oerr_multicoll      += oerr_multicoll;
                   1599:        sc->oerr_exesscoll      += oerr_exesscoll;
                   1600:        sc->oerr_latecoll       += oerr_latecoll;
                   1601:        sc->oerr_carrloss       += oerr_carrloss;
                   1602: #endif
                   1603: }
1.1       bouyer   1604:
1.17      bouyer   1605: static void tl_addr_filter(sc)
                   1606:        tl_softc_t *sc;
                   1607: {
                   1608:        struct ether_multistep step;
                   1609:        struct ether_multi *enm;
                   1610:        u_int32_t hash[2] = {0, 0};
                   1611:        int i;
1.1       bouyer   1612:
1.17      bouyer   1613:        sc->tl_if.if_flags &= ~IFF_ALLMULTI;
                   1614:        ETHER_FIRST_MULTI(step, &sc->tl_ec, enm);
                   1615:        while (enm != NULL) {
                   1616: #ifdef TLDEBUG
                   1617:                printf("tl_addr_filter: addrs %s %s\n",
                   1618:                   ether_sprintf(enm->enm_addrlo),
                   1619:                   ether_sprintf(enm->enm_addrhi));
                   1620: #endif
                   1621:                if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
                   1622:                        i = tl_multicast_hash(enm->enm_addrlo);
                   1623:                        hash[i/32] |= 1 << (i%32);
                   1624:                } else {
                   1625:                        hash[0] = hash[1] = 0xffffffff;
                   1626:                        sc->tl_if.if_flags |= IFF_ALLMULTI;
                   1627:                        break;
1.1       bouyer   1628:                }
1.17      bouyer   1629:                ETHER_NEXT_MULTI(step, enm);
                   1630:        }
                   1631: #ifdef TLDEBUG
                   1632:        printf("tl_addr_filer: hash1 %x has2 %x\n", hash[0], hash[1]);
                   1633: #endif
                   1634:        tl_intreg_write(sc, TL_INT_HASH1, hash[0]);
                   1635:        tl_intreg_write(sc, TL_INT_HASH2, hash[1]);
                   1636: }
1.1       bouyer   1637:
1.17      bouyer   1638: static int tl_multicast_hash(a)
                   1639:        u_int8_t *a;
                   1640: {
                   1641:        int hash;
                   1642:
                   1643: #define DA(addr,bit) (addr[5 - (bit/8)] & (1 << bit%8))
                   1644: #define xor8(a,b,c,d,e,f,g,h) (((a != 0) + (b != 0) + (c != 0) + (d != 0) + (e != 0) + (f != 0) + (g != 0) + (h != 0)) & 1)
                   1645:
                   1646:        hash  = xor8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30),
                   1647:            DA(a,36), DA(a,42));
                   1648:        hash |= xor8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31),
                   1649:            DA(a,37), DA(a,43)) << 1;
                   1650:        hash |= xor8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32),
                   1651:            DA(a,38), DA(a,44)) << 2;
                   1652:        hash |= xor8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33),
                   1653:            DA(a,39), DA(a,45)) << 3;
                   1654:        hash |= xor8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34),
                   1655:            DA(a,40), DA(a,46)) << 4;
                   1656:        hash |= xor8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35),
                   1657:            DA(a,41), DA(a,47)) << 5;
1.1       bouyer   1658:
1.17      bouyer   1659:        return hash;
                   1660: }
1.1       bouyer   1661:
1.59      tsutsui  1662: #if defined(TLDEBUG_RX)
1.17      bouyer   1663: void
                   1664: ether_printheader(eh)
                   1665:        struct ether_header *eh;
                   1666: {
                   1667:        u_char *c = (char*)eh;
                   1668:        int i;
                   1669:        for (i=0; i<sizeof(struct ether_header); i++)
                   1670:                printf("%x ", (u_int)c[i]);
                   1671:                printf("\n");
                   1672: }
1.1       bouyer   1673: #endif

CVSweb <webmaster@jp.NetBSD.org>