cxgb3: disable high freq non-data interrupts
Under RX pressure, The HW might generate a high load of interrupts to signal mac fifo or free lists overflow. Disable the interrupts, and poll the relevant status bits to maintain stats. Signed-off-by: Divy Le Ray <divy@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
42c8ea17e8
commit
fc88219601
@ -2471,6 +2471,8 @@ static void t3_adap_check_task(struct work_struct *work)
|
|||||||
struct adapter *adapter = container_of(work, struct adapter,
|
struct adapter *adapter = container_of(work, struct adapter,
|
||||||
adap_check_task.work);
|
adap_check_task.work);
|
||||||
const struct adapter_params *p = &adapter->params;
|
const struct adapter_params *p = &adapter->params;
|
||||||
|
int port;
|
||||||
|
unsigned int v, status, reset;
|
||||||
|
|
||||||
adapter->check_task_cnt++;
|
adapter->check_task_cnt++;
|
||||||
|
|
||||||
@ -2489,6 +2491,54 @@ static void t3_adap_check_task(struct work_struct *work)
|
|||||||
if (p->rev == T3_REV_B2)
|
if (p->rev == T3_REV_B2)
|
||||||
check_t3b2_mac(adapter);
|
check_t3b2_mac(adapter);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan the XGMAC's to check for various conditions which we want to
|
||||||
|
* monitor in a periodic polling manner rather than via an interrupt
|
||||||
|
* condition. This is used for conditions which would otherwise flood
|
||||||
|
* the system with interrupts and we only really need to know that the
|
||||||
|
* conditions are "happening" ... For each condition we count the
|
||||||
|
* detection of the condition and reset it for the next polling loop.
|
||||||
|
*/
|
||||||
|
for_each_port(adapter, port) {
|
||||||
|
struct cmac *mac = &adap2pinfo(adapter, port)->mac;
|
||||||
|
u32 cause;
|
||||||
|
|
||||||
|
cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
|
||||||
|
reset = 0;
|
||||||
|
if (cause & F_RXFIFO_OVERFLOW) {
|
||||||
|
mac->stats.rx_fifo_ovfl++;
|
||||||
|
reset |= F_RXFIFO_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do the same as above for FL_EMPTY interrupts.
|
||||||
|
*/
|
||||||
|
status = t3_read_reg(adapter, A_SG_INT_CAUSE);
|
||||||
|
reset = 0;
|
||||||
|
|
||||||
|
if (status & F_FLEMPTY) {
|
||||||
|
struct sge_qset *qs = &adapter->sge.qs[0];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
reset |= F_FLEMPTY;
|
||||||
|
|
||||||
|
v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
|
||||||
|
0xffff;
|
||||||
|
|
||||||
|
while (v) {
|
||||||
|
qs->fl[i].empty += (v & 1);
|
||||||
|
if (i)
|
||||||
|
qs++;
|
||||||
|
i ^= 1;
|
||||||
|
v >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
|
||||||
|
|
||||||
/* Schedule the next check update if any port is active. */
|
/* Schedule the next check update if any port is active. */
|
||||||
spin_lock_irq(&adapter->work_lock);
|
spin_lock_irq(&adapter->work_lock);
|
||||||
if (adapter->open_device_map & PORT_MASK)
|
if (adapter->open_device_map & PORT_MASK)
|
||||||
|
@ -170,6 +170,10 @@
|
|||||||
|
|
||||||
#define S_RSPQ0DISABLED 8
|
#define S_RSPQ0DISABLED 8
|
||||||
|
|
||||||
|
#define S_FL0EMPTY 16
|
||||||
|
#define V_FL0EMPTY(x) ((x) << S_FL0EMPTY)
|
||||||
|
#define F_FL0EMPTY V_FL0EMPTY(1U)
|
||||||
|
|
||||||
#define A_SG_EGR_RCQ_DRB_THRSH 0x54
|
#define A_SG_EGR_RCQ_DRB_THRSH 0x54
|
||||||
|
|
||||||
#define S_HIRCQDRBTHRSH 16
|
#define S_HIRCQDRBTHRSH 16
|
||||||
@ -258,6 +262,10 @@
|
|||||||
#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
|
#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
|
||||||
#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U)
|
#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U)
|
||||||
|
|
||||||
|
#define S_FLEMPTY 1
|
||||||
|
#define V_FLEMPTY(x) ((x) << S_FLEMPTY)
|
||||||
|
#define F_FLEMPTY V_FLEMPTY(1U)
|
||||||
|
|
||||||
#define A_SG_INT_ENABLE 0x60
|
#define A_SG_INT_ENABLE 0x60
|
||||||
|
|
||||||
#define A_SG_CMDQ_CREDIT_TH 0x64
|
#define A_SG_CMDQ_CREDIT_TH 0x64
|
||||||
|
@ -2725,7 +2725,8 @@ irq_handler_t t3_intr_handler(struct adapter *adap, int polling)
|
|||||||
*/
|
*/
|
||||||
void t3_sge_err_intr_handler(struct adapter *adapter)
|
void t3_sge_err_intr_handler(struct adapter *adapter)
|
||||||
{
|
{
|
||||||
unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
|
unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) &
|
||||||
|
~F_FLEMPTY;
|
||||||
|
|
||||||
if (status & SGE_PARERR)
|
if (status & SGE_PARERR)
|
||||||
CH_ALERT(adapter, "SGE parity error (0x%x)\n",
|
CH_ALERT(adapter, "SGE parity error (0x%x)\n",
|
||||||
|
@ -1323,7 +1323,7 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
|
|||||||
#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
|
#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
|
||||||
#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
|
#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
|
||||||
V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
|
V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
|
||||||
F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
|
F_TXFIFO_UNDERRUN)
|
||||||
#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
|
#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
|
||||||
F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
|
F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
|
||||||
F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
|
F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
|
||||||
@ -1695,7 +1695,14 @@ static void mc7_intr_handler(struct mc7 *mc7)
|
|||||||
static int mac_intr_handler(struct adapter *adap, unsigned int idx)
|
static int mac_intr_handler(struct adapter *adap, unsigned int idx)
|
||||||
{
|
{
|
||||||
struct cmac *mac = &adap2pinfo(adap, idx)->mac;
|
struct cmac *mac = &adap2pinfo(adap, idx)->mac;
|
||||||
u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
|
/*
|
||||||
|
* We mask out interrupt causes for which we're not taking interrupts.
|
||||||
|
* This allows us to use polling logic to monitor some of the other
|
||||||
|
* conditions when taking interrupts would impose too much load on the
|
||||||
|
* system.
|
||||||
|
*/
|
||||||
|
u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) &
|
||||||
|
~F_RXFIFO_OVERFLOW;
|
||||||
|
|
||||||
if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
|
if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
|
||||||
mac->stats.tx_fifo_parity_err++;
|
mac->stats.tx_fifo_parity_err++;
|
||||||
@ -3617,7 +3624,15 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
|||||||
adapter->params.info = ai;
|
adapter->params.info = ai;
|
||||||
adapter->params.nports = ai->nports;
|
adapter->params.nports = ai->nports;
|
||||||
adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
|
adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
|
||||||
adapter->params.linkpoll_period = 0;
|
/*
|
||||||
|
* We used to only run the "adapter check task" once a second if
|
||||||
|
* we had PHYs which didn't support interrupts (we would check
|
||||||
|
* their link status once a second). Now we check other conditions
|
||||||
|
* in that routine which could potentially impose a very high
|
||||||
|
* interrupt load on the system. As such, we now always scan the
|
||||||
|
* adapter state once a second ...
|
||||||
|
*/
|
||||||
|
adapter->params.linkpoll_period = 10;
|
||||||
adapter->params.stats_update_period = is_10G(adapter) ?
|
adapter->params.stats_update_period = is_10G(adapter) ?
|
||||||
MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
|
MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
|
||||||
adapter->params.pci.vpd_cap_addr =
|
adapter->params.pci.vpd_cap_addr =
|
||||||
@ -3707,7 +3722,14 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
|||||||
ETH_ALEN);
|
ETH_ALEN);
|
||||||
init_link_config(&p->link_config, p->phy.caps);
|
init_link_config(&p->link_config, p->phy.caps);
|
||||||
p->phy.ops->power_down(&p->phy, 1);
|
p->phy.ops->power_down(&p->phy, 1);
|
||||||
if (!(p->phy.caps & SUPPORTED_IRQ))
|
|
||||||
|
/*
|
||||||
|
* If the PHY doesn't support interrupts for link status
|
||||||
|
* changes, schedule a scan of the adapter links at least
|
||||||
|
* once a second.
|
||||||
|
*/
|
||||||
|
if (!(p->phy.caps & SUPPORTED_IRQ) &&
|
||||||
|
adapter->params.linkpoll_period > 10)
|
||||||
adapter->params.linkpoll_period = 10;
|
adapter->params.linkpoll_period = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user