From patchwork Fri Dec 2 14:06:16 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: sjur.brandeland@stericsson.com X-Patchwork-Id: 128866 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.180.67]) by ozlabs.org (Postfix) with ESMTP id CBFFAB6F75 for ; Sat, 3 Dec 2011 01:06:42 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756738Ab1LBOGd (ORCPT ); Fri, 2 Dec 2011 09:06:33 -0500 Received: from mail-bw0-f46.google.com ([209.85.214.46]:43571 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756695Ab1LBOGb (ORCPT ); Fri, 2 Dec 2011 09:06:31 -0500 Received: by bkas6 with SMTP id s6so3891539bka.19 for ; Fri, 02 Dec 2011 06:06:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=tIeHLgyLuQKGg2b6VZfeD65Hdvoa6v7ymm80k4AH0e8=; b=R+/+pTAMxfGio6cr1cKXRutNCejejP6VbsTNmiCsdRkTjeKJYK58lNxkYL/IQEFi/W wx4DYQuFlbpipfPO8v/HzUAiQB7MaUMUUxoTIQljAAE/9FeAuDIhBBTTBP2dnYnvA6P1 /R11Or61PsA5kPqQcqUimX7j8UQM+kOyMeFXg= Received: by 10.180.105.232 with SMTP id gp8mr4537648wib.65.1322834789616; Fri, 02 Dec 2011 06:06:29 -0800 (PST) Received: from localhost.localdomain ([212.4.57.94]) by mx.google.com with ESMTPS id u5sm3981183wbm.2.2011.12.02.06.06.28 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 02 Dec 2011 06:06:29 -0800 (PST) From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= To: netdev@vger.kernel.org Cc: David Miller , Alexey Orishko , =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Subject: [PATCH 2/3] caif: Add support for flow-control on device's tx-queue Date: Fri, 2 Dec 2011 15:06:16 +0100 Message-Id: <1322834777-2486-3-git-send-email-sjur.brandeland@stericsson.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1322834777-2486-1-git-send-email-sjur.brandeland@stericsson.com> References: <1322834777-2486-1-git-send-email-sjur.brandeland@stericsson.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Flow control is implemented by inspecting the qdisc queue length in order to detect potential overflow on the TX queue. When a threshold is reached flow-off is sent upwards in the CAIF stack. At the same time the skb->destructor is hi-jacked in order to detect when the last packet put on queue is consumed. When this "hi-jacked" packet is consumed, flow-on is sent upwards in the CAIF stack. Signed-off-by: Sjur Brændeland --- net/caif/caif_dev.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 48 insertions(+), 0 deletions(-) diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index f7e8c70..415353e 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -34,6 +34,7 @@ struct caif_device_entry { struct list_head list; struct net_device *netdev; int __percpu *pcpu_refcnt; + bool xoff; }; struct caif_device_entry_list { @@ -48,6 +49,7 @@ struct caif_net { }; static int caif_net_id; +static int q_high = 50; /* Percent */ struct cfcnfg *get_cfcnfg(struct net *net) { @@ -126,9 +128,28 @@ static struct caif_device_entry *caif_get(struct net_device *dev) return NULL; } +void caif_flow_cb(struct sk_buff *skb) +{ + struct caif_device_entry *caifd; + WARN_ON(skb->dev == NULL); + + rcu_read_lock(); + caifd = caif_get(skb->dev); + caifd->xoff = 0; + caifd_hold(caifd); + rcu_read_unlock(); + + caifd->layer.up-> + ctrlcmd(caifd->layer.up, + _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND, + caifd->layer.id); + caifd_put(caifd); +} + static int transmit(struct cflayer *layer, struct cfpkt *pkt) { int err; + struct caif_dev_common *caifdev; struct caif_device_entry *caifd = container_of(layer, struct caif_device_entry, layer); struct sk_buff *skb; @@ -137,6 +158,33 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) skb->dev = caifd->netdev; skb_reset_network_header(skb); skb->protocol = htons(ETH_P_CAIF); + caifdev = netdev_priv(caifd->netdev); + + if (caifdev->flowctrl == NULL && caifd->netdev->tx_queue_len > 0 && + !caifd->xoff) { + struct netdev_queue *txq; + int high; + + txq = netdev_get_tx_queue(skb->dev, 0); + high = (caifd->netdev->tx_queue_len * q_high) / 100; + + /* If we run with a TX queue, check if the queue is too long*/ + if (netif_queue_stopped(caifd->netdev) || + qdisc_qlen(txq->qdisc) > high) { + + pr_debug("queue stop(%d) or full (%d>%d) - XOFF\n", + netif_queue_stopped(caifd->netdev), + qdisc_qlen(txq->qdisc), high); + caifd->xoff = 1; + /* Hijack this skb free callback function. */ + skb_orphan(skb); + skb->destructor = caif_flow_cb; + caifd->layer.up-> + ctrlcmd(caifd->layer.up, + _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, + caifd->layer.id); + } + } err = dev_queue_xmit(skb); if (err > 0)