From patchwork Fri May 19 09:06:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xinming Hu X-Patchwork-Id: 9736701 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 329D3601C2 for ; Fri, 19 May 2017 09:07:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 21932288C4 for ; Fri, 19 May 2017 09:07:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1608C288EC; Fri, 19 May 2017 09:07:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4051A288D2 for ; Fri, 19 May 2017 09:07:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753495AbdESJHI (ORCPT ); Fri, 19 May 2017 05:07:08 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:36762 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755836AbdESJHF (ORCPT ); Fri, 19 May 2017 05:07:05 -0400 Received: by mail-pg0-f65.google.com with SMTP id h64so9105763pge.3 for ; Fri, 19 May 2017 02:06:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lD9UdU1DWKR5B8266Sw3fEkcvzu7BUPBtYH+UkRvuu8=; b=mqfm/NBfTp+PuuQcXSSCoO27Ril71y8O6dK1evIIjy0U6SYSZ3xju/R5A6/ZQPwhky pGWTVLBziJWAqxLGMg+tGArJDBIQerDbDpcb3NZ6NRwBtTFWgfs6/ibnuhgc5d78FMox CdUI6JyYvt6+psOhHxu854MPeye5uQzi3rcHB0fXU3yqEheKwS8Bks8qLowR5K+k0Pym FdE7kv99DXpleXBWb9QNbyTh8LrTrR38k9OKWqdSag4u3OOdSX8jJD3+CSVvyC5cVZyo 0vyiMn4UhcWPfPVWP/vPMejibxyEWE0pbN/c6b1fcZZFDkDHhx6vKeBPqO+1I5G4HESU eQOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=lD9UdU1DWKR5B8266Sw3fEkcvzu7BUPBtYH+UkRvuu8=; b=GLUzb/z1TSJU387iZbIngXkSGuk2gy35qJT5QtMmM1U4CJrN1T6uMXIxiQPTPuvcMV Y+/J2mtppcRTDqHHgEM3XTnqNsahW3Pm03qgmzI3jh30J/6SEKXnhkXo9HtqjXpXuhjs mS3lK59kGNO7XZYrep+iMP6JsQE5T17yKuvj7wQZo4DC0nTmM4NfMZDvcQ0LL+6VDgt6 KVJ2GOu6B+UGkf5hAmEoAEzKCTsT6jZ27W4vUsKZxcy3G5GVuXKiIeuEbgmV5BOprBS4 zqzpeL1a3F+KDZVJNtfzb3kBs30GdALK+bVSC8QWDvGPdL4O7GoI8pqZrCdcettcTcNG 8tKA== X-Gm-Message-State: AODbwcDXm+JfXdabIWT+omrweunHFJLsQqHOzecg3hjvPnJCf2zAB/a7 ySQpB12Ee7YMLg== X-Received: by 10.84.231.16 with SMTP id f16mr10406511plk.20.1495184819360; Fri, 19 May 2017 02:06:59 -0700 (PDT) Received: from ubuntu.members.linode.com ([2400:8902::f03c:91ff:fee7:7cf1]) by smtp.gmail.com with ESMTPSA id d6sm14558201pfk.90.2017.05.19.02.06.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 19 May 2017 02:06:58 -0700 (PDT) From: Xinming Hu To: Linux Wireless Cc: Kalle Valo , Brian Norris , Dmitry Torokhov , rajatja@google.com, Zhiyuan Yang , Cathy Luo , Xinming Hu , Ganapathi Bhat Subject: [PATCH v3 4/6] mwifiex: usb: add timer to flush aggregation packets Date: Fri, 19 May 2017 09:06:43 +0000 Message-Id: <1495184805-6631-4-git-send-email-huxinming820@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1495184805-6631-1-git-send-email-huxinming820@gmail.com> References: <1495184805-6631-1-git-send-email-huxinming820@gmail.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Xinming Hu Aggregation will wait for next packet until limit aggr size/number reach. Packet might be drop and also packet dequeue will be stop in some cases. This patch add timer to flush packets in aggregation list to avoid long time waiting. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat --- v3: same as v1,v2 --- drivers/net/wireless/marvell/mwifiex/usb.c | 258 ++++++++++++++++++++--------- drivers/net/wireless/marvell/mwifiex/usb.h | 14 ++ 2 files changed, 193 insertions(+), 79 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index e13f758d..f230017 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -662,76 +662,6 @@ static void mwifiex_usb_disconnect(struct usb_interface *intf) .soft_unbind = 1, }; -static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - struct usb_tx_data_port *port; - int i, j; - - card->tx_cmd.adapter = adapter; - card->tx_cmd.ep = card->tx_cmd_ep; - - card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->tx_cmd.urb) - return -ENOMEM; - - for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { - port = &card->port[i]; - if (!port->tx_data_ep) - continue; - port->tx_data_ix = 0; - skb_queue_head_init(&port->tx_aggr.aggr_list); - if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) - port->block_status = false; - else - port->block_status = true; - for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { - port->tx_data_list[j].adapter = adapter; - port->tx_data_list[j].ep = port->tx_data_ep; - port->tx_data_list[j].urb = - usb_alloc_urb(0, GFP_KERNEL); - if (!port->tx_data_list[j].urb) - return -ENOMEM; - } - } - - return 0; -} - -static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) -{ - struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - int i; - - card->rx_cmd.adapter = adapter; - card->rx_cmd.ep = card->rx_cmd_ep; - - card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_cmd.urb) - return -ENOMEM; - - card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); - if (!card->rx_cmd.skb) - return -ENOMEM; - - if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) - return -1; - - for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { - card->rx_data_list[i].adapter = adapter; - card->rx_data_list[i].ep = card->rx_data_ep; - - card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); - if (!card->rx_data_list[i].urb) - return -1; - if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], - MWIFIEX_RX_DATA_BUF_SIZE)) - return -1; - } - - return 0; -} - static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, u32 *len, u8 ep, u32 timeout) { @@ -918,6 +848,15 @@ static int mwifiex_usb_prepare_tx_aggr_skb(struct mwifiex_adapter *adapter, struct mwifiex_txinfo *tx_info = NULL; bool is_txinfo_set = false; + /* Packets in aggr_list will be send in either skb_aggr or + * write complete, delete the tx_aggr timer + */ + if (port->tx_aggr.timer_cnxt.is_hold_timer_set) { + del_timer(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + } + skb_aggr = mwifiex_alloc_dma_align_buf(port->tx_aggr.aggr_len, GFP_ATOMIC); if (!skb_aggr) { @@ -999,6 +938,7 @@ static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, u8 f_send_cur_buf = 0; u8 f_precopy_cur_buf = 0; u8 f_postcopy_cur_buf = 0; + u32 timeout; int ret; /* padding to ensure each packet alginment */ @@ -1069,8 +1009,35 @@ static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, skb_queue_tail(&port->tx_aggr.aggr_list, skb); port->tx_aggr.aggr_len += (skb->len + pad); port->tx_aggr.aggr_num++; + if (f_send_aggr_buf) + goto send_aggr_buf; + + /* packet will not been send immediately, + * set a timer to make sure it will be sent under + * strict time limit. Dynamically fit the timeout + * value, according to packets number in aggr_list + */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = + port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } else { + if (port->tx_aggr.timer_cnxt.hold_tmo_msecs < + MWIFIEX_USB_TX_AGGR_TMO_MAX) { + /* Dyanmic fit timeout */ + timeout = + ++port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + } + } } +send_aggr_buf: if (f_send_aggr_buf) { ret = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); if (!ret) { @@ -1114,11 +1081,60 @@ static int mwifiex_usb_aggr_tx_data(struct mwifiex_adapter *adapter, u8 ep, skb_queue_tail(&port->tx_aggr.aggr_list, skb); port->tx_aggr.aggr_len += (skb->len + pad); port->tx_aggr.aggr_num++; + /* New aggregation begin, start timer */ + if (!port->tx_aggr.timer_cnxt.is_hold_timer_set) { + port->tx_aggr.timer_cnxt.hold_tmo_msecs = + MWIFIEX_USB_TX_AGGR_TMO_MIN; + timeout = port->tx_aggr.timer_cnxt.hold_tmo_msecs; + mod_timer(&port->tx_aggr.timer_cnxt.hold_timer, + jiffies + msecs_to_jiffies(timeout)); + port->tx_aggr.timer_cnxt.is_hold_timer_set = true; + } } return -EINPROGRESS; } +static void mwifiex_usb_tx_aggr_tmo(unsigned long context) +{ + struct urb_context *urb_cnxt = NULL; + struct sk_buff *skb_send = NULL; + struct tx_aggr_tmr_cnxt *timer_context = + (struct tx_aggr_tmr_cnxt *)context; + struct mwifiex_adapter *adapter = timer_context->adapter; + struct usb_tx_data_port *port = timer_context->port; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&port->tx_aggr_lock, flags); + err = mwifiex_usb_prepare_tx_aggr_skb(adapter, port, &skb_send); + if (err) { + mwifiex_dbg(adapter, ERROR, + "prepare tx aggr skb failed, err=%d\n", err); + return; + } + + if (atomic_read(&port->tx_data_urb_pending) >= + MWIFIEX_TX_DATA_URB) { + port->block_status = true; + adapter->data_sent = + mwifiex_usb_data_sent(adapter); + err = -1; + goto done; + } + + if (port->tx_data_ix >= MWIFIEX_TX_DATA_URB) + port->tx_data_ix = 0; + + urb_cnxt = &port->tx_data_list[port->tx_data_ix++]; + err = mwifiex_usb_construct_send_urb(adapter, port, port->tx_data_ep, + urb_cnxt, skb_send); +done: + if (err == -1) + mwifiex_write_data_complete(adapter, skb_send, 0, -1); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); +} + /* This function write a command/data packet to card. */ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct sk_buff *skb, @@ -1127,7 +1143,8 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, struct usb_card_rec *card = adapter->card; struct urb_context *context = NULL; struct usb_tx_data_port *port = NULL; - int idx; + unsigned long flags; + int idx, ret; if (adapter->is_suspended) { mwifiex_dbg(adapter, ERROR, @@ -1167,9 +1184,13 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, return -1; } - if (adapter->bus_aggr.enable) - return mwifiex_usb_aggr_tx_data(adapter, ep, skb, + if (adapter->bus_aggr.enable) { + spin_lock_irqsave(&port->tx_aggr_lock, flags); + ret = mwifiex_usb_aggr_tx_data(adapter, ep, skb, tx_param, port); + spin_unlock_irqrestore(&port->tx_aggr_lock, flags); + return ret; + } context = &port->tx_data_list[port->tx_data_ix++]; } @@ -1177,6 +1198,84 @@ static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, return mwifiex_usb_construct_send_urb(adapter, port, ep, context, skb); } +static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + struct usb_tx_data_port *port; + int i, j; + + card->tx_cmd.adapter = adapter; + card->tx_cmd.ep = card->tx_cmd_ep; + + card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->tx_cmd.urb) + return -ENOMEM; + + for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { + port = &card->port[i]; + if (!port->tx_data_ep) + continue; + port->tx_data_ix = 0; + skb_queue_head_init(&port->tx_aggr.aggr_list); + if (port->tx_data_ep == MWIFIEX_USB_EP_DATA) + port->block_status = false; + else + port->block_status = true; + for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { + port->tx_data_list[j].adapter = adapter; + port->tx_data_list[j].ep = port->tx_data_ep; + port->tx_data_list[j].urb = + usb_alloc_urb(0, GFP_KERNEL); + if (!port->tx_data_list[j].urb) + return -ENOMEM; + } + + port->tx_aggr.timer_cnxt.adapter = adapter; + port->tx_aggr.timer_cnxt.port = port; + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; + setup_timer(&port->tx_aggr.timer_cnxt.hold_timer, + mwifiex_usb_tx_aggr_tmo, + (unsigned long)&port->tx_aggr.timer_cnxt); + } + + return 0; +} + +static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + int i; + + card->rx_cmd.adapter = adapter; + card->rx_cmd.ep = card->rx_cmd_ep; + + card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_cmd.urb) + return -ENOMEM; + + card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); + if (!card->rx_cmd.skb) + return -ENOMEM; + + if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) + return -1; + + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { + card->rx_data_list[i].adapter = adapter; + card->rx_data_list[i].ep = card->rx_data_ep; + + card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_data_list[i].urb) + return -1; + if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], + MWIFIEX_RX_DATA_BUF_SIZE)) + return -1; + } + + return 0; +} + /* This function register usb device and initialize parameter. */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { @@ -1224,14 +1323,16 @@ static void mwifiex_usb_cleanup_tx_aggr(struct mwifiex_adapter *adapter) struct sk_buff *skb_tmp; int idx; - if (adapter->bus_aggr.enable) { - for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { - port = &card->port[idx]; + for (idx = 0; idx < MWIFIEX_TX_DATA_PORT; idx++) { + port = &card->port[idx]; + if (adapter->bus_aggr.enable) while ((skb_tmp = skb_dequeue(&port->tx_aggr.aggr_list))) mwifiex_write_data_complete(adapter, skb_tmp, 0, -1); - } + del_timer_sync(&port->tx_aggr.timer_cnxt.hold_timer); + port->tx_aggr.timer_cnxt.is_hold_timer_set = false; + port->tx_aggr.timer_cnxt.hold_tmo_msecs = 0; } } @@ -1239,8 +1340,7 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) { struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; - if (adapter->bus_aggr.enable) - mwifiex_usb_cleanup_tx_aggr(adapter); + mwifiex_usb_cleanup_tx_aggr(adapter); card->adapter = NULL; } diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index b89b840..37abd22 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -64,10 +64,22 @@ struct urb_context { u8 ep; }; +#define MWIFIEX_USB_TX_AGGR_TMO_MIN 1 +#define MWIFIEX_USB_TX_AGGR_TMO_MAX 4 + +struct tx_aggr_tmr_cnxt { + struct mwifiex_adapter *adapter; + struct usb_tx_data_port *port; + struct timer_list hold_timer; + bool is_hold_timer_set; + u32 hold_tmo_msecs; +}; + struct usb_tx_aggr { struct sk_buff_head aggr_list; int aggr_len; int aggr_num; + struct tx_aggr_tmr_cnxt timer_cnxt; }; struct usb_tx_data_port { @@ -79,6 +91,8 @@ struct usb_tx_data_port { /* usb tx aggregation*/ struct usb_tx_aggr tx_aggr; struct sk_buff *skb_aggr[MWIFIEX_TX_DATA_URB]; + /* lock for protect tx aggregation data path*/ + spinlock_t tx_aggr_lock; }; struct usb_card_rec {