diff options
author | kmacy <kmacy@FreeBSD.org> | 2007-03-20 21:43:32 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2007-03-20 21:43:32 +0000 |
commit | febce07b1841a6b5680a436c04a0e6ea67af094a (patch) | |
tree | 902f132b95a6b5c1b94654d87f196a5f8c9da24b /sys/dev | |
parent | 9c3aae940304a96fc50dbe9e3e92f5f783d3bf03 (diff) | |
download | FreeBSD-src-febce07b1841a6b5680a436c04a0e6ea67af094a.zip FreeBSD-src-febce07b1841a6b5680a436c04a0e6ea67af094a.tar.gz |
Synchronize with version 1.0.071 of Chelsio's common code
(with the notable exception of improvements for using multiple TX queues)
This adds support for the T3B2 ASIC rev
Obtained from: Chelsio
MFC after: 3 days
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cxgb/common/cxgb_common.h | 35 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_regs.h | 4 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_t3_hw.c | 150 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_version.h | 8 | ||||
-rw-r--r-- | sys/dev/cxgb/common/cxgb_xgmac.c | 130 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_adapter.h | 1 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_config.h | 2 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_ioctl.h | 12 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_main.c | 76 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_osdep.h | 2 |
10 files changed, 363 insertions, 57 deletions
diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h index 4d7c5966..3c49818 100644 --- a/sys/dev/cxgb/common/cxgb_common.h +++ b/sys/dev/cxgb/common/cxgb_common.h @@ -45,6 +45,7 @@ enum { TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ + NTX_SCHED = 8, /* # of HW Tx scheduling queues */ }; #define MAX_RX_COALESCING_LEN 16224U @@ -69,6 +70,12 @@ enum { /* adapter interrupt-maintained statistics */ }; enum { + FW_VERSION_MAJOR = 3, + FW_VERSION_MINOR = 2, + FW_VERSION_MICRO = 0 +}; + +enum { SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */ SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */ SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */ @@ -203,6 +210,9 @@ struct mac_stats { unsigned long serdes_signal_loss; unsigned long xaui_pcs_ctc_err; unsigned long xaui_pcs_align_change; + + unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */ + unsigned long num_resets; /* # times reset due to stuck TX */ }; struct tp_mib_stats { @@ -261,6 +271,7 @@ struct tp_params { unsigned int rx_num_pgs; /* # of Rx pages */ unsigned int tx_num_pgs; /* # of Tx pages */ unsigned int ntimer_qs; /* # of timer queues */ + unsigned int dack_re; /* DACK timer resolution */ }; struct qset_params { /* SGE queue set parameters */ @@ -271,6 +282,7 @@ struct qset_params { /* SGE queue set parameters */ unsigned int jumbo_size; /* # of entries in jumbo free list */ unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ unsigned int cong_thres; /* FL congestion threshold */ + unsigned int vector; /* Interrupt (line or vector) number */ }; struct sge_params { @@ -344,6 +356,12 @@ struct adapter_params { unsigned int rev; /* chip revision */ }; +enum { /* chip revisions */ + T3_REV_A = 0, + T3_REV_B = 2, + T3_REV_B2 = 3, +}; + struct trace_params { u32 sip; u32 sip_mask; @@ -409,6 +427,10 @@ struct cmac { adapter_t *adapter; unsigned int offset; unsigned int nucast; /* # of address filters for unicast MACs */ + unsigned int tcnt; + unsigned int xcnt; + unsigned int toggle_cnt; + unsigned int txen; struct mac_stats stats; }; @@ -544,6 +566,12 @@ static inline unsigned int core_ticks_per_usec(const adapter_t *adap) return adap->params.vpd.cclk / 1000; } +static inline unsigned int dack_ticks_to_usec(const adapter_t *adap, + unsigned int ticks) +{ + return (ticks << adap->params.tp.dack_re) / core_ticks_per_usec(adap); +} + static inline unsigned int is_pcie(const adapter_t *adap) { return adap->params.pci.variant == PCI_VARIANT_PCIE; @@ -622,6 +650,7 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n); const struct mac_stats *t3_mac_update_stats(struct cmac *mac); int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc); +int t3b2_mac_watchdog_task(struct cmac *mac); void t3_mc5_prep(adapter_t *adapter, struct mc5 *mc5, int mode); int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, @@ -644,6 +673,12 @@ void t3_get_cong_cntl_tab(adapter_t *adap, void t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, int filter_index, int invert, int enable); int t3_config_sched(adapter_t *adap, unsigned int kbps, int sched); +int t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg); +void t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps, + unsigned int *ipg); +void t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]); +void t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals, + unsigned int start, unsigned int n); #endif void t3_sge_prep(adapter_t *adap, struct sge_params *p); diff --git a/sys/dev/cxgb/common/cxgb_regs.h b/sys/dev/cxgb/common/cxgb_regs.h index 153116f..fe8cd14 100644 --- a/sys/dev/cxgb/common/cxgb_regs.h +++ b/sys/dev/cxgb/common/cxgb_regs.h @@ -4163,8 +4163,8 @@ $FreeBSD$ #define V_TX_MOD_WEIGHT(x) ((x) << S_TX_MOD_WEIGHT) #define G_TX_MOD_WEIGHT(x) (((x) >> S_TX_MOD_WEIGHT) & M_TX_MOD_WEIGHT) -#define S_TX_MOD_TIMER_MODE 9 -#define M_TX_MOD_TIMER_MODE 0x7f +#define S_TX_MOD_TIMER_MODE 8 +#define M_TX_MOD_TIMER_MODE 0xff #define V_TX_MOD_TIMER_MODE(x) ((x) << S_TX_MOD_TIMER_MODE) #define G_TX_MOD_TIMER_MODE(x) (((x) >> S_TX_MOD_TIMER_MODE) & M_TX_MOD_TIMER_MODE) diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c index 701b5c7..fd467e2 100644 --- a/sys/dev/cxgb/common/cxgb_t3_hw.c +++ b/sys/dev/cxgb/common/cxgb_t3_hw.c @@ -684,7 +684,8 @@ enum { SF_ERASE_SECTOR = 0xd8, /* erase sector */ FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ - FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */ + FW_VERS_ADDR = 0x77ffc, /* flash address holding FW version */ + FW_MIN_SIZE = 8 /* at least version and csum */ }; /** @@ -887,12 +888,13 @@ int t3_check_fw_version(adapter_t *adapter) major = G_FW_VERSION_MAJOR(vers); minor = G_FW_VERSION_MINOR(vers); - if (type == FW_VERSION_T3 && major == CHELSIO_FW_MAJOR && minor == CHELSIO_FW_MINOR) + if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && + minor == FW_VERSION_MINOR) return 0; CH_ERR(adapter, "found wrong FW version(%u.%u), " "driver needs version %d.%d\n", major, minor, - CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR); + FW_VERSION_MAJOR, FW_VERSION_MINOR); return -EINVAL; } @@ -937,7 +939,7 @@ int t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size) const u32 *p = (const u32 *)fw_data; int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; - if (size & 3) + if ((size & 3) || (size < FW_MIN_SIZE)) return -EINVAL; if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) return -EFBIG; @@ -1558,7 +1560,6 @@ int t3_slow_intr_handler(adapter_t *adapter) if (!cause) return 0; - printf("slow intr handler\n"); if (cause & F_PCIM0) { if (is_pcie(adapter)) pcie_intr_handler(adapter); @@ -2353,7 +2354,7 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | F_MTUENABLE | V_WINDOWSCALEMODE(1) | - V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); + V_TIMESTAMPSMODE(0) | V_SACKMODE(1) | V_SACKRX(1)); t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) | @@ -2380,13 +2381,14 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) } else t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); - t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212); - t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212); - t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); + t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); + t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0); } /* Desired TP timer resolution in usec */ -#define TP_TMR_RES 50 +#define TP_TMR_RES 200 /* TCP timer values in ms */ #define TP_DACK_TIMER 50 @@ -2403,7 +2405,7 @@ static void tp_config(adapter_t *adap, const struct tp_params *p) static void tp_set_timers(adapter_t *adap, unsigned int core_clk) { unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; - unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */ + unsigned int dack_re = adap->params.tp.dack_re; unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ unsigned int tps = core_clk >> tre; @@ -2489,10 +2491,11 @@ static void __devinit init_mtus(unsigned short mtus[]) * are enabled and still have at least 8 bytes of payload. */ mtus[0] = 88; - mtus[1] = 256; - mtus[2] = 512; - mtus[3] = 576; - mtus[4] = 808; + mtus[1] = 88; /* workaround for silicon starting at 1 */ + mtus[2] = 256; + mtus[3] = 512; + mtus[4] = 576; + /* mtus[4] = 808; */ mtus[5] = 1024; mtus[6] = 1280; mtus[7] = 1492; @@ -2648,6 +2651,42 @@ void t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps) sizeof(*tps) / sizeof(u32), 0); } +/** + * t3_read_pace_tbl - read the pace table + * @adap: the adapter + * @pace_vals: holds the returned values + * + * Returns the values of TP's pace table in nanoseconds. + */ +void t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED]) +{ + unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000); + + for (i = 0; i < NTX_SCHED; i++) { + t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i); + pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns; + } +} + +/** + * t3_set_pace_tbl - set the pace table + * @adap: the adapter + * @pace_vals: the pace values in nanoseconds + * @start: index of the first entry in the HW pace table to set + * @n: how many entries to set + * + * Sets (a subset of the) HW pace table. + */ +void t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals, + unsigned int start, unsigned int n) +{ + unsigned int tick_ns = dack_ticks_to_usec(adap, 1000); + + for ( ; n; n--, start++, pace_vals++) + t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | + ((*pace_vals + tick_ns / 2) / tick_ns)); +} + #define ulp_region(adap, name, start, len) \ t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ @@ -2712,7 +2751,7 @@ void t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp, * @kbps: target rate in Kbps * @sched: the scheduler index * - * Configure a HW scheduler for the target rate + * Configure a Tx HW scheduler for the target rate. */ int t3_config_sched(adapter_t *adap, unsigned int kbps, int sched) { @@ -2750,6 +2789,75 @@ int t3_config_sched(adapter_t *adap, unsigned int kbps, int sched) return 0; } +/** + * t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler + * @adap: the adapter + * @sched: the scheduler index + * @ipg: the interpacket delay in tenths of nanoseconds + * + * Set the interpacket delay for a HW packet rate scheduler. + */ +int t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg) +{ + unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; + + /* convert ipg to nearest number of core clocks */ + ipg *= core_ticks_per_usec(adap); + ipg = (ipg + 5000) / 10000; + if (ipg > 0xffff) + return -EINVAL; + + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v = (v & 0xffff) | (ipg << 16); + else + v = (v & 0xffff0000) | ipg; + t3_write_reg(adap, A_TP_TM_PIO_DATA, v); + t3_read_reg(adap, A_TP_TM_PIO_DATA); + return 0; +} + +/** + * t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler + * @adap: the adapter + * @sched: the scheduler index + * @kbps: the byte rate in Kbps + * @ipg: the interpacket delay in tenths of nanoseconds + * + * Return the current configuration of a HW Tx scheduler. + */ +void t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps, + unsigned int *ipg) +{ + unsigned int v, addr, bpt, cpt; + + if (kbps) { + addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + bpt = (v >> 8) & 0xff; + cpt = v & 0xff; + if (!cpt) + *kbps = 0; /* scheduler disabled */ + else { + v = (adap->params.vpd.cclk * 1000) / cpt; + *kbps = (v * bpt) / 125; + } + } + if (ipg) { + addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2; + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + v &= 0xffff; + *ipg = (10000 * v) / core_ticks_per_usec(adap); + } +} + static int tp_init(adapter_t *adap, const struct tp_params *p) { int busy = 0; @@ -3249,10 +3357,11 @@ void early_hw_init(adapter_t *adapter, const struct adapter_info *ai) */ int t3_reset_adapter(adapter_t *adapter) { - int i; - uint16_t devid = 0; + int i, save_and_restore_pcie = + adapter->params.rev < T3_REV_B2 && is_pcie(adapter); + uint16_t devid = 0; - if (is_pcie(adapter)) + if (save_and_restore_pcie) t3_os_pci_save_state(adapter); t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); @@ -3270,7 +3379,7 @@ int t3_reset_adapter(adapter_t *adapter) if (devid != 0x1425) return -1; - if (is_pcie(adapter)) + if (save_and_restore_pcie) t3_os_pci_restore_state(adapter); return 0; } @@ -3325,6 +3434,7 @@ int __devinit t3_prep_adapter(adapter_t *adapter, p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); p->ntimer_qs = p->cm_size >= (128 << 20) || adapter->params.rev > 0 ? 12 : 6; + p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */ adapter->params.mc5.nservers = DEFAULT_NSERVERS; adapter->params.mc5.nfilters = adapter->params.rev > 0 ? diff --git a/sys/dev/cxgb/common/cxgb_version.h b/sys/dev/cxgb/common/cxgb_version.h index 7d15ca4..4f671cf 100644 --- a/sys/dev/cxgb/common/cxgb_version.h +++ b/sys/dev/cxgb/common/cxgb_version.h @@ -32,10 +32,14 @@ POSSIBILITY OF SUCH DAMAGE. $FreeBSD$ ***************************************************************************/ - +/* + * Note that although this driver doesn't contain all of the functionality of the Linux driver + * the common code is 99% the same. Hence we keep the same version number to indicate what linux + * driver the common code corresponds to. + */ #ifndef __CHELSIO_VERSION_H #define __CHELSIO_VERSION_H #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.0.071" #endif diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c index f958c20..aeea758 100644 --- a/sys/dev/cxgb/common/cxgb_xgmac.c +++ b/sys/dev/cxgb/common/cxgb_xgmac.c @@ -129,9 +129,6 @@ int t3_mac_reset(struct cmac *mac) xaui_serdes_reset(mac); } - if (adap->params.rev > 0) - t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000); - val = F_MAC_RESET_; if (is_10G(adap)) val |= F_PCS_RESET_; @@ -150,6 +147,62 @@ int t3_mac_reset(struct cmac *mac) return 0; } +static int t3b2_mac_reset(struct cmac *mac) +{ + u32 val; + adapter_t *adap = mac->adapter; + unsigned int oft = mac->offset; + + + /* Stop egress traffic to xgm*/ + if (!macidx(mac)) + t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); + else + t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); + + /* PCS in reset */ + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); + (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + t3_os_sleep(10); + + /* Check for xgm Rx fifo empty */ + if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, + 0x80000000, 1, 5, 2)) { + CH_ERR(adap, "MAC %d Rx fifo drain failed\n", + macidx(mac)); + return -1; + } + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ + (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + val = F_MAC_RESET_; + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + t3_os_sleep(1); + t3b_pcs_reset(mac); + } + t3_write_reg(adap, A_XGM_RX_CFG + oft, + F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); + + /*Resume egress traffic to xgm*/ + if (!macidx(mac)) + t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); + else + t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); + + return 0; +} + /* * Set the exact match register 'idx' to recognize the given Ethernet address. */ @@ -256,9 +309,10 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) * Adjust the PAUSE frame watermarks. We always set the LWM, and the * HWM only if flow-control is enabled. */ - hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U); - hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024); - lwm = hwm - 1024; + hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, + MAC_RXFIFO_SIZE * 38 / 100); + hwm = min(hwm, MAC_RXFIFO_SIZE - 8192); + lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4); v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); v |= V_RXFIFOPAUSELWM(lwm / 8); @@ -275,8 +329,16 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; thres = max(thres, 8U); /* need at least 8 */ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, - V_TXFIFOTHRESH(M_TXFIFOTHRESH), - V_TXFIFOTHRESH(thres)); + V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), + V_TXFIFOTHRESH(thres) | V_TXIPG(1)); + + /* Assuming a minimum drain rate of 2.5Gbps... + */ + if (adap->params.rev > 0) + t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, + (hwm-lwm) * 4 / 8); + t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, + MAC_RXFIFO_SIZE * 4 * 8 / 512); return 0; } @@ -303,13 +365,13 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); } - +#if 0 val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */ t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); - +#endif t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); return 0; @@ -324,9 +386,15 @@ int t3_mac_enable(struct cmac *mac, int which) if (which & MAC_DIRECTION_TX) { t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001); + t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx); + mac->tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA))); + mac->xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT))); + mac->txen = F_TXEN; + mac->toggle_cnt = 0; } if (which & MAC_DIRECTION_RX) t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); @@ -343,13 +411,45 @@ int t3_mac_disable(struct cmac *mac, int which) t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); - t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0); + t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + mac->txen = 0; } if (which & MAC_DIRECTION_RX) t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); return 0; } +int t3b2_mac_watchdog_task(struct cmac *mac) +{ + int status; + unsigned int tcnt, xcnt; + adapter_t *adap = mac->adapter; + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + macidx(mac)); + tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA))); + xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset))); + + if ((tcnt != mac->tcnt) && (xcnt == 0) && (mac->xcnt == 0)) { + if (mac->toggle_cnt > 4) { + t3b2_mac_reset(mac); + mac->toggle_cnt = 0; + status = 2; + } else { + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); + t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); + t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ + mac->toggle_cnt++; + status = 1; + } + } else { + mac->toggle_cnt = 0; + status = 0; + } + mac->tcnt = tcnt; + mac->xcnt = xcnt; + return status; +} + /* * This function is called periodically to accumulate the current values of the * RMON counters into the port statistics. Since the packet counters are only @@ -379,7 +479,11 @@ const struct mac_stats *t3_mac_update_stats(struct cmac *mac) RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); - mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); + + v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); + if (mac->adapter->params.rev == T3_REV_B2) + v &= 0x7fffffff; + mac->stats.rx_too_long += v; RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); diff --git a/sys/dev/cxgb/cxgb_adapter.h b/sys/dev/cxgb/cxgb_adapter.h index 534e314..33a5e4a 100644 --- a/sys/dev/cxgb/cxgb_adapter.h +++ b/sys/dev/cxgb/cxgb_adapter.h @@ -71,7 +71,6 @@ struct port_info { struct cphy phy; struct cmac mac; struct link_config link_config; - int activity; struct ifmedia media; struct mtx lock; diff --git a/sys/dev/cxgb/cxgb_config.h b/sys/dev/cxgb/cxgb_config.h index 2a95f88..e5168ad 100644 --- a/sys/dev/cxgb/cxgb_config.h +++ b/sys/dev/cxgb/cxgb_config.h @@ -38,8 +38,6 @@ $FreeBSD$ #ifndef CONFIG_DEFINED #define CONFIG_CHELSIO_T3_CORE -#define CHELSIO_FW_MAJOR 3 -#define CHELSIO_FW_MINOR 2 #define DEFAULT_JUMBO #endif diff --git a/sys/dev/cxgb/cxgb_ioctl.h b/sys/dev/cxgb/cxgb_ioctl.h index f74b9a2..79e5fa6 100644 --- a/sys/dev/cxgb/cxgb_ioctl.h +++ b/sys/dev/cxgb/cxgb_ioctl.h @@ -110,6 +110,8 @@ struct ch_qset_params { int32_t intr_lat; int32_t polling; int32_t cong_thres; + int32_t vector; + int32_t qnum; }; struct ch_pktsched_params { @@ -121,6 +123,16 @@ struct ch_pktsched_params { uint8_t binding; }; +struct ch_hw_sched { + uint32_t cmd; + uint8_t sched; + int8_t mode; + int8_t channel; + int32_t kbps; /* rate in Kbps */ + int32_t class_ipg; /* tenths of nanoseconds */ + int32_t flow_ipg; /* usec */ +}; + #ifndef TCB_SIZE # define TCB_SIZE 128 #endif diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index 8a61fe4..ab79f68 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -104,7 +104,6 @@ static int setup_sge_qsets(adapter_t *); static void cxgb_async_intr(void *); static void cxgb_ext_intr_handler(void *, int); static void cxgb_tick(void *); -static void check_link_status(adapter_t *sc); static void setup_rss(adapter_t *sc); /* Attachment glue for the PCI controller end of the device. Each port of @@ -278,7 +277,8 @@ cxgb_fw_download(adapter_t *sc, device_t dev) #endif int status; - snprintf(&buf[0], sizeof(buf), "t3fw%d%d", CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR); + snprintf(&buf[0], sizeof(buf), "t3fw%d%d", FW_VERSION_MAJOR, + FW_VERSION_MINOR); fw = firmware_get(buf); @@ -395,7 +395,7 @@ cxgb_controller_attach(device_t dev) /* Create a periodic callout for checking adapter status */ - callout_init_mtx(&sc->cxgb_tick_ch, &sc->lock, 0); + callout_init_mtx(&sc->cxgb_tick_ch, &sc->lock, CALLOUT_RETURNUNLOCKED); ai = cxgb_get_adapter_info(dev); if (t3_prep_adapter(sc, ai, 1) < 0) { @@ -407,7 +407,7 @@ cxgb_controller_attach(device_t dev) * Warn user that a firmware update will be attempted in init. */ device_printf(dev, "firmware needs to be updated to version %d.%d\n", - CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR); + FW_VERSION_MAJOR, FW_VERSION_MINOR); sc->flags &= ~FW_UPTODATE; } else { sc->flags |= FW_UPTODATE; @@ -1090,7 +1090,7 @@ cxgb_init_locked(struct port_info *p) ifp = p->ifp; if ((sc->flags & FW_UPTODATE) == 0) { device_printf(sc->dev, "updating firmware to version %d.%d\n", - CHELSIO_FW_MAJOR, CHELSIO_FW_MINOR); + FW_VERSION_MAJOR, FW_VERSION_MINOR); if ((error = cxgb_fw_download(sc, sc->dev)) != 0) { device_printf(sc->dev, "firmware download failed err: %d" "interface will be unavailable\n", error); @@ -1393,31 +1393,73 @@ cxgb_ext_intr_handler(void *arg, int count) } static void -cxgb_tick(void *arg) +check_link_status(adapter_t *sc) { - adapter_t *sc = (adapter_t *)arg; - const struct adapter_params *p = &sc->params; + int i; - if (p->linkpoll_period) - check_link_status(sc); + for (i = 0; i < (sc)->params.nports; ++i) { + struct port_info *p = &sc->port[i]; - callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz, - cxgb_tick, sc); + if (!(p->port_type->caps & SUPPORTED_IRQ)) + t3_link_changed(sc, i); + } } static void -check_link_status(adapter_t *sc) +check_t3b2_mac(struct adapter *adapter) { int i; - for (i = 0; i < (sc)->params.nports; ++i) { - struct port_info *p = &sc->port[i]; + for_each_port(adapter, i) { + struct port_info *p = &adapter->port[i]; + struct ifnet *ifp = p->ifp; + int status; - if (!(p->port_type->caps & SUPPORTED_IRQ)) - t3_link_changed(sc, i); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + continue; + + status = 0; + PORT_LOCK(p); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) + status = t3b2_mac_watchdog_task(&p->mac); + if (status == 1) + p->mac.stats.num_toggled++; + else if (status == 2) { + struct cmac *mac = &p->mac; + + t3_mac_set_mtu(mac, ifp->if_mtu); + t3_mac_set_address(mac, 0, p->hw_addr); + cxgb_set_rxmode(p); + t3_link_start(&p->phy, mac, &p->link_config); + t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); + t3_port_intr_enable(adapter, p->port); + p->mac.stats.num_resets++; + } + PORT_UNLOCK(p); } } +static void +cxgb_tick(void *arg) +{ + adapter_t *sc = (adapter_t *)arg; + const struct adapter_params *p = &sc->params; + + if (p->linkpoll_period) + check_link_status(sc); + callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz, + cxgb_tick, sc); + + /* + * adapter lock can currently only be acquire after the + * port lock + */ + ADAPTER_UNLOCK(sc); + if (p->rev == T3_REV_B2) + check_t3b2_mac(sc); + +} + static int in_range(int val, int lo, int hi) { diff --git a/sys/dev/cxgb/cxgb_osdep.h b/sys/dev/cxgb/cxgb_osdep.h index a3c562c..83bb325 100644 --- a/sys/dev/cxgb/cxgb_osdep.h +++ b/sys/dev/cxgb/cxgb_osdep.h @@ -141,6 +141,8 @@ static const int debug_flags = DBG_RX; #define t3_os_sleep(x) DELAY((x) * 1000) +#define max_t(type, a, b) (type)max((a), (b)) + /* Standard PHY definitions */ #define BMCR_LOOPBACK BMCR_LOOP #define BMCR_ISOLATE BMCR_ISO |