root/usr/src/uts/common/io/usbgem/usbgem.h
/*
 * usbgem.h: General USB to Ethernet MAC driver framework
 * @(#)usbgem.h 1.4 12/02/09
 * (C) Copyright 2003-2009 Masayuki Murayama KHF04453@nifty.ne.jp
 */

#ifndef __USBGEM_H__
#define __USBGEM_H__

#include <sys/mac.h>
#ifndef MAC_VERSION
#include <sys/mac_provider.h>
#endif
#include <sys/mac_ether.h>

/*
 * Useful macros and typedefs
 */
#define USBGEM_NAME_LEN 32

#define USBGEM_TX_TIMEOUT               (drv_usectohz(3*1000000))
#define USBGEM_TX_TIMEOUT_INTERVAL      (drv_usectohz(1*1000000))
#define USBGEM_LINK_WATCH_INTERVAL      (drv_usectohz(1*1000000))

/* general return code */
#define USBGEM_SUCCESS  0
#define USBGEM_FAILURE  1

/* return code of usbgem_tx_done */
#define INTR_RESTART_TX 0x80000000U

struct usbgem_stats {
        uint32_t        intr;

        uint32_t        crc;
        uint32_t        errrcv;
        uint32_t        overflow;
        uint32_t        frame;
        uint32_t        missed;
        uint32_t        runt;
        uint32_t        frame_too_long;
        uint32_t        norcvbuf;
        uint32_t        sqe;

        uint32_t        collisions;
        uint32_t        first_coll;
        uint32_t        multi_coll;
        uint32_t        excoll;
        uint32_t        xmit_internal_err;
        uint32_t        nocarrier;
        uint32_t        defer;
        uint32_t        errxmt;
        uint32_t        underflow;
        uint32_t        xmtlatecoll;
        uint32_t        noxmtbuf;
        uint32_t        jabber;


        uint64_t        rbytes;
        uint64_t        obytes;
        uint64_t        rpackets;
        uint64_t        opackets;
        uint32_t        rbcast;
        uint32_t        obcast;
        uint32_t        rmcast;
        uint32_t        omcast;
        uint32_t        rcv_internal_err;
};

struct mcast_addr {
        struct ether_addr       addr;
        uint32_t                hash;
};

#define USBGEM_MAXMC    64
#define USBGEM_MCALLOC  (sizeof (struct mcast_addr) * USBGEM_MAXMC)

#define SLOT(dp, n)     ((n) % (dp)->ugc.usbgc_tx_list_max)

/*
 * mac soft state
 */
struct usbgem_dev {
        dev_info_t      *dip;
        mac_handle_t    mh;
        char            name[USBGEM_NAME_LEN];

        /* pointer to usb private data */
        usb_client_dev_data_t   *reg_data;

        /* usb handles */
        usb_pipe_handle_t       default_pipe;
        usb_pipe_handle_t       bulkin_pipe;
        usb_pipe_handle_t       bulkout_pipe;
        usb_pipe_handle_t       intr_pipe;

        /* usb endpoints */
        usb_ep_descr_t          *ep_default;
        usb_ep_descr_t          *ep_bulkin;
        usb_ep_descr_t          *ep_bulkout;
        usb_ep_descr_t          *ep_intr;

        /* usb policies */
        usb_pipe_policy_t       policy_default;
        usb_pipe_policy_t       policy_bulkin;
        usb_pipe_policy_t       policy_bulkout;
        usb_pipe_policy_t       policy_interrupt;

        /* MAC address information */
        struct ether_addr       cur_addr;
        struct ether_addr       dev_addr;

        /* RX state and resource management */
        kmutex_t                rxlock;
        int                     rx_busy_cnt;
        boolean_t               rx_active;
        kcondvar_t              rx_drain_cv;

        /* RX buffer management */
        int                     rx_buf_len;

        /* TX state and resource management */
        kmutex_t                txlock;
        int                     tx_busy_cnt;
        usb_bulk_req_t          *tx_free_list;
        kcondvar_t              tx_drain_cv;
        clock_t                 tx_start_time;
        int                     bulkout_timeout;        /* in second */
        int                     tx_max_packets;
        int                     tx_seq_num;
        int                     tx_intr_pended;

        /* NIC state from OS view */
        int                     nic_state;
#define NIC_STATE_UNKNOWN       0
#define NIC_STATE_STOPPED       1
#define NIC_STATE_INITIALIZED   2
#define NIC_STATE_ONLINE        3

        /* MAC state from hardware view */
        int                     mac_state;
#define MAC_STATE_DISCONNECTED  0       /* it includes suspended state too */
#define MAC_STATE_STOPPED       1       /* powered up / buf not initialized */
#define MAC_STATE_INITIALIZED   2       /* initialized */
#define MAC_STATE_ONLINE        3       /* working correctly  */
#define MAC_STATE_ERROR         4       /* need to restart nic */

        clock_t                 fatal_error;

        /* robustness: timer and watchdog */
        uint_t                  tx_watcher_stop;
        kt_did_t                tx_watcher_did;
        kcondvar_t              tx_watcher_cv;
        kmutex_t                tx_watcher_lock;
        clock_t                 tx_watcher_timeout;
        clock_t                 tx_watcher_interval;

