summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkmacy <kmacy@FreeBSD.org>2007-03-20 21:43:32 +0000
committerkmacy <kmacy@FreeBSD.org>2007-03-20 21:43:32 +0000
commitfebce07b1841a6b5680a436c04a0e6ea67af094a (patch)
tree902f132b95a6b5c1b94654d87f196a5f8c9da24b /sys
parent9c3aae940304a96fc50dbe9e3e92f5f783d3bf03 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/cxgb/common/cxgb_common.h35
-rw-r--r--sys/dev/cxgb/common/cxgb_regs.h4
-rw-r--r--sys/dev/cxgb/common/cxgb_t3_hw.c150
-rw-r--r--sys/dev/cxgb/common/cxgb_version.h8
-rw-r--r--sys/dev/cxgb/common/cxgb_xgmac.c130
-rw-r--r--sys/dev/cxgb/cxgb_adapter.h1
-rw-r--r--sys/dev/cxgb/cxgb_config.h2
-rw-r--r--sys/dev/cxgb/cxgb_ioctl.h12
-rw-r--r--sys/dev/cxgb/cxgb_main.c76
-rw-r--r--sys/dev/cxgb/cxgb_osdep.h2
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
OpenPOWER on IntegriCloud