root/usr/src/uts/common/io/elxl/elxl.h
/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Frank van der Linden.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


#ifndef ELXL_H
#define ELXL_H

/*
 * This file defines the registers specific to the EtherLink XL family
 * of NICs.
 */

#define REG_CMD_STAT            0x0e    /* Write command, read status */

#define CMD_GLOBAL_RESET        0x0000
#define CMD_SELECT_WINDOW       0x0800
#define CMD_BNC_ENABLE          0x1000  /* enable 10BASE2 DC-DC converter */
#define CMD_RX_DISABLE          0x1800
#define CMD_RX_ENABLE           0x2000
#define CMD_RX_RESET            0x2800
#define CMD_UP_STALL            0x3000
#define CMD_UP_UNSTALL          0x3001
#define CMD_DN_STALL            0x3002
#define CMD_DN_UNSTALL          0x3003
#define CMD_TX_ENABLE           0x4800
#define CMD_TX_DISABLE          0x5000
#define CMD_TX_RESET            0x5800
#define CMD_INT_REQ             0x6000
#define CMD_INT_ACK             0x6800
#define CMD_INT_ENABLE          0x7000
#define CMD_IND_ENABLE          0x7800
#define CMD_SET_FILTER          0x8000
#define CMD_SET_RXEARLY         0x8800
#define CMD_SET_TXSTART         0x9800
#define CMD_STATS_ENABLE        0xa800
#define CMD_STATS_DISABLE       0xb000
#define CMD_BNC_DISABLE         0xb800  /* disable 10BASE2 DC-DC converter */
#define CMD_SET_TXRECLAIM       0xc000
#define CMD_CLEAR_HASHBIT       0xc800
#define CMD_SET_HASHBIT         0xcc00

/*
 * Defines for the interrupt status register
 */
#define INT_LATCH               0x0001
#define INT_HOST_ERROR          0x0002
#define INT_TX_COMPLETE         0x0004
#define INT_RX_COMPLETE         0x0010
#define INT_RX_EARLY            0x0020
#define INT_REQUESTED           0x0040
#define INT_STATS               0x0080
#define INT_LINK                0x0100  /* NB: most NICs don't implement it! */
#define INT_DN_COMPLETE         0x0200
#define INT_UP_COMPLETE         0x0400
#define STAT_CMD_IN_PROGRESS    0x1000

#define INT_WATCHED                                                     \
        (INT_HOST_ERROR | INT_STATS | INT_DN_COMPLETE | INT_UP_COMPLETE)


/*
 * Flat address space registers (outside the windows)
 */

#define REG_TXPKTID             0x18    /* 90xB only */
#define REG_TIMER               0x1a
#define REG_TXSTATUS            0x1b
#define TXSTATUS_RECLAIM_ERR    0x02
#define TXSTATUS_STATUS_OFLOW   0x04    /* bad news! */
#define TXSTATUS_MAXCOLLISIONS  0x08
#define TXSTATUS_UNDERRUN       0x10
#define TXSTATUS_JABBER         0x20
#define TXSTATUS_INT_REQ        0x40
#define TXSTATUS_COMPLETE       0x80
#define TXSTATUS_ERRS           0x32

#define REG_INTSTATUSAUTO       0x1e
#define REG_DMACTRL             0x20
#define DMACTRL_DNCMPLREQ       0x00000002
#define DMACTRL_DNSTALLED       0x00000004
#define DMACTRL_UPCOMPLETE      0x00000008
#define DMACTRL_DNCOMPLETE      0x00000010
#define DMACTRL_UPRXEAREN       0x00000020
#define DMACTRL_ARNCNTDN        0x00000040
#define DMACTRL_DNINPROG        0x00000080
#define DMACTRL_CNTSPEED        0x00000100
#define DMACTRL_CNTDNMODE       0x00000200
#define DMACTRL_ALTSEQDIS       0x00010000
#define DMACTRL_DEFEATMWI       0x00100000
#define DMACTRL_DEFEATMRL       0x00200000
#define DMACTRL_UPOVERDIS       0x00400000
#define DMACTRL_TARGABORT       0x40000000
#define DMACTRL_MSTRABORT       0x80000000
#define REG_DNLISTPTR           0x24
#define REG_DNBURSTTHRESH       0x2a    /* 90xB only */
#define REG_DNPRIOTHRESH        0x2c    /* 90xB only */
#define REG_DNPOLL              0x2d    /* 90xB only */
#define REG_TXFREETHRESH        0x2f    /* 90x only */
#define REG_UPPKTSTATUS         0x30
#define REG_FREETIMER           0x34
#define REG_COUNTDOWN           0x36
#define REG_UPLISTPTR           0x38
#define REG_UPPRIOTHRESH        0x3c    /* 90xB only */
#define REG_UPPOLL              0x3d    /* 90xB only */
#define REG_UPBURSTTHRESH       0x3e    /* 90xB only */
#define REG_REALTIMECNT         0x40    /* 90xB only */
#define REG_DNMAXBURST          0x78    /* 90xB only */
#define REG_UPMAXBURST          0x7a    /* 90xB only */

