#ifndef __CXGBE_ADAPTER_H
#define __CXGBE_ADAPTER_H
#include <sys/ddi.h>
#include <sys/mac_provider.h>
#include <sys/ethernet.h>
#include <sys/queue.h>
#include <sys/containerof.h>
#include <sys/ddi_ufm.h>
#include "firmware/t4fw_interface.h"
#include "shared.h"
struct adapter;
typedef struct adapter adapter_t;
#define FW_IQ_QSIZE 256
#define FW_IQ_ESIZE 64
#define RX_IQ_QSIZE 1024
#define RX_IQ_ESIZE 64
#define EQ_ESIZE 64
#define RX_FL_ESIZE 64
#define FL_BUF_SIZES 4
#define CTRL_EQ_QSIZE 128
#define TX_EQ_QSIZE 1024
#define TX_SGL_SEGS 36
#define TX_WR_FLITS (SGE_MAX_WR_LEN / 8)
#define UDBS_SEG_SHIFT 7
#define UDBS_DB_OFFSET 8
#define UDBS_WR_OFFSET 64
typedef enum t4_port_flags {
TPF_INIT_DONE = (1 << 0),
TPF_OPEN = (1 << 1),
} t4_port_flags_t;
typedef enum t4_port_feat {
CXGBE_HW_LSO = (1 << 0),
CXGBE_HW_CSUM = (1 << 1),
} t4_port_feat_t;
struct port_info {
dev_info_t *dip;
mac_handle_t mh;
mac_callbacks_t *mc;
int mtu;
uint8_t hw_addr[ETHERADDRL];
kmutex_t lock;
struct adapter *adapter;
t4_port_flags_t flags;
uint16_t viid;
int16_t xact_addr_filt;
uint16_t rss_size;
uint16_t ntxq;
uint16_t first_txq;
uint16_t nrxq;
uint16_t first_rxq;
uint8_t lport;
int8_t mdio_addr;
uint8_t port_type;
uint8_t mod_type;
uint8_t port_id;
uint8_t tx_chan;
uint8_t rx_chan;
uint8_t rx_cchan;
uint8_t instance;
uint8_t child_inst;
uint8_t tmr_idx;
int8_t pktc_idx;
uint8_t dbq_timer_idx;
struct link_config link_cfg;
struct port_stats stats;
t4_port_feat_t features;
uint8_t macaddr_cnt;
u8 rss_mode;
u16 viid_mirror;
kstat_t *ksp_config;
kstat_t *ksp_info;
kstat_t *ksp_fec;
u8 vivld;
u8 vin;
u8 smt_idx;
u8 vivld_mirror;
u8 vin_mirror;
u8 smt_idx_mirror;
};
struct fl_sdesc {
struct rxbuf *rxb;
};
struct tx_desc {
__be64 flit[8];
};
struct tx_sdesc {
mblk_t *mp_head;
mblk_t *mp_tail;
uint32_t txb_used;
uint16_t hdls_used;
uint16_t desc_used;
uint64_t _pad;
};
typedef enum t4_iq_flags {
IQ_ALLOCATED = (1 << 0),
IQ_INTR = (1 << 1),
IQ_HAS_FL = (1 << 2),
} t4_iq_flags_t;
typedef enum t4_iq_state {
IQS_DISABLED = 0,
IQS_BUSY = 1,
IQS_IDLE = 2,
} t4_iq_state_t;
struct rxbuf_cache_params {
dev_info_t *dip;
ddi_dma_attr_t dma_attr_rx;
ddi_device_acc_attr_t acc_attr_rx;
size_t buf_size;
};
struct sge_iq_stats {
uint64_t sis_overflow;
uint64_t sis_processed;
};
typedef enum t4_intr_config {
TIC_SE_INTR_ARM = 1,
TIC_TIMER0 = (0 << 1),
TIC_TIMER1 = (1 << 1),
TIC_TIMER2 = (2 << 1),
TIC_TIMER3 = (3 << 1),
TIC_TIMER4 = (4 << 1),
TIC_TIMER5 = (5 << 1),
TIC_START_COUNTER = (6 << 1),
} t4_intr_config_t;
struct sge_iq {
t4_iq_state_t state;
t4_iq_flags_t flags;
t4_intr_config_t intr_params;
ddi_dma_handle_t dhdl;
ddi_acc_handle_t ahdl;
__be64 *desc;
uint64_t ba;
const __be64 *cdesc;
struct adapter *adapter;
uint8_t gen;
int8_t intr_pktc_idx;
uint8_t esize;
uint16_t qsize;
uint16_t cidx;
uint16_t pending;
uint16_t cntxt_id;
uint16_t abs_id;
kmutex_t lock;
uint8_t polling;
struct sge_iq_stats stats;
STAILQ_ENTRY(sge_iq) link;
};
typedef enum t4_eq_flags {
EQ_ALLOCATED = (1 << 0),
EQ_MTX = (1 << 1),
EQ_CORKED = (1 << 2),
} t4_eq_flags_t;
typedef enum t4_doorbells {
DOORBELL_UDB = (1 << 0),
DOORBELL_WCWR = (1 << 1),
DOORBELL_UDBWC = (1 << 2),
DOORBELL_KDB = (1 << 3),
} t4_doorbells_t;
struct sge_eq {
ddi_dma_handle_t desc_dhdl;
ddi_acc_handle_t desc_ahdl;
t4_eq_flags_t flags;
kmutex_t lock;
struct tx_desc *desc;
uint64_t ba;
struct sge_qstat *spg;
t4_doorbells_t doorbells;
caddr_t udb;
uint_t udb_qid;
uint16_t cap;
uint16_t avail;
uint16_t qsize;
uint16_t cidx;
uint16_t pidx;
uint16_t pending;
uint16_t iqid;
uint8_t tx_chan;
uint32_t cntxt_id;
};
typedef enum t4_fl_flags {
FL_MTX = (1 << 0),
FL_STARVING = (1 << 1),
FL_DOOMED = (1 << 2),
} t4_fl_flags_t;
#define FL_RUNNING_LOW(fl) (fl->cap - fl->needed <= fl->lowat)
#define FL_NOT_RUNNING_LOW(fl) (fl->cap - fl->needed >= 2 * fl->lowat)
struct sge_fl {
t4_fl_flags_t flags;
kmutex_t lock;
ddi_dma_handle_t dhdl;
ddi_acc_handle_t ahdl;
__be64 *desc;
uint64_t ba;
struct fl_sdesc *sdesc;
uint32_t cap;
uint16_t qsize;
uint16_t cntxt_id;
uint32_t cidx;
uint32_t pidx;
uint32_t needed;
uint32_t lowat;
uint32_t pending;
uint32_t offset;
uint16_t copy_threshold;
uint64_t copied_up;
uint64_t passed_up;
uint64_t allocb_fail;
TAILQ_ENTRY(sge_fl) link;
};
struct sge_txq {
struct sge_eq eq;
struct port_info *port;
struct tx_sdesc *sdesc;
mac_ring_handle_t ring_handle;
ddi_dma_handle_t *tx_dhdl;
uint32_t tx_dhdl_total;
uint32_t tx_dhdl_pidx;
uint32_t tx_dhdl_cidx;
uint32_t tx_dhdl_avail;
ddi_dma_handle_t txb_dhdl;
ddi_acc_handle_t txb_ahdl;
caddr_t txb_va;
uint64_t txb_ba;
uint32_t txb_size;
uint32_t txb_next;
uint32_t txb_avail;
uint16_t copy_threshold;
uint64_t txpkts;
uint64_t txbytes;
kstat_t *ksp;
uint64_t txcsum;
uint64_t tso_wrs;
uint64_t imm_wrs;
uint64_t sgl_wrs;
uint64_t txpkt_wrs;
uint64_t txpkts_wrs;
uint64_t txpkts_pkts;
uint64_t txb_used;
uint64_t hdl_used;
uint32_t txb_full;
uint32_t dma_hdl_failed;
uint32_t dma_map_failed;
uint32_t qfull;
uint32_t pullup_early;
uint32_t pullup_late;
uint32_t pullup_failed;
uint32_t csum_failed;
};
struct sge_rxq {
struct sge_iq iq;
struct sge_fl fl;
struct port_info *port;
kstat_t *ksp;
mac_ring_handle_t ring_handle;
uint64_t ring_gen_num;
uint64_t rxcsum;
uint64_t rxpkts;
uint64_t rxbytes;
uint32_t nomem;
};
struct sge {
int fl_starve_threshold;
int s_qpp;
uint64_t dbq_timer_tick;
uint16_t dbq_timers[SGE_NDBQTIMERS];
int nrxq;
int ntxq;
int niq;
int neq;
int stat_len;
int pktshift;
int fl_align;
uint8_t fwq_tmr_idx;
int8_t fwq_pktc_idx;
struct sge_iq fwq;
struct sge_txq *txq;
struct sge_rxq *rxq;
uint_t iq_start;
uint_t eq_start;
uint_t iqmap_sz;
uint_t eqmap_sz;
struct sge_iq **iqmap;
struct sge_eq **eqmap;
ddi_device_acc_attr_t acc_attr_desc;
ddi_dma_attr_t dma_attr_desc;
ddi_device_acc_attr_t acc_attr_tx;
ddi_dma_attr_t dma_attr_tx;
kmem_cache_t *rxbuf_cache;
struct rxbuf_cache_params rxb_params;
};
struct driver_properties {
int max_ntxq_10g;
int max_nrxq_10g;
int max_ntxq_1g;
int max_nrxq_1g;
int intr_types;
int tmr_idx_10g;
int pktc_idx_10g;
int tmr_idx_1g;
int pktc_idx_1g;
uint8_t dbq_timer_idx;
uint8_t fwq_tmr_idx;
int8_t fwq_pktc_idx;
int qsize_txq;
int qsize_rxq;
uint_t holdoff_timer_us[SGE_NTIMERS];
uint_t holdoff_pktcnt[SGE_NCOUNTERS];
int wc;
int multi_rings;
int t4_fw_install;
};
struct t4_mbox_list {
STAILQ_ENTRY(t4_mbox_list) link;
};
typedef enum t4_adapter_flags {
TAF_INIT_DONE = (1 << 0),
TAF_FW_OK = (1 << 1),
TAF_INTR_FWD = (1 << 2),
TAF_INTR_ALLOC = (1 << 3),
TAF_MASTER_PF = (1 << 4),
TAF_DBQ_TIMER = (1 << 5),
} t4_adapter_flags_t;
struct adapter {
list_node_t node;
dev_info_t *dip;
dev_t dev;
unsigned int pf;
unsigned int mbox;
unsigned int vpd_busy;
unsigned int vpd_flag;
u32 t4_bar0;
uint_t open;
ddi_acc_handle_t pci_regh;
ddi_acc_handle_t regh;
caddr_t regp;
ddi_acc_handle_t bar2_hdl;
caddr_t bar2_ptr;
int intr_type;
int intr_count;
int intr_cap;
uint_t intr_pri;
ddi_intr_handle_t *intr_handle;
struct driver_properties props;
kstat_t *ksp;
kstat_t *ksp_stat;
struct sge sge;
struct port_info *port[MAX_NPORTS];
uint8_t chan_map[NCHAN];
uint32_t filter_mode;
t4_adapter_flags_t flags;
t4_doorbells_t doorbells;
unsigned int cfcsum;
struct adapter_params params;
kmutex_t lock;
kcondvar_t cv;
kmutex_t sfl_lock;
TAILQ_HEAD(, sge_fl) sfl;
timeout_id_t sfl_timer;
id_t temp_sensor;
id_t volt_sensor;
ddi_ufm_handle_t *ufm_hdl;
kmutex_t mbox_lock;
STAILQ_HEAD(, t4_mbox_list) mbox_list;
};
struct memwin {
uint32_t base;
uint32_t aperture;
};
#define ADAPTER_LOCK(sc) mutex_enter(&(sc)->lock)
#define ADAPTER_UNLOCK(sc) mutex_exit(&(sc)->lock)
#define ADAPTER_LOCK_ASSERT_OWNED(sc) ASSERT(mutex_owned(&(sc)->lock))
#define ADAPTER_LOCK_ASSERT_NOTOWNED(sc) ASSERT(!mutex_owned(&(sc)->lock))
#define PORT_LOCK(pi) mutex_enter(&(pi)->lock)
#define PORT_UNLOCK(pi) mutex_exit(&(pi)->lock)
#define PORT_LOCK_ASSERT_OWNED(pi) ASSERT(mutex_owned(&(pi)->lock))
#define PORT_LOCK_ASSERT_NOTOWNED(pi) ASSERT(!mutex_owned(&(pi)->lock))
#define IQ_LOCK(iq) mutex_enter(&(iq)->lock)
#define IQ_UNLOCK(iq) mutex_exit(&(iq)->lock)
#define IQ_LOCK_ASSERT_OWNED(iq) ASSERT(mutex_owned(&(iq)->lock))
#define IQ_LOCK_ASSERT_NOTOWNED(iq) ASSERT(!mutex_owned(&(iq)->lock))
#define FL_LOCK(fl) mutex_enter(&(fl)->lock)
#define FL_UNLOCK(fl) mutex_exit(&(fl)->lock)
#define FL_LOCK_ASSERT_OWNED(fl) ASSERT(mutex_owned(&(fl)->lock))
#define FL_LOCK_ASSERT_NOTOWNED(fl) ASSERT(!mutex_owned(&(fl)->lock))
#define RXQ_LOCK(rxq) IQ_LOCK(&(rxq)->iq)
#define RXQ_UNLOCK(rxq) IQ_UNLOCK(&(rxq)->iq)
#define RXQ_LOCK_ASSERT_OWNED(rxq) IQ_LOCK_ASSERT_OWNED(&(rxq)->iq)
#define RXQ_LOCK_ASSERT_NOTOWNED(rxq) IQ_LOCK_ASSERT_NOTOWNED(&(rxq)->iq)
#define RXQ_FL_LOCK(rxq) FL_LOCK(&(rxq)->fl)
#define RXQ_FL_UNLOCK(rxq) FL_UNLOCK(&(rxq)->fl)
#define RXQ_FL_LOCK_ASSERT_OWNED(rxq) FL_LOCK_ASSERT_OWNED(&(rxq)->fl)
#define RXQ_FL_LOCK_ASSERT_NOTOWNED(rxq) FL_LOCK_ASSERT_NOTOWNED(&(rxq)->fl)
#define EQ_LOCK(eq) mutex_enter(&(eq)->lock)
#define EQ_UNLOCK(eq) mutex_exit(&(eq)->lock)
#define EQ_LOCK_ASSERT_OWNED(eq) ASSERT(mutex_owned(&(eq)->lock))
#define EQ_LOCK_ASSERT_NOTOWNED(eq) ASSERT(!mutex_owned(&(eq)->lock))
#define TXQ_LOCK(txq) EQ_LOCK(&(txq)->eq)
#define TXQ_UNLOCK(txq) EQ_UNLOCK(&(txq)->eq)
#define TXQ_LOCK_ASSERT_OWNED(txq) EQ_LOCK_ASSERT_OWNED(&(txq)->eq)
#define TXQ_LOCK_ASSERT_NOTOWNED(txq) EQ_LOCK_ASSERT_NOTOWNED(&(txq)->eq)
#define for_each_txq(pi, iter, txq) \
txq = &pi->adapter->sge.txq[pi->first_txq]; \
for (iter = 0; iter < pi->ntxq; ++iter, ++txq)
#define for_each_rxq(pi, iter, rxq) \
rxq = &pi->adapter->sge.rxq[pi->first_rxq]; \
for (iter = 0; iter < pi->nrxq; ++iter, ++rxq)
#define NFIQ(sc) ((sc)->intr_count > 1 ? (sc)->intr_count - 1 : 1)
#define T4_EXTRA_INTR 2
static inline void t4_mbox_list_add(struct adapter *adap,
struct t4_mbox_list *entry)
{
mutex_enter(&adap->mbox_lock);
STAILQ_INSERT_TAIL(&adap->mbox_list, entry, link);
mutex_exit(&adap->mbox_lock);
}
static inline void t4_mbox_list_del(struct adapter *adap,
struct t4_mbox_list *entry)
{
mutex_enter(&adap->mbox_lock);
STAILQ_REMOVE(&adap->mbox_list, entry, t4_mbox_list, link);
mutex_exit(&adap->mbox_lock);
}
static inline struct t4_mbox_list *
t4_mbox_list_first_entry(struct adapter *adap)
{
return (STAILQ_FIRST(&adap->mbox_list));
}
static inline struct port_info *
adap2pinfo(struct adapter *sc, int idx)
{
return (sc->port[idx]);
}
static inline struct sge_rxq *
iq_to_rxq(struct sge_iq *iq)
{
return (__containerof(iq, struct sge_rxq, iq));
}
static inline bool
t4_port_is_10xg(const struct port_info *pi)
{
return (pi->link_cfg.pcaps &
(FW_PORT_CAP32_SPEED_400G |
FW_PORT_CAP32_SPEED_200G |
FW_PORT_CAP32_SPEED_100G |
FW_PORT_CAP32_SPEED_50G |
FW_PORT_CAP32_SPEED_40G |
FW_PORT_CAP32_SPEED_25G |
FW_PORT_CAP32_SPEED_10G));
}
static inline unsigned int t4_use_ldst(struct adapter *adap)
{
return (adap->flags & FW_OK);
}
static inline void t4_db_full(struct adapter *adap) {}
static inline void t4_db_dropped(struct adapter *adap) {}
static inline bool
t4_cver_eq(const adapter_t *adap, uint8_t ver)
{
return (CHELSIO_CHIP_VERSION(adap->params.chip) == ver);
}
static inline bool
t4_cver_ge(const adapter_t *adap, uint8_t ver)
{
return (CHELSIO_CHIP_VERSION(adap->params.chip) >= ver);
}
int t4_port_full_init(struct port_info *);
void t4_port_queues_enable(struct port_info *pi);
void t4_port_queues_disable(struct port_info *pi);
uint32_t t4_read_reg(struct adapter *, uint32_t);
void t4_write_reg(struct adapter *, uint32_t, uint32_t);
uint64_t t4_read_reg64(struct adapter *, uint32_t);
void t4_write_reg64(struct adapter *, uint32_t, uint64_t);
void t4_debug_init(void);
void t4_debug_fini(void);
void t4_sge_init(struct adapter *sc);
int t4_alloc_fwq(struct adapter *);
int t4_free_fwq(struct adapter *);
int t4_setup_port_queues(struct port_info *pi);
int t4_teardown_port_queues(struct port_info *pi);
uint_t t4_intr_all(caddr_t arg1, caddr_t arg2);
uint_t t4_intr(caddr_t arg1, caddr_t arg2);
uint_t t4_intr_err(caddr_t arg1, caddr_t arg2);
void t4_iq_gts_update(struct sge_iq *, t4_intr_config_t, uint16_t);
void t4_iq_update_intr_cfg(struct sge_iq *, uint8_t, int8_t);
void t4_eq_update_dbq_timer(struct sge_eq *, struct port_info *);
int t4_mgmt_tx(struct adapter *sc, mblk_t *m);
mblk_t *t4_eth_tx(void *, mblk_t *);
mblk_t *t4_mc_tx(void *arg, mblk_t *m);
mblk_t *t4_ring_rx(struct sge_rxq *rxq, int poll_bytes);
void t4_mc_cb_init(struct port_info *);
void t4_os_link_changed(struct adapter *sc, int idx, int link_stat);
void t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m);
void t4_mac_tx_update(struct port_info *pi, struct sge_txq *txq);
int t4_addmac(void *arg, const uint8_t *ucaddr);
const char **t4_get_priv_props(struct port_info *, size_t *);
uint8_t t4_choose_holdoff_timer(struct adapter *, uint_t);
int8_t t4_choose_holdoff_pktcnt(struct adapter *, int);
uint_t t4_choose_dbq_timer(struct adapter *, uint_t);
int t4_ioctl(struct adapter *sc, int cmd, void *data, int mode);
#endif