From patchwork Mon Nov 23 14:31:08 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Kagstrom X-Patchwork-Id: 39053 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 40484B6F29 for ; Tue, 24 Nov 2009 01:31:24 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753340AbZKWObM (ORCPT ); Mon, 23 Nov 2009 09:31:12 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753048AbZKWObM (ORCPT ); Mon, 23 Nov 2009 09:31:12 -0500 Received: from ernst.netinsight.se ([194.16.221.21]:36016 "HELO ernst.netinsight.se" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1751649AbZKWObL (ORCPT ); Mon, 23 Nov 2009 09:31:11 -0500 Received: from marrow.netinsight.se (unverified [10.100.3.78]) by ernst.netinsight.se (EMWAC SMTPRS 0.83) with SMTP id ; Mon, 23 Nov 2009 15:31:06 +0100 Date: Mon, 23 Nov 2009 15:31:08 +0100 From: Simon Kagstrom To: netdev@vger.kernel.org Cc: davem@davemloft.net, davej@redhat.com, shemminger@vyatta.com, romieu@fr.zoreil.com Subject: [PATCH v2 2/7] via-velocity: Add ethtool interrupt coalescing support Message-ID: <20091123153108.48be06b0@marrow.netinsight.se> In-Reply-To: <20091123152724.2871cf4d@marrow.netinsight.se> References: <20091120160633.77b7aee0@marrow.netinsight.se> <20091123152724.2871cf4d@marrow.netinsight.se> X-Mailer: Claws Mail 3.7.3 (GTK+ 2.16.1; i486-pc-linux-gnu) Mime-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org (Partially from the upstream VIA driver). Tweaking the number of frames-per-interrupt and timer-until-interrupt can reduce the amount of CPU work quite a lot. Signed-off-by: Simon Kagstrom --- drivers/net/via-velocity.c | 160 +++++++++++++++++++++++++++++++++++++++++++- drivers/net/via-velocity.h | 7 ++- 2 files changed, 165 insertions(+), 2 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index b6cf3b5..85ee898 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1259,6 +1259,66 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) } } +/** + * setup_queue_timers - Setup interrupt timers + * + * Setup interrupt frequency during suppression (timeout if the frame + * count isn't filled). + */ +static void setup_queue_timers(struct velocity_info *vptr) +{ + /* Only for newer revisions */ + if (vptr->rev_id >= REV_ID_VT3216_A0) { + u8 txqueue_timer = 0; + u8 rxqueue_timer = 0; + + if (vptr->mii_status & (VELOCITY_SPEED_1000 | + VELOCITY_SPEED_100)) { + txqueue_timer = vptr->options.txqueue_timer; + rxqueue_timer = vptr->options.rxqueue_timer; + } + + writeb(txqueue_timer, &vptr->mac_regs->TQETMR); + writeb(rxqueue_timer, &vptr->mac_regs->RQETMR); + } +} +/** + * setup_adaptive_interrupts - Setup interrupt suppression + * + * @vptr velocity adapter + * + * The velocity is able to suppress interrupt during high interrupt load. + * This function turns on that feature. + */ +static void setup_adaptive_interrupts(struct velocity_info *vptr) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + u16 tx_intsup = vptr->options.tx_intsup; + u16 rx_intsup = vptr->options.rx_intsup; + + /* Setup default interrupt mask (will be changed below) */ + vptr->int_mask = INT_MASK_DEF; + + /* Set Tx Interrupt Suppression Threshold */ + writeb(CAMCR_PS0, ®s->CAMCR); + if (tx_intsup != 0) { + vptr->int_mask &= ~(ISR_PTXI | ISR_PTX0I | ISR_PTX1I | + ISR_PTX2I | ISR_PTX3I); + writew(tx_intsup, ®s->ISRCTL); + } else + writew(ISRCTL_TSUPDIS, ®s->ISRCTL); + + /* Set Rx Interrupt Suppression Threshold */ + writeb(CAMCR_PS1, ®s->CAMCR); + if (rx_intsup != 0) { + vptr->int_mask &= ~ISR_PRXI; + writew(rx_intsup, ®s->ISRCTL); + } else + writew(ISRCTL_RSUPDIS, ®s->ISRCTL); + + /* Select page to interrupt hold timer */ + writeb(0, ®s->CAMCR); +} /** * velocity_init_registers - initialise MAC registers @@ -1345,7 +1405,7 @@ static void velocity_init_registers(struct velocity_info *vptr, */ enable_mii_autopoll(regs); - vptr->int_mask = INT_MASK_DEF; + setup_adaptive_interrupts(vptr); writel(vptr->rx.pool_dma, ®s->RDBaseLo); writew(vptr->options.numrx - 1, ®s->RDCSize); @@ -1802,6 +1862,8 @@ static void velocity_error(struct velocity_info *vptr, int status) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + + setup_queue_timers(vptr); } /* * Get link status from PHYSR0 @@ -3223,6 +3285,100 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value) msglevel = value; } +static int get_pending_timer_val(int val) +{ + int mult_bits = val >> 6; + int mult = 1; + + switch (mult_bits) + { + case 1: + mult = 4; break; + case 2: + mult = 16; break; + case 3: + mult = 64; break; + case 0: + default: + break; + } + + return (val & 0x3f) * mult; +} + +static void set_pending_timer_val(int *val, u32 us) +{ + u8 mult = 0; + u8 shift = 0; + + if (us >= 0x3f) { + mult = 1; /* mult with 4 */ + shift = 2; + } + if (us >= 0x3f * 4) { + mult = 2; /* mult with 16 */ + shift = 4; + } + if (us >= 0x3f * 16) { + mult = 3; /* mult with 64 */ + shift = 6; + } + + *val = (mult << 6) | ((us >> shift) & 0x3f); +} + + +static int velocity_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ecmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + + ecmd->tx_max_coalesced_frames = vptr->options.tx_intsup; + ecmd->rx_max_coalesced_frames = vptr->options.rx_intsup; + + ecmd->rx_coalesce_usecs = get_pending_timer_val(vptr->options.rxqueue_timer); + ecmd->tx_coalesce_usecs = get_pending_timer_val(vptr->options.txqueue_timer); + + return 0; +} + +static int velocity_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ecmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + int max_us = 0x3f * 64; + + /* 6 bits of */ + if (ecmd->tx_coalesce_usecs > max_us) + return -EINVAL; + if (ecmd->rx_coalesce_usecs > max_us) + return -EINVAL; + + if (ecmd->tx_max_coalesced_frames > 0xff) + return -EINVAL; + if (ecmd->rx_max_coalesced_frames > 0xff) + return -EINVAL; + + vptr->options.rx_intsup = ecmd->rx_max_coalesced_frames; + vptr->options.tx_intsup = ecmd->tx_max_coalesced_frames; + + set_pending_timer_val(&vptr->options.rxqueue_timer, + ecmd->rx_coalesce_usecs); + set_pending_timer_val(&vptr->options.txqueue_timer, + ecmd->tx_coalesce_usecs); + + /* Setup the interrupt suppression and queue timers */ + mac_disable_int(vptr->mac_regs); + setup_adaptive_interrupts(vptr); + setup_queue_timers(vptr); + + mac_write_int_mask(vptr->int_mask, vptr->mac_regs); + mac_clear_isr(vptr->mac_regs); + mac_enable_int(vptr->mac_regs); + + return 0; +} + static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, @@ -3232,6 +3388,8 @@ static const struct ethtool_ops velocity_ethtool_ops = { .get_msglevel = velocity_get_msglevel, .set_msglevel = velocity_set_msglevel, .get_link = velocity_get_link, + .get_coalesce = velocity_get_coalesce, + .set_coalesce = velocity_set_coalesce, .begin = velocity_ethtool_up, .complete = velocity_ethtool_down }; diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index 2f00c13..6091946 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -1005,7 +1005,8 @@ struct mac_regs { volatile __le32 RDBaseLo; /* 0x38 */ volatile __le16 RDIdx; /* 0x3C */ - volatile __le16 reserved_3E; + volatile u8 TQETMR; /* 0x3E, VT3216 and above only */ + volatile u8 RQETMR; /* 0x3F, VT3216 and above only */ volatile __le32 TDBaseLo[4]; /* 0x40 */ @@ -1491,6 +1492,10 @@ struct velocity_opt { int rx_bandwidth_hi; int rx_bandwidth_lo; int rx_bandwidth_en; + int rxqueue_timer; + int txqueue_timer; + int tx_intsup; + int rx_intsup; u32 flags; };