        /* MII mamagement */
        boolean_t               anadv_autoneg:1;
        boolean_t               anadv_1000fdx:1;
        boolean_t               anadv_1000hdx:1;
        boolean_t               anadv_100t4:1;
        boolean_t               anadv_100fdx:1;
        boolean_t               anadv_100hdx:1;
        boolean_t               anadv_10fdx:1;
        boolean_t               anadv_10hdx:1;
        boolean_t               anadv_1000t_ms:2;
        boolean_t               anadv_pause:1;
        boolean_t               anadv_asmpause:1;
        boolean_t               mii_advert_ro:1;

        boolean_t               full_duplex:1;
        int                     speed:3;
#define         USBGEM_SPD_10   0
#define         USBGEM_SPD_100  1
#define         USBGEM_SPD_1000 2
#define         USBGEM_SPD_NUM  3
        unsigned int            flow_control:2;
#define         FLOW_CONTROL_NONE       0
#define         FLOW_CONTROL_SYMMETRIC  1
#define         FLOW_CONTROL_TX_PAUSE   2
#define         FLOW_CONTROL_RX_PAUSE   3

        boolean_t               mii_supress_msg:1;

        uint32_t                mii_phy_id;
        uint16_t                mii_status;
        uint16_t                mii_advert;
        uint16_t                mii_lpable;
        uint16_t                mii_exp;
        uint16_t                mii_ctl1000;
        uint16_t                mii_stat1000;
        uint16_t                mii_xstatus;
        int8_t                  mii_phy_addr;   /* must be signed */

        uint16_t                mii_status_ro;
        uint16_t                mii_xstatus_ro;

        int                     mii_state;
#define         MII_STATE_UNKNOWN               0
#define         MII_STATE_RESETTING             1
#define         MII_STATE_AUTONEGOTIATING       2
#define         MII_STATE_AN_DONE               3
#define         MII_STATE_MEDIA_SETUP           4
#define         MII_STATE_LINKUP                5
#define         MII_STATE_LINKDOWN              6

        clock_t                 mii_last_check; /* in tick */
        clock_t                 mii_timer;      /* in tick */
#define         MII_RESET_TIMEOUT       drv_usectohz(1000*1000)
#define         MII_AN_TIMEOUT          drv_usectohz(5000*1000)
#define         MII_LINKDOWN_TIMEOUT    drv_usectohz(10000*1000)

        clock_t                 mii_interval;   /* in tick */
        clock_t                 linkup_delay;   /* in tick */

        uint_t                  link_watcher_stop;
        kt_did_t                link_watcher_did;
        kcondvar_t              link_watcher_wait_cv;
        kmutex_t                link_watcher_lock;

        krwlock_t               dev_state_lock; /* mac_state and nic_state */
        ksema_t                 hal_op_lock;    /* serialize hw operations */
        ksema_t                 drv_op_lock;    /* hotplug op lock */

        /* multcast list */
        ksema_t                 rxfilter_lock;
        int                     mc_count;
        int                     mc_count_req;
        struct mcast_addr       *mc_list;
        int                     rxmode;
#define         RXMODE_PROMISC          0x01
#define         RXMODE_ALLMULTI_REQ     0x02
#define         RXMODE_MULTI_OVF        0x04
#define         RXMODE_ENABLE           0x08
#define         RXMODE_ALLMULTI         (RXMODE_ALLMULTI_REQ | RXMODE_MULTI_OVF)
#define         RXMODE_BITS     \
                        "\020"  \
                        "\004ENABLE"    \
                        "\003MULTI_OVF" \
                        "\002ALLMULTI_REQ"      \
                        "\001PROMISC"

        /* statistcs */
        struct usbgem_stats             stats;

        /* pointer to local structure */
        void                    *private;
        int                     priv_size;

        /* configuration */
        struct usbgem_conf {
                /* name */
                char            usbgc_name[USBGEM_NAME_LEN];
                int             usbgc_ppa;

                /* specification on usb */
                int     usbgc_ifnum;    /* interface number */
                int     usbgc_alt;      /* alternate */

                /* specification on tx engine */
                int             usbgc_tx_list_max;

                /* specification on rx engine */
                int             usbgc_rx_header_len;
                int             usbgc_rx_list_max;

                /* time out parameters */
                clock_t         usbgc_tx_timeout;
                clock_t         usbgc_tx_timeout_interval;

                /* flow control */
                int             usbgc_flow_control;

                /* MII timeout parameters */
                clock_t usbgc_mii_linkdown_timeout;
                clock_t usbgc_mii_link_watch_interval;
                clock_t usbgc_mii_reset_timeout;

                clock_t usbgc_mii_an_watch_interval;
                clock_t usbgc_mii_an_timeout;
                clock_t usbgc_mii_an_wait;
                clock_t usbgc_mii_an_delay;