/*
 * Window 0.  Eeprom access.
 */
#define W0_MFG_ID               0x00
#define W0_EE_CMD               0x0a
#define EE_CMD_ADDR             0x001f
#define EE_CMD_WRITE_EN         0x0000
#define EE_CMD_READ             0x0080
#define EE_CMD_READ8            0x0200
#define EE_CMD_BUSY             0x8000
#define W0_EE_DATA              0x0c
/*
 * Window 2.
 */
#define W2_STATION_ADDRESS      0x00
#define W2_STATION_MASK         0x06
#define W2_RESET_OPTIONS        0x0c            /* Reset options (90xB only) */
#define W2_RESET_OPT_LEDPOLAR   0x0010  /* invert LED polarity */
#define W2_RESET_OPT_PHYPOWER   0x4000  /* turn on PHY power */


/*
 * Window 3.
 */
#define W3_INTERNAL_CONFIG      0x00    /* 32 bits */
#define W3_MAX_PKT_SIZE         0x04    /* 90xB only */
#define W3_MAC_CONTROL          0x06
#define MAC_CONTROL_FDX         0x0020
#define MAC_CONTROL_ALLOW_LARGE 0x0040
#define MAC_CONTROL_FLOW_EN     0x0100  /* 90xB only */
#define MAC_CONTROL_VLT_EN      0x0200  /* 90xB only */

/*
 * This is reset options for the other cards, media options for
 * the 90xB NICs. Reset options are in a separate register for
 * the 90xB.
 *
 * Note that these bit values are also the same as the
 * W3_RESET_OPTIONS media selection bits on 90x NICs, which
 * conviently occupies the same register, and pretty much is
 * the same thing.  There are some differences in the upper bits,
 * but we don't care about those.
 */
#define W3_MEDIAOPT             0x08
#define MEDIAOPT_100T4          0x0001
#define MEDIAOPT_100TX          0x0002
#define MEDIAOPT_100FX          0x0004
#define MEDIAOPT_10T            0x0008
#define MEDIAOPT_BNC            0x0010
#define MEDIAOPT_AUI            0x0020
#define MEDIAOPT_MII            0x0040
#define MEDIAOPT_10FL           0x0080
#define MEDIAOPT_MASK           0x00ff  /* excludes 10BASEFL */

/*
 * Window 4 registers.
 */
#define W4_MEDIASTAT            0xa
#define MEDIASTAT_SQE_EN        0x0008
#define MEDIASTAT_JABGUARD_EN   0x0040
#define MEDIASTAT_LINKBEAT_EN   0x0080
#define MEDIASTAT_LINKDETECT    0x0800
#define MEDIASTAT_AUI_DIS       0x8000

/*
 * Window 4, offset 8 is defined for MII/PHY access for EtherLink XL
 * cards.
 */
#define W4_PHYSMGMT             0x08
#define PHYSMGMT_CLK            0x0001
#define PHYSMGMT_DATA           0x0002
#define PHYSMGMT_DIR            0x0004

/*
 * Counter in window 4 for packets with a bad start-of-stream delimiter/
 */
#define W4_BADSSD               0x0c

/*
 * Upper bits of 20-bit byte counters.
 */
#define W4_UBYTESOK             0x0d

/*
 * W6 registers, used for statistics
 */
#define W6_TX_BYTES             0x0c
#define W6_RX_BYTES             0x0a
#define W6_UPPER_FRAMES         0x09
#define W6_DEFER                0x08
#define W6_RX_FRAMES            0x07
#define W6_TX_FRAMES            0x06
#define W6_RX_OVERRUNS          0x05
#define W6_TX_LATE_COL          0x04
#define W6_SINGLE_COL           0x03
#define W6_MULT_COL             0x02
#define W6_SQE_ERRORS           0x01
#define W6_NO_CARRIER           0x00

