Revamp interrupt handling in em(4) driver:

o Do not mask the RX overrun interrupt.

o Rewrite em_intr():
  - Axe EM_MAX_INTR.
  - Cycle acknowledging interrupts and processing
    packets until zero interrupt cause register is
    read.
  - If RX overrun comes in log this fact. [ NetBSD also
    resets adapter in this case, but my tests showed that
    this is not needed and only pessimizes behavior under
    heavy load. ]
  - Since almost all functions is rewritten, style the
    remaining lines.

This fixes em(4) interfaces wedging under high load.

In collaboration with:	wpaul, cognet
Obtained from:		NetBSD
This commit is contained in:
Gleb Smirnoff 2005-10-20 08:46:43 +00:00
parent 22b1904845
commit 5422f907d4
3 changed files with 39 additions and 39 deletions

View File

@ -985,51 +985,57 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
static void
em_intr(void *arg)
{
u_int32_t loop_cnt = EM_MAX_INTR;
u_int32_t reg_icr;
struct ifnet *ifp;
struct adapter *adapter = arg;
struct adapter *adapter = arg;
struct ifnet *ifp;
uint32_t reg_icr;
int wantinit = 0;
EM_LOCK(adapter);
ifp = adapter->ifp;
ifp = adapter->ifp;
#ifdef DEVICE_POLLING
if (ifp->if_capenable & IFCAP_POLLING) {
if (ifp->if_capenable & IFCAP_POLLING) {
EM_UNLOCK(adapter);
return;
return;
}
#endif /* DEVICE_POLLING */
reg_icr = E1000_READ_REG(&adapter->hw, ICR);
if (!reg_icr) {
EM_UNLOCK(adapter);
return;
}
for (;;) {
reg_icr = E1000_READ_REG(&adapter->hw, ICR);
if (reg_icr == 0)
break;
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
callout_stop(&adapter->timer);
adapter->hw.get_link_status = 1;
em_check_for_link(&adapter->hw);
em_print_link_status(adapter);
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
}
while (loop_cnt > 0) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
em_process_receive_interrupts(adapter, -1);
em_clean_transmit_interrupts(adapter);
}
loop_cnt--;
}
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
em_process_receive_interrupts(adapter, -1);
em_clean_transmit_interrupts(adapter);
}
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
/* Link status change */
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
callout_stop(&adapter->timer);
adapter->hw.get_link_status = 1;
em_check_for_link(&adapter->hw);
em_print_link_status(adapter);
callout_reset(&adapter->timer, hz, em_local_timer,
adapter);
}
if (reg_icr & E1000_ICR_RXO) {
log(LOG_WARNING, "%s: RX overrun\n", ifp->if_xname);
wantinit = 1;
}
}
#if 0
if (wantinit)
em_init_locked(adapter);
#endif
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp);
em_start_locked(ifp);
EM_UNLOCK(adapter);
return;
return;
}

View File

@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/module.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/if_arp.h>
@ -163,14 +164,6 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#define EM_RADV 64
/*
* This parameter controls the maximum no of times the driver will loop
* in the isr.
* Minimum Value = 1
*/
#define EM_MAX_INTR 3
/*
* Inform the stack about transmit checksum offload capabilities.
*/

View File

@ -556,6 +556,7 @@ uint8_t em_arc_subsystem_valid(struct em_hw *hw);
E1000_IMS_TXDW | \
E1000_IMS_RXDMT0 | \
E1000_IMS_RXSEQ | \
E1000_IMS_RXO | \
E1000_IMS_LSC)