Index: sys/dev/ixgbe/if_ix.c =================================================================== --- sys/dev/ixgbe/if_ix.c +++ sys/dev/ixgbe/if_ix.c @@ -347,6 +347,16 @@ SYSCTL_INT(_hw_ix, OID_AUTO, enable_rss, CTLFLAG_RDTUN, &ixgbe_enable_rss, 0, "Enable Receive-Side Scaling (RSS)"); +/* + * AIM: Adaptive Interrupt Moderation + * which means that the interrupt rate + * is varied over time based on the + * traffic for that interrupt vector + */ +static int ixgbe_enable_aim = FALSE; +SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, + "Enable adaptive interrupt moderation"); + #if 0 /* Keep running tab on them for sanity check */ static int ixgbe_total_ports; @@ -2094,6 +2104,8 @@ struct ix_rx_queue *que = arg; struct adapter *adapter = que->adapter; struct ifnet *ifp = iflib_get_ifp(que->adapter->ctx); + uint32_t newitr = 0; + struct rx_ring *rxr = &que->rxr; /* Protect against spurious interrupts */ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) @@ -2102,6 +2114,56 @@ ixgbe_disable_queue(adapter, que->msix); ++que->irqs; + /* Check for AIM */ + if (adapter->enable_aim == FALSE) { + goto no_calc; + } + /* + * Do Adaptive Interrupt Moderation: + * - Write out last calculated setting + * - Calculate based on average size over + * the last interval. + */ + if (que->eitr_setting) { + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(que->msix), + que->eitr_setting); + } + + que->eitr_setting = 0; + /* Idle, do nothing */ + if (rxr->bytes == 0) { + goto no_calc; + } + + if ((rxr->bytes) && (rxr->packets)) { + newitr = max(newitr, (rxr->bytes / rxr->packets)); + } + + newitr += 24; /* account for hardware frame, crc */ + /* set an upper boundary */ + newitr = min(newitr, 3000); + + /* Be nice to the mid range */ + if ((newitr > 300) && (newitr < 1200)) { + newitr = (newitr / 3); + } else { + newitr = (newitr / 2); + } + + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + newitr |= newitr << 16; + } else { + newitr |= IXGBE_EITR_CNT_WDIS; + } + + /* save for next interrupt */ + que->eitr_setting = newitr; + + /* Reset state */ + rxr->bytes = 0; + rxr->packets = 0; + +no_calc: return (FILTER_SCHEDULE_THREAD); } /* ixgbe_msix_que */ @@ -2560,6 +2622,10 @@ adapter, 0, ixgbe_sysctl_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); + adapter->enable_aim = ixgbe_enable_aim; + SYSCTL_ADD_INT(ctx_list, child, OID_AUTO, "enable_aim", CTLFLAG_RW, + &adapter->enable_aim, 0, "Interrupt Moderation"); + #ifdef IXGBE_DEBUG /* testing sysctls (for all devices) */ SYSCTL_ADD_PROC(ctx_list, child, OID_AUTO, "power_state", Index: sys/dev/ixgbe/ixgbe.h =================================================================== --- sys/dev/ixgbe/ixgbe.h +++ sys/dev/ixgbe/ixgbe.h @@ -408,6 +408,7 @@ /* Info about the interface */ int advertise; /* link speeds */ + int enable_aim; /* adaptive interrupt moderation */ bool link_active; u16 num_segs; u32 link_speed;