/*
 * Receive filter bits for use with CMD_SET_FILTER.
 */
#define FILTER_UNICAST          0x01
#define FILTER_ALLMULTI         0x02
#define FILTER_ALLBCAST         0x04
#define FILTER_PROMISC          0x08
#define FILTER_MULTIHASH        0x10    /* only on 90xB */

/*
 * Window 7 registers. These are different for 90x and 90xB than
 * for the EtherLink III / Fast EtherLink cards.
 */

#define W7_VLANMASK     0x00    /* 90xB only */
#define W7_VLANTYPE     0x04    /* 90xB only */
#define W7_TIMER        0x0a    /* 90x only */
#define W7_TX_STATUS    0x0b    /* 90x only */
#define W7_POWEREVENT   0x0c    /* 90xB only */
#define W7_INTSTATUS    0x0e

/*
 * The Internal Config register is different on 90xB cards. The
 * different masks / shifts are defined here.
 */

/*
 * Lower 16 bits.
 */
#define CONFIG_TXLARGE          0x4000
#define CONFIG_TXLARGE_SHIFT    14

#define CONFIG_RXLARGE          0x8000
#define CONFIG_RXLARGE_SHIFT    15

/*
 * Upper 16 bits.
 */
#define XCVR_SEL_10T            0x00000000U
#define XCVR_SEL_AUI            0x00100000U
#define XCVR_SEL_BNC            0x00300000U
#define XCVR_SEL_100TX          0x00400000U     /* 3com says don't use this! */
#define XCVR_SEL_100FX          0x00500000U
#define XCVR_SEL_MII            0x00600000U
#define XCVR_SEL_AUTO           0x00800000U
#define XCVR_SEL_MASK           0x00f00000U

#define RAM_PARTITION_5_3       0x00000000U
#define RAM_PARTITION_3_1       0x00010000U
#define RAM_PARTITION_1_1       0x00020000U
#define RAM_PARTITION_3_5       0x00030000U
#define RAM_PARTITION_MASK      0x00030000U

#define CONFIG_AUTOSEL          0x0100
#define CONFIG_AUTOSEL_SHIFT    8

#define CONFIG_DISABLEROM       0x0200
#define CONFIG_DISABLEROM_SHIFT 9

/*
 * ID of internal PHY.
 */

#define INTPHY_ID               24

/*
 * Fragment header as laid out in memory for DMA access.
 */

#define EX_FR_LENMASK   0x00001fff      /* mask for length in fr_len field */
#define EX_FR_LAST      0x80000000      /* indicates last fragment */

/*
 * 3Com NICs have separate structures for packet upload (receive) and
 * download (transmit) descriptors.  However, the structures for the
 * "legacy" transmit format are nearly identical except for the fact
 * that the third field is named differently and the bit fields are
 * different.  To maximize code reuse, we use a single type to cover
 * both uses.  Note that for receive we can arrange these in a loop,
 * but not for transmit.  Note also that for simplicity, we only use
 * the "type 0" legacy DPD format -- the features offered by the newer
 * type 1 format are not something we need.
 */
typedef struct ex_pd {
        uint32_t        pd_link;
        uint32_t        pd_shared;
        uint32_t        pd_addr;
        uint32_t        pd_len;
} ex_pd_t;
#define pd_fsh          pd_shared
#define pd_status       pd_shared

/*
 * Type 0 Download Packet Descriptor (DPD).  We don't use the other
 * type, since it isn't supported by older 90x ASICs.
 */
struct ex_dpd {
        uint32_t dpd_nextptr;           /* prt to next fragheader */
        uint32_t dpd_fsh;               /* frame start header */
        uint32_t dpd_addr;
        uint32_t dpd_len;
};

struct ex_upd {
        uint32_t upd_nextptr;
        uint32_t upd_pktstatus;
        uint32_t upd_addr;      /* phys addr of frag */
        uint32_t upd_len;       /* length of frag */
};

#define DPD_DMADDR(s, t) \
        ((s)->sc_dpddma + ((char *)((t)->tx_dpd) - (char *)((s)->sc_dpd)))

/*
 * Frame Start Header bitfields.
 */

