diff options
author | Divy Le Ray <divy@chelsio.com> | 2009-03-12 17:14:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-13 14:30:45 -0400 |
commit | fc88219601aa3f94def89433a6afde154e8faa8c (patch) | |
tree | 8c921807f947ba25c7ce188c9ec586aa57b0a0f9 | |
parent | 42c8ea17e8f78752ed5a354791b0ea1697dc3480 (diff) |
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>
-rw-r--r-- | drivers/net/cxgb3/cxgb3_main.c | 50 | ||||
-rw-r--r-- | drivers/net/cxgb3/regs.h | 8 | ||||
-rw-r--r-- | drivers/net/cxgb3/sge.c | 3 | ||||
-rw-r--r-- | drivers/net/cxgb3/t3_hw.c | 30 |
4 files changed, 86 insertions, 5 deletions
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index c32f514c41a7..9ff0452fcddd 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c | |||
@@ -2471,6 +2471,8 @@ static void t3_adap_check_task(struct work_struct *work) | |||
2471 | struct adapter *adapter = container_of(work, struct adapter, | 2471 | struct adapter *adapter = container_of(work, struct adapter, |
2472 | adap_check_task.work); | 2472 | adap_check_task.work); |
2473 | const struct adapter_params *p = &adapter->params; | 2473 | const struct adapter_params *p = &adapter->params; |
2474 | int port; | ||
2475 | unsigned int v, status, reset; | ||
2474 | 2476 | ||
2475 | adapter->check_task_cnt++; | 2477 | adapter->check_task_cnt++; |
2476 | 2478 | ||
@@ -2489,6 +2491,54 @@ static void t3_adap_check_task(struct work_struct *work) | |||
2489 | if (p->rev == T3_REV_B2) | 2491 | if (p->rev == T3_REV_B2) |
2490 | check_t3b2_mac(adapter); | 2492 | check_t3b2_mac(adapter); |
2491 | 2493 | ||
2494 | /* | ||
2495 | * Scan the XGMAC's to check for various conditions which we want to | ||
2496 | * monitor in a periodic polling manner rather than via an interrupt | ||
2497 | * condition. This is used for conditions which would otherwise flood | ||
2498 | * the system with interrupts and we only really need to know that the | ||
2499 | * conditions are "happening" ... For each condition we count the | ||
2500 | * detection of the condition and reset it for the next polling loop. | ||
2501 | */ | ||
2502 | for_each_port(adapter, port) { | ||
2503 | struct cmac *mac = &adap2pinfo(adapter, port)->mac; | ||
2504 | u32 cause; | ||
2505 | |||
2506 | cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset); | ||
2507 | reset = 0; | ||
2508 | if (cause & F_RXFIFO_OVERFLOW) { | ||
2509 | mac->stats.rx_fifo_ovfl++; | ||
2510 | reset |= F_RXFIFO_OVERFLOW; | ||
2511 | } | ||
2512 | |||
2513 | t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset); | ||
2514 | } | ||
2515 | |||
2516 | /* | ||
2517 | * We do the same as above for FL_EMPTY interrupts. | ||
2518 | */ | ||
2519 | status = t3_read_reg(adapter, A_SG_INT_CAUSE); | ||
2520 | reset = 0; | ||
2521 | |||
2522 | if (status & F_FLEMPTY) { | ||
2523 | struct sge_qset *qs = &adapter->sge.qs[0]; | ||
2524 | int i = 0; | ||
2525 | |||
2526 | reset |= F_FLEMPTY; | ||
2527 | |||
2528 | v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) & | ||
2529 | 0xffff; | ||
2530 | |||
2531 | while (v) { | ||
2532 | qs->fl[i].empty += (v & 1); | ||
2533 | if (i) | ||
2534 | qs++; | ||
2535 | i ^= 1; | ||
2536 | v >>= 1; | ||
2537 | } | ||
2538 | } | ||
2539 | |||
2540 | t3_write_reg(adapter, A_SG_INT_CAUSE, reset); | ||
2541 | |||
2492 | /* Schedule the next check update if any port is active. */ | 2542 | /* Schedule the next check update if any port is active. */ |
2493 | spin_lock_irq(&adapter->work_lock); | 2543 | spin_lock_irq(&adapter->work_lock); |
2494 | if (adapter->open_device_map & PORT_MASK) | 2544 | if (adapter->open_device_map & PORT_MASK) |
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index a035d5c24442..aa08550ee998 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h | |||
@@ -170,6 +170,10 @@ | |||
170 | 170 | ||
171 | #define S_RSPQ0DISABLED 8 | 171 | #define S_RSPQ0DISABLED 8 |
172 | 172 | ||
173 | #define S_FL0EMPTY 16 | ||
174 | #define V_FL0EMPTY(x) ((x) << S_FL0EMPTY) | ||
175 | #define F_FL0EMPTY V_FL0EMPTY(1U) | ||
176 | |||
173 | #define A_SG_EGR_RCQ_DRB_THRSH 0x54 | 177 | #define A_SG_EGR_RCQ_DRB_THRSH 0x54 |
174 | 178 | ||
175 | #define S_HIRCQDRBTHRSH 16 | 179 | #define S_HIRCQDRBTHRSH 16 |
@@ -258,6 +262,10 @@ | |||
258 | #define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) | 262 | #define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) |
259 | #define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) | 263 | #define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) |
260 | 264 | ||
265 | #define S_FLEMPTY 1 | ||
266 | #define V_FLEMPTY(x) ((x) << S_FLEMPTY) | ||
267 | #define F_FLEMPTY V_FLEMPTY(1U) | ||
268 | |||
261 | #define A_SG_INT_ENABLE 0x60 | 269 | #define A_SG_INT_ENABLE 0x60 |
262 | 270 | ||
263 | #define A_SG_CMDQ_CREDIT_TH 0x64 | 271 | #define A_SG_CMDQ_CREDIT_TH 0x64 |
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 7d779d18e137..a7555cb3fa4a 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c | |||
@@ -2725,7 +2725,8 @@ irq_handler_t t3_intr_handler(struct adapter *adap, int polling) | |||
2725 | */ | 2725 | */ |
2726 | void t3_sge_err_intr_handler(struct adapter *adapter) | 2726 | void t3_sge_err_intr_handler(struct adapter *adapter) |
2727 | { | 2727 | { |
2728 | unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE); | 2728 | unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) & |
2729 | ~F_FLEMPTY; | ||
2729 | 2730 | ||
2730 | if (status & SGE_PARERR) | 2731 | if (status & SGE_PARERR) |
2731 | CH_ALERT(adapter, "SGE parity error (0x%x)\n", | 2732 | CH_ALERT(adapter, "SGE parity error (0x%x)\n", |
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index ac2a974dfe37..7c6ee0c9b6fc 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c | |||
@@ -1323,7 +1323,7 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, | |||
1323 | #define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) | 1323 | #define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) |
1324 | #define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ | 1324 | #define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ |
1325 | V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ | 1325 | V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ |
1326 | F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW) | 1326 | F_TXFIFO_UNDERRUN) |
1327 | #define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ | 1327 | #define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ |
1328 | F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ | 1328 | F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ |
1329 | F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ | 1329 | F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ |
@@ -1695,7 +1695,14 @@ static void mc7_intr_handler(struct mc7 *mc7) | |||
1695 | static int mac_intr_handler(struct adapter *adap, unsigned int idx) | 1695 | static int mac_intr_handler(struct adapter *adap, unsigned int idx) |
1696 | { | 1696 | { |
1697 | struct cmac *mac = &adap2pinfo(adap, idx)->mac; | 1697 | struct cmac *mac = &adap2pinfo(adap, idx)->mac; |
1698 | u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); | 1698 | /* |
1699 | * We mask out interrupt causes for which we're not taking interrupts. | ||
1700 | * This allows us to use polling logic to monitor some of the other | ||
1701 | * conditions when taking interrupts would impose too much load on the | ||
1702 | * system. | ||
1703 | */ | ||
1704 | u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) & | ||
1705 | ~F_RXFIFO_OVERFLOW; | ||
1699 | 1706 | ||
1700 | if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { | 1707 | if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { |
1701 | mac->stats.tx_fifo_parity_err++; | 1708 | mac->stats.tx_fifo_parity_err++; |
@@ -3617,7 +3624,15 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, | |||
3617 | adapter->params.info = ai; | 3624 | adapter->params.info = ai; |
3618 | adapter->params.nports = ai->nports; | 3625 | adapter->params.nports = ai->nports; |
3619 | adapter->params.rev = t3_read_reg(adapter, A_PL_REV); | 3626 | adapter->params.rev = t3_read_reg(adapter, A_PL_REV); |
3620 | adapter->params.linkpoll_period = 0; | 3627 | /* |
3628 | * We used to only run the "adapter check task" once a second if | ||
3629 | * we had PHYs which didn't support interrupts (we would check | ||
3630 | * their link status once a second). Now we check other conditions | ||
3631 | * in that routine which could potentially impose a very high | ||
3632 | * interrupt load on the system. As such, we now always scan the | ||
3633 | * adapter state once a second ... | ||
3634 | */ | ||
3635 | adapter->params.linkpoll_period = 10; | ||
3621 | adapter->params.stats_update_period = is_10G(adapter) ? | 3636 | adapter->params.stats_update_period = is_10G(adapter) ? |
3622 | MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); | 3637 | MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); |
3623 | adapter->params.pci.vpd_cap_addr = | 3638 | adapter->params.pci.vpd_cap_addr = |
@@ -3707,7 +3722,14 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, | |||
3707 | ETH_ALEN); | 3722 | ETH_ALEN); |
3708 | init_link_config(&p->link_config, p->phy.caps); | 3723 | init_link_config(&p->link_config, p->phy.caps); |
3709 | p->phy.ops->power_down(&p->phy, 1); | 3724 | p->phy.ops->power_down(&p->phy, 1); |
3710 | if (!(p->phy.caps & SUPPORTED_IRQ)) | 3725 | |
3726 | /* | ||
3727 | * If the PHY doesn't support interrupts for link status | ||
3728 | * changes, schedule a scan of the adapter links at least | ||
3729 | * once a second. | ||
3730 | */ | ||
3731 | if (!(p->phy.caps & SUPPORTED_IRQ) && | ||
3732 | adapter->params.linkpoll_period > 10) | ||
3711 | adapter->params.linkpoll_period = 10; | 3733 | adapter->params.linkpoll_period = 10; |
3712 | } | 3734 | } |
3713 | 3735 | ||