sfe_util.h revision da14cebe459d3275048785f25bd869cb09b5307f
/*
* sfe_util.h: header to support the gem layer used by Masa Murayama
*
* Copyright (c) 2002-2008 Masayuki Murayama. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SFE_UTIL_H_
#define _SFE_UTIL_H_
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
/*
* Useful macros and typedefs
*/
#define GEM_NAME_LEN 32
#define GEM_TX_TIMEOUT (drv_usectohz(5*1000000))
#define GEM_TX_TIMEOUT_INTERVAL (drv_usectohz(1*1000000))
#define GEM_LINK_WATCH_INTERVAL (drv_usectohz(1*1000000)) /* 1 sec */
/* general return code */
#define GEM_SUCCESS 0
#define GEM_FAILURE (-1)
/* return code of gem_tx_done */
#define INTR_RESTART_TX 0x80000000
typedef int32_t seqnum_t;
/*
* I/O instructions
*/
#define OUTB(dp, p, v) \
ddi_put8((dp)->regs_handle, \
(void *)((caddr_t)((dp)->base_addr) + (p)), v)
#define OUTW(dp, p, v) \
ddi_put16((dp)->regs_handle, \
(void *)((caddr_t)((dp)->base_addr) + (p)), v)
#define OUTL(dp, p, v) \
ddi_put32((dp)->regs_handle, \
(void *)((caddr_t)((dp)->base_addr) + (p)), v)
#define OUTLINL(dp, p, v) \
ddi_put32((dp)->regs_handle, \
(void *)((caddr_t)((dp)->base_addr) + (p)), v); \
(void) INL((dp), (p))
#define INB(dp, p) \
ddi_get8((dp)->regs_handle, \
(void *)(((caddr_t)(dp)->base_addr) + (p)))
#define INW(dp, p) \
ddi_get16((dp)->regs_handle, \
(void *)(((caddr_t)(dp)->base_addr) + (p)))
#define INL(dp, p) \
ddi_get32((dp)->regs_handle, \
(void *)(((caddr_t)(dp)->base_addr) + (p)))
struct gem_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;
};
#define GEM_MAXTXSEGS 4
#define GEM_MAXRXSEGS 1
#define GEM_MAXTXFRAGS 8
#define GEM_MAXRXFRAGS 4
/* TX buffer management */
struct txbuf {
struct txbuf *txb_next;
/* pointer to original mblk */
mblk_t *txb_mp;
/* dma mapping for current packet */
ddi_dma_cookie_t txb_dmacookie[GEM_MAXTXFRAGS];
uint_t txb_nfrags;
/* bounce buffer management */
ddi_dma_handle_t txb_bdh;
ddi_acc_handle_t txb_bah;
caddr_t txb_buf; /* vaddr of bounce buffer */
uint64_t txb_buf_dma; /* paddr of bounce buffer */
/* timeout management */
clock_t txb_stime;
/* Hardware descriptor info */
seqnum_t txb_desc;
int txb_ndescs;
uint64_t txb_flag;
};
/* RX buffer management */
struct rxbuf {
/* Hardware independent section */
struct rxbuf *rxb_next;
struct gem_dev *rxb_devp;
/* dma mapping management */
ddi_dma_handle_t rxb_dh;
caddr_t rxb_buf;
size_t rxb_buf_len;
ddi_dma_cookie_t rxb_dmacookie[GEM_MAXRXFRAGS];
uint_t rxb_nfrags;
/* bounce buffer management */
ddi_acc_handle_t rxb_bah;
};
struct mcast_addr {
struct ether_addr addr;
uint32_t hash;
};
#define GEM_MAXMC 64
#define GEM_MCALLOC (sizeof (struct mcast_addr) * GEM_MAXMC)
#define SUB(x, y) ((seqnum_t)((x) - (y)))
#define SLOT(seqnum, size) (((unsigned int)(seqnum)) & ((size)-1))
/*
* mac soft state
*/
struct gem_dev {
dev_info_t *dip;
mac_handle_t mh;
char name[GEM_NAME_LEN];
void *base_addr;
ddi_acc_handle_t regs_handle;
ddi_iblock_cookie_t iblock_cookie;
/* MAC address information */
struct ether_addr cur_addr;
struct ether_addr dev_addr;
/* Descriptor rings, io area */
ddi_dma_handle_t desc_dma_handle;
ddi_acc_handle_t desc_acc_handle;
caddr_t rx_ring;
caddr_t tx_ring;
caddr_t io_area;
/* caddr_t rx_buf; */
uint64_t rx_ring_dma;
uint64_t tx_ring_dma;
uint64_t io_area_dma;
/* RX slot ring management */
kmutex_t intrlock;
boolean_t intr_busy;
seqnum_t rx_active_head;
seqnum_t rx_active_tail;
mac_resource_handle_t mac_rx_ring_ha;
/* Rx buffer management */
struct rxbuf *rx_buf_head;
struct rxbuf *rx_buf_tail;
struct rxbuf *rx_buf_freelist;
int rx_buf_allocated;
int rx_buf_freecnt;
int rx_buf_len;
/* TX descriptor ring management */
seqnum_t tx_desc_head;
seqnum_t tx_desc_tail;
seqnum_t tx_desc_intr;
/* TX buffur ring management */
kmutex_t xmitlock;
kcondvar_t tx_drain_cv;
seqnum_t tx_active_head;
seqnum_t tx_active_tail;
seqnum_t tx_softq_head;
seqnum_t tx_softq_tail;
seqnum_t tx_free_head;
seqnum_t tx_free_tail;
int tx_max_packets;
/* TX buffer resource management */
struct txbuf *tx_buf;
seqnum_t tx_slots_base;
/* TX state management */
int tx_busy;
int tx_reclaim_busy;
clock_t tx_blocked;
/* NIC state */
volatile boolean_t mac_active; /* tx and rx are running */
volatile int nic_state; /* logical driver state */
#define NIC_STATE_STOPPED 0
#define NIC_STATE_INITIALIZED 1
#define NIC_STATE_ONLINE 2
volatile boolean_t mac_suspended;
/* robustness: timer and watchdog */
volatile timeout_id_t timeout_id;
/* MII management */
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_flow_control:2;
boolean_t mii_advert_ro:1;
boolean_t full_duplex:1;
int speed:3;
#define GEM_SPD_10 0
#define GEM_SPD_100 1
#define GEM_SPD_1000 2
#define GEM_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 */
uint8_t 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 */
volatile timeout_id_t link_watcher_id;
ddi_softintr_t soft_id;
/* multcast list management */
int16_t mc_count;
int16_t mc_count_req;
struct mcast_addr *mc_list;
uint32_t 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 gem_stats stats;
/* pointer to local structure */
void *private;
int priv_size;
/* polling mode */
int poll_pkt_delay; /* in number of packets */
/* descriptor area */
int tx_desc_size;
int rx_desc_size;
/* configuration */
struct gem_conf {
/* name */
char gc_name[GEM_NAME_LEN];
/* specification on tx and rx dma engine */
long gc_tx_buf_align;
int gc_tx_max_frags;
int gc_tx_max_descs_per_pkt;
int gc_tx_buf_size;
int gc_tx_buf_limit;
int gc_tx_desc_unit_shift;
int gc_tx_ring_size;
int gc_tx_ring_limit;
int gc_tx_copy_thresh;
boolean_t gc_tx_auto_pad;
boolean_t gc_tx_desc_write_oo;
long gc_rx_buf_align;
int gc_rx_max_frags;
int gc_rx_desc_unit_shift;
int gc_rx_ring_size;
int gc_rx_copy_thresh;
int gc_rx_buf_max;
int gc_rx_header_len;
int gc_io_area_size;
/* memory mapping attributes */
struct ddi_device_acc_attr gc_dev_attr;
struct ddi_device_acc_attr gc_buf_attr;
struct ddi_device_acc_attr gc_desc_attr;
/* dma attributes */
ddi_dma_attr_t gc_dma_attr_desc;
ddi_dma_attr_t gc_dma_attr_txbuf;
ddi_dma_attr_t gc_dma_attr_rxbuf;
/* tx time out parameters */
clock_t gc_tx_timeout;
clock_t gc_tx_timeout_interval;
/* auto negotiation capability */
int gc_flow_control;
/* MII mode */
int gc_mii_mode;
#define GEM_MODE_100BASETX 0
#define GEM_MODE_1000BASET 1
#define GEM_MODE_1000BASETX 2
/* MII link state watch parameters */
clock_t gc_mii_linkdown_timeout;
clock_t gc_mii_link_watch_interval;
clock_t gc_mii_reset_timeout;
clock_t gc_mii_an_watch_interval;
clock_t gc_mii_an_timeout;
clock_t gc_mii_an_wait;
clock_t gc_mii_an_delay;
/* MII configuration */
int gc_mii_addr_min;
int gc_mii_linkdown_action;
int gc_mii_linkdown_timeout_action;
#define MII_ACTION_NONE 0
#define MII_ACTION_RESET 1
#define MII_ACTION_RSA 2
boolean_t gc_mii_dont_reset;
boolean_t gc_mii_an_oneshot;
boolean_t gc_mii_hw_link_detection;
boolean_t gc_mii_stop_mac_on_linkdown;
/* I/O methods */
/* mac operation */
int (*gc_attach_chip)(struct gem_dev *dp);
int (*gc_reset_chip)(struct gem_dev *dp);
int (*gc_init_chip)(struct gem_dev *dp);
int (*gc_start_chip)(struct gem_dev *dp);
int (*gc_stop_chip)(struct gem_dev *dp);
uint32_t (*gc_multicast_hash)(struct gem_dev *dp, uint8_t *);
int (*gc_set_rx_filter)(struct gem_dev *dp);
int (*gc_set_media)(struct gem_dev *dp);
int (*gc_get_stats)(struct gem_dev *dp);
uint_t (*gc_interrupt)(struct gem_dev *dp);
/* descriptor operation */
int (*gc_tx_desc_write)(struct gem_dev *dp, int slot,
ddi_dma_cookie_t *dmacookie,
int frags, uint64_t flag);
#define GEM_TXFLAG_INTR 0x00000001ull
#define GEM_TXFLAG_TCP 0x00000002ull
#define GEM_TXFLAG_TCP_SHIFT 1ull
#define GEM_TXFLAG_UDP 0x00000004ull
#define GEM_TXFLAG_UDP_SHIFT 2ull
#define GEM_TXFLAG_IPv4 0x00000008ull
#define GEM_TXFLAG_IPv4_SHIFT 3ull
#define GEM_TXFLAG_IPv6 0x00000010ull
#define GEM_TXFLAG_IPv6_SHIFT 4ull
#define GEM_TXFLAG_HEAD 0x00000020ull
#define GEM_TXFLAG_TAIL 0x00000040ull
#define GEM_TXFLAG_SWVTAG 0x00000080ull
#define GEM_TXFLAG_PRIVATE 0x0000ff00ull
#define GEM_TXFLAG_PRIVATE_SHIFT 8ull
#define GEM_TXFLAG_PRIVATE_MASK 0xffull
#define GEM_TXFLAG_VID 0x0fff0000ull
#define GEM_TXFLAG_VID_SHIFT 16ull
#define GEM_TXFLAG_VID_MASK 0xfffull
#define GEM_TXFLAG_CFI 0x10000000ull
#define GEM_TXFLAG_PRI 0xe0000000ull
#define GEM_TXFLAG_PRI_SHIFT 29ull
#define GEM_TXFLAG_PRI_MASK 0x7ull
#define GEM_TXFLAG_VTAG 0xffff0000ull
#define GEM_TXFLAG_VTAG_SHIFT 16ull
#define GEM_TXFLAG_HCKSTART 0x000000ff00000000ull
#define GEM_TXFLAG_HCKSTART_SHIFT 32ull
#define GEM_TXFLAG_HCKSTUFF 0x0000ff0000000000ull
#define GEM_TXFLAG_HCKSTUFF_SHIFT 40ull
#define GEM_TXFLAG_TCPHLEN 0x0000ff0000000000ull
#define GEM_TXFLAG_TCPHLEN_SHIFT 40ull
#define GEM_TXFLAG_MSS 0xffff000000000000ull
#define GEM_TXFLAG_MSS_SHIFT 48ull
void (*gc_tx_start) (struct gem_dev *dp, int slot, int frags);
void (*gc_rx_desc_write)(struct gem_dev *dp, int slot,
ddi_dma_cookie_t *dmacookie, int frags);
void (*gc_rx_start)(struct gem_dev *dp, int slot, int frags);
uint_t (*gc_tx_desc_stat)
(struct gem_dev *dp, int slot, int descs);
#define GEM_TX_DONE 0x00010000
#define GEM_TX_ERR 0x00020000
uint64_t (*gc_rx_desc_stat)
(struct gem_dev *dp, int slot, int frags);
#define GEM_RX_CKSUM 0xffff000000000000ull
#define GEM_RX_CKSUM_SHIFT 48
#define GEM_RX_PRI 0x0000e00000000000ull
#define GEM_RX_PRI_SHIFT 45
#define GEM_RX_CFI 0x0000100000000000ull
#define GEM_RX_VID 0x00000fff00000000ull
#define GEM_RX_VID_SHIFT 32
#define GEM_RX_VTAG 0x0000ffff00000000ull
#define GEM_RX_VTAG_SHIFT 32
#define GEM_RX_CKSUM_IPv6 0x00080000ul
#define GEM_RX_CKSUM_IPv6_SHIFT 19
#define GEM_RX_CKSUM_IPv4 0x00040000ul
#define GEM_RX_CKSUM_IPv4_SHIFT 18
#define GEM_RX_CKSUM_UDP 0x00020000ul
#define GEM_RX_CKSUM_UDP_SHIFT 17
#define GEM_RX_CKSUM_TCP 0x00010000ul
#define GEM_RX_CKSUM_TCP_SHIFT 16
#define GEM_RX_ERR 0x00008000ul
#define GEM_RX_DONE 0x00004000ul
#define GEM_RX_LEN 0x00003ffful /* 16KB - 1 */
void (*gc_tx_desc_init)(struct gem_dev *dp, int slot);
void (*gc_rx_desc_init)(struct gem_dev *dp, int slot);
void (*gc_tx_desc_clean)(struct gem_dev *dp, int slot);
void (*gc_rx_desc_clean)(struct gem_dev *dp, int slot);
/* mii operations */
int (*gc_mii_probe)(struct gem_dev *dp);
int (*gc_mii_init)(struct gem_dev *dp);
int (*gc_mii_config)(struct gem_dev *dp);
void (*gc_mii_sync)(struct gem_dev *dp);
uint16_t (*gc_mii_read)(struct gem_dev *dp, uint_t reg);
void (*gc_mii_write)(struct gem_dev *dp,
uint_t reg, uint16_t val);
void (*gc_mii_tune_phy)(struct gem_dev *dp);
/* packet in/out operation for copy-style */
void (*gc_put_packet)(struct gem_dev *dp,
mblk_t *, void *, size_t);
mblk_t *(*gc_get_packet)(struct gem_dev *dp,
struct rxbuf *, size_t);
int gc_nports;
/* hw checksum */
uint32_t gc_hck_rx_start;
} gc;
uint32_t misc_flag;
#define GEM_LSO 0x00000400
#define GEM_CTRL_PKT 0x00000200
#define GEM_SOFTINTR 0x00000100
#define GEM_POLL_RXONLY 0x00000080
#define GEM_VLAN_HARD 0x00000040
#define GEM_VLAN_SOFT 0x00000020
#define GEM_VLAN (GEM_VLAN_HARD | GEM_VLAN_SOFT)
#define GEM_CKSUM_HEADER_IPv4 0x00000010
#define GEM_CKSUM_PARTIAL 0x00000008
#define GEM_CKSUM_FULL_IPv6 0x00000004
#define GEM_CKSUM_FULL_IPv4 0x00000002
#define GEM_NOINTR 0x00000001
volatile timeout_id_t intr_watcher_id;
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;
/* multiple port device support */
struct gem_dev *next; /* pointer to next port on the same device */
int port;
/* ndd stuff */
caddr_t nd_data_p;
caddr_t nd_arg_p;
#ifdef GEM_DEBUG_LEVEL
int tx_cnt;
#endif
};
/*
* Exported functions
*/
boolean_t gem_get_mac_addr_conf(struct gem_dev *);
int gem_mii_probe_default(struct gem_dev *);
int gem_mii_config_default(struct gem_dev *);
boolean_t gem_mii_link_check(struct gem_dev *dp);
uint16_t gem_mii_read(struct gem_dev *, uint_t);
void gem_mii_write(struct gem_dev *, uint_t, uint16_t);
int gem_reclaim_txbuf(struct gem_dev *dp);
int gem_restart_nic(struct gem_dev *dp, uint_t flags);
#define GEM_RESTART_NOWAIT 0x00000002
#define GEM_RESTART_KEEP_BUF 0x00000001
boolean_t gem_tx_done(struct gem_dev *);
int gem_receive(struct gem_dev *);
int gem_receive_copy(struct gem_dev *);
struct gem_dev *gem_do_attach(dev_info_t *, int,
struct gem_conf *, void *, ddi_acc_handle_t *, void *, int);
mblk_t *gem_send_common(struct gem_dev *, mblk_t *, uint32_t);
#define GEM_SEND_COPY 0x00008000
#define GEM_SEND_CTRL 0x000000ff /* private flags for control packets */
#define GEM_SEND_VTAG 0xffff0000
#define GEM_SEND_VTAG_SHIFT 16
mblk_t *gem_get_packet_default(struct gem_dev *, struct rxbuf *, size_t);
uint32_t gem_ether_crc_le(const uint8_t *addr, int len);
uint32_t gem_ether_crc_be(const uint8_t *addr, int len);
int gem_do_detach(dev_info_t *);
int gem_getlongprop_buf(dev_t dev, dev_info_t *dip,
int flags, char *name, void *buf, int *lenp);
int gem_getprop(dev_t dev, dev_info_t *dip,
int flags, char *name, int defvalue);
struct rxbuf *gem_get_rxbuf(struct gem_dev *, int);
void gem_rx_desc_dma_sync(struct gem_dev *, int, int, int);
void gem_tx_desc_dma_sync(struct gem_dev *, int, int, int);
int gem_resume(dev_info_t *);
int gem_suspend(dev_info_t *);
uint8_t gem_search_pci_cap(dev_info_t *dip, ddi_acc_handle_t, uint8_t);
int gem_pci_set_power_state(dev_info_t *, ddi_acc_handle_t, uint_t);
int gem_pci_regs_map_setup(dev_info_t *, uint32_t, uint32_t,
struct ddi_device_acc_attr *, caddr_t *, ddi_acc_handle_t *);
void gem_mod_init(struct dev_ops *, char *);
void gem_mod_fini(struct dev_ops *);
#define GEM_GET_DEV(dip) \
((struct gem_dev *)(ddi_get_driver_private(dip)))
#endif /* _SFE_UTIL_H_ */