#define EX_DPD_DNIND    0x80000000      /* intr on download done */
#define EX_DPD_TXIND    0x00008000      /* intr on tx done */
#define EX_DPD_NOCRC    0x00002000      /* no CRC append */

/*
 * Lower 12 bits are the tx length for the 90x family. The 90xB
 * assumes that the tx length is the sum of all frame lengths,
 * and uses the bits as below. It also defines some more bits in
 * the upper part.
 */
#define EX_DPD_EMPTY    0x20000000      /* no data in this DPD */
#define EX_DPD_UPDEFEAT 0x10000000      /* don't round tx lengths up */
#define EX_DPD_UDPCKSUM 0x08000000      /* do hardware UDP checksum */
#define EX_DPD_TCPCKSUM 0x04000000      /* do hardware TCP checksum */
#define EX_DPD_IPCKSUM  0x02000000      /* do hardware IP checksum */
#define EX_DPD_DNCMPLT  0x01000000      /* packet has been downloaded */
#define EX_DPD_IDMASK   0x000003fc      /* mask for packet id */
#define EX_DPD_IDSHIFT  2
#define EX_DPD_RNDMASK  0x00000003      /* mask for rounding */
                                        /* 0 -> dword, 2 -> word, 1,3 -> none */
/*
 * upd_pktstatus bitfields.
 * The *CKSUMERR fields are only valid if the matching *CHECKED field
 * is set.
 */
#define EX_UPD_PKTLENMASK       0x00001fff      /* 12:0 -> packet length */
#define EX_UPD_ERROR            0x00004000      /* rcv error */
#define EX_UPD_COMPLETE         0x00008000      /* rcv complete */
#define EX_UPD_OVERRUN          0x00010000      /* rcv overrun */
#define EX_UPD_RUNT             0x00020000      /* pkt < 60 bytes */
#define EX_UPD_ALIGNERR         0x00040000      /* alignment error */
#define EX_UPD_CRCERR           0x00080000      /* CRC error */
#define EX_UPD_OVERSIZED        0x00100000      /* oversize frame */
#define EX_UPD_DRIBBLEBITS      0x00800000      /* pkt had dribble bits */
#define EX_UPD_OVERFLOW         0x01000000      /* insufficient space for pkt */
#define EX_UPD_IPCKSUMERR       0x02000000      /* IP cksum error (90xB) */
#define EX_UPD_TCPCKSUMERR      0x04000000      /* TCP cksum error (90xB) */
#define EX_UPD_UDPCKSUMERR      0x08000000      /* UDP cksum error (90xB) */
#define EX_UPD_IPCHECKED        0x20000000      /* IP cksum done */
#define EX_UPD_TCPCHECKED       0x40000000      /* TCP cksum done */
#define EX_UPD_UDPCHECKED       0x80000000      /* UDP cksum done */

#define EX_UPD_ERR              0x001f4000      /* Errors we check for */
#define EX_UPD_ERR_VLAN         0x000f0000      /* same for 802.1q */

#define EX_UPD_CKSUMERR         0x0e000000      /* any IP checksum error */

/*
 * EEPROM offsets.  These are 16-bit word addresses.  There are a lot of
 * other things in here, but we only care about the OEM address.
 */
#define EE_3COM_ADDR_0          0x00
#define EE_3COM_ADDR_1          0x01
#define EE_3COM_ADDR_2          0x02
#define EE_OEM_ADDR_0           0x0a
#define EE_OEM_ADDR_1           0x0b
#define EE_OEM_ADDR_2           0x0c
#define EE_CAPABILITIES         0x10

#define EX_NTX          256
#define EX_NRX          128
#define EX_BUFSZ        1536

typedef struct ex_desc {
        struct ex_desc          *ed_next;
        struct ex_desc          *ed_prev;
        ddi_dma_handle_t        ed_dmah;
        ddi_acc_handle_t        ed_acch;
        caddr_t                 ed_buf;
        uint32_t                ed_bufaddr;
        uint32_t                ed_descaddr;
        uint32_t                ed_off;         /* offset of pd */
        ex_pd_t                 *ed_pd;
} ex_desc_t;

typedef struct ex_ring {
        int                     r_count;
        int                     r_avail;
        ddi_dma_handle_t        r_dmah;
        ddi_acc_handle_t        r_acch;
        uint32_t                r_paddr;
        ex_pd_t                 *r_pd;
        ex_desc_t               *r_desc;
        ex_desc_t               *r_head;
        ex_desc_t               *r_tail;
} ex_ring_t;