                /* MII configuration */
                int     usbgc_mii_addr_min;
                int     usbgc_mii_linkdown_action;
                int     usbgc_mii_linkdown_timeout_action;
#define         MII_ACTION_NONE         0
#define         MII_ACTION_RESET        1
#define         MII_ACTION_RSA          2
                boolean_t       usbgc_mii_dont_reset:1;
                boolean_t       usbgc_mii_an_oneshot:1;
                boolean_t       usbgc_mii_hw_link_detection:1;
                boolean_t       usbgc_mii_stop_mac_on_linkdown:1;
                uint16_t        usbgc_mii_an_cmd;

                /* I/O methods */

                /* mac operation */
                int     (*usbgc_attach_chip)(struct usbgem_dev *dp);
                int     (*usbgc_reset_chip)(struct usbgem_dev *dp);
                int     (*usbgc_init_chip)(struct usbgem_dev *dp);
                int     (*usbgc_start_chip)(struct usbgem_dev *dp);
                int     (*usbgc_stop_chip)(struct usbgem_dev *dp);
                uint32_t (*usbgc_multicast_hash)(struct usbgem_dev *dp,
                    const uint8_t *);
                int     (*usbgc_set_rx_filter)(struct usbgem_dev *dp);
                int     (*usbgc_set_media)(struct usbgem_dev *dp);
                int     (*usbgc_get_stats)(struct usbgem_dev *dp);
                void    (*usbgc_interrupt)(struct usbgem_dev *dp, mblk_t *mp);

                /* packet manipulation */
                mblk_t  *(*usbgc_tx_make_packet)(struct usbgem_dev *dp,
                    mblk_t *mp);
                mblk_t  *(*usbgc_rx_make_packet)(struct usbgem_dev *dp,
                    mblk_t *mp);
                /* mii operations */
                int     (*usbgc_mii_probe)(struct usbgem_dev *dp);
                int     (*usbgc_mii_init)(struct usbgem_dev *dp);
                int     (*usbgc_mii_config)(struct usbgem_dev *dp, int *errp);
                uint16_t (*usbgc_mii_read)(struct usbgem_dev *dp, uint_t reg,
                    int *errp);
                void    (*usbgc_mii_write)(struct usbgem_dev *dp, uint_t reg,
                    uint16_t val, int *errp);

                /* jumbo frame */
                int     usbgc_max_mtu;
                int     usbgc_default_mtu;
                int     usbgc_min_mtu;
        } ugc;

        int     misc_flag;
#define USBGEM_VLAN     0x0001
        timeout_id_t    intr_watcher_id;

        /* buffer size */
        uint_t  mtu;

        /* performance tuning parameters */
        uint_t  txthr;          /* tx fifo threshoold */
        uint_t  txmaxdma;       /* tx max dma burst size */
        uint_t  rxthr;          /* rx fifo threshoold */
        uint_t  rxmaxdma;       /* tx max dma burst size */

        /* kstat stuff */
        kstat_t *ksp;

        /* ndd stuff */
        caddr_t nd_data_p;
        caddr_t nd_arg_p;

#ifdef USBGEM_DEBUG_LEVEL
        int     tx_cnt;
#endif
};

/*
 * Exported functions
 */
int usbgem_ctrl_out(struct usbgem_dev *dp,
    uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
    void *bp, int size);

int usbgem_ctrl_in(struct usbgem_dev *dp,
    uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
    void *bp, int size);

int usbgem_ctrl_out_val(struct usbgem_dev *dp,
    uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
    uint32_t v);

int usbgem_ctrl_in_val(struct usbgem_dev *dp,
    uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
    void *valp);

void usbgem_generate_macaddr(struct usbgem_dev *, uint8_t *);
boolean_t usbgem_get_mac_addr_conf(struct usbgem_dev *);
int usbgem_mii_probe_default(struct usbgem_dev *);
int usbgem_mii_init_default(struct usbgem_dev *);
int usbgem_mii_config_default(struct usbgem_dev *, int *errp);
void usbgem_mii_update_link(struct usbgem_dev *);
void usbgem_restart_tx(struct usbgem_dev *);
boolean_t usbgem_tx_done(struct usbgem_dev *, int);
void usbgem_receive(struct usbgem_dev *);
struct usbgem_dev *usbgem_do_attach(dev_info_t *,
    struct usbgem_conf *, void *, int);
int usbgem_do_detach(dev_info_t *);

uint32_t usbgem_ether_crc_le(const uint8_t *addr);
uint32_t usbgem_ether_crc_be(const uint8_t *addr);

int usbgem_resume(dev_info_t *);
int usbgem_suspend(dev_info_t *);
int usbgem_quiesce(dev_info_t *);

#define USBGEM_STREAM_OPS(dev_ops, attach, detach) \
    DDI_DEFINE_STREAM_OPS(dev_ops, nulldev, nulldev, attach, detach, \
    nodev, NULL, D_MP, NULL, usbgem_quiesce)

int usbgem_mod_init(struct dev_ops *, char *);
void usbgem_mod_fini(struct dev_ops *);

#define USBGEM_GET_DEV(dip) \
        ((struct usbgem_dev *)(ddi_get_driver_private(dip)))

#endif /* __USBGEM_H__ */