/*
 * Higher level linked list of upload packet descriptors.
 */
struct ex_rxdesc {
        ddi_dma_handle_t        rx_dmah;
        ddi_acc_handle_t        rx_acch;
        caddr_t                 rx_buf;
        uint32_t                rx_paddr;
        struct ex_upd           *rx_upd;
};

/*
 * Ethernet software status per interface.
 */
typedef struct ex_softc {
        dev_info_t              *ex_dip;
        mac_handle_t            ex_mach;
        mii_handle_t            ex_miih;
        ddi_periodic_t          ex_linkcheck;

        ddi_acc_handle_t        ex_pcih;
        ddi_acc_handle_t        ex_regsh;
        caddr_t                 ex_regsva;

        kmutex_t                ex_txlock;
        kmutex_t                ex_intrlock;

        ddi_intr_handle_t       ex_intrh;

        uint8_t                 ex_curraddr[6];
        uint8_t                 ex_factaddr[6];
        boolean_t               ex_promisc;
        unsigned                ex_mccount;

        boolean_t               ex_running;
        boolean_t               ex_suspended;

        ex_ring_t               ex_rxring;
        ex_ring_t               ex_txring;

        uint32_t                ex_xcvr;
        uint32_t                ex_speed;
        link_duplex_t           ex_duplex;
        boolean_t               ex_fdx;
        link_state_t            ex_link;
        boolean_t               ex_mii_active;
        uint32_t                ex_mediaopt;
        char                    ex_medias[128];
        uint16_t                ex_capab;

        /*
         * Kstats.
         */
        uint64_t                ex_ipackets;
        uint64_t                ex_opackets;
        uint64_t                ex_ibytes;
        uint64_t                ex_obytes;
        uint64_t                ex_brdcstrcv;
        uint64_t                ex_multircv;
        uint64_t                ex_brdcstxmt;
        uint64_t                ex_multixmt;
        unsigned                ex_toolong;
        unsigned                ex_runt;
        unsigned                ex_oflo;
        unsigned                ex_fcs;
        unsigned                ex_align;
        unsigned                ex_allocbfail;
        unsigned                ex_txerr;
        unsigned                ex_uflo;
        unsigned                ex_jabber;
        unsigned                ex_excoll;
        unsigned                ex_sqe;
        unsigned                ex_nocarrier;
        unsigned                ex_multcol;
        unsigned                ex_defer;
        unsigned                ex_latecol;
        unsigned                ex_singlecol;

        uint_t                  ex_conf;        /* config flags */

#define CONF_INTPHY             0x0001  /* has internal PHY at address 24 */
#define CONF_90XB               0x0002  /* is 90xB */

} elxl_t;

#define WAIT_CMD(sc) \
        { \
                int stat; \
                do { \
                        stat = GET16(REG_CMD_STAT); \
                } while ((stat & STAT_CMD_IN_PROGRESS) && (stat != 0xffff)); \
        }

#define GET8(off)       \
        ddi_get8(sc->ex_regsh, (void *)(sc->ex_regsva + (off)))
#define GET16(off)      \
        ddi_get16(sc->ex_regsh, (void *)(sc->ex_regsva + (off)))
#define GET32(off)      \
        ddi_get32(sc->ex_regsh, (void *)(sc->ex_regsva + (off)))
#define PUT8(off, val)  \
        ddi_put8(sc->ex_regsh, (void *)(sc->ex_regsva + (off)), val)
#define PUT16(off, val) \
        ddi_put16(sc->ex_regsh, (void *)(sc->ex_regsva + (off)), val)
#define PUT32(off, val) \
        ddi_put32(sc->ex_regsh, (void *)(sc->ex_regsva + (off)), val)

#define SET16(off, val) PUT16(off, GET16(off) | val)
#define CLR16(off, val) PUT16(off, GET16(off) & ~(val))

#define PUT_CMD(x)      PUT16(REG_CMD_STAT, (x))
#define SET_WIN(x)      PUT16(REG_CMD_STAT, CMD_SELECT_WINDOW | (x))

#define PUT_PD(ring, member, val)       ddi_put32(ring->r_acch, &member, (val))
#define GET_PD(ring, member)            ddi_get32(ring->r_acch, &member)

#endif  /* ELXL_H */