From patchwork Wed Nov 25 11:41:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ajay Singh X-Patchwork-Id: 333455 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 942A2C64E75 for ; Wed, 25 Nov 2020 11:41:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1365B206D9 for ; Wed, 25 Nov 2020 11:41:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="uqQPpIwT"; dkim=pass (1024-bit key) header.d=microchiptechnology.onmicrosoft.com header.i=@microchiptechnology.onmicrosoft.com header.b="BnNvQuoc" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728481AbgKYLlP (ORCPT ); Wed, 25 Nov 2020 06:41:15 -0500 Received: from esa3.microchip.iphmx.com ([68.232.153.233]:51746 "EHLO esa3.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728405AbgKYLlO (ORCPT ); Wed, 25 Nov 2020 06:41:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1606304473; x=1637840473; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-id:content-transfer-encoding: mime-version; bh=ebmKOXgmbfDuBc1sdYfAgmXxYoR6wXtCtWAXdVOs+1o=; b=uqQPpIwT+392EOTl+g9HOSsZGuSgop0MHPMT6/cvEn23i5wT8Mzf3xMD 3AKqoLmnmsZ0/7/jfRrd/aIdPe65XlBOUvfIGjvbU3EB9DJmdaWkQeBps fwJ545BN7OCG+RfDUIgWWti1ej2CU6D7ifuCFLrUPrUTI8gA4vuwxU7JP jz/p51tiMyPNkl3L97ArcL9vH1gLKGMh0DubdSKSpBuJtD4JYcG1MJx4n ux+pbojYL+usiCF8Mk3QZnIveUXxwrbKbQghgGmuMjMdbGFDK6t4yIJiR 8WoUxQiJ4w+pbMvnEwdbh6e3qkhEmk7Us2ldKEK4xByYt5HHxv4RWQVB+ Q==; IronPort-SDR: /SSVM1dmgUqsvTWjjzXpA8JhH2FcKkRWRkNRlztqEw7VGvdDr3Ne4OMzMRqvDf3smyE2dPp4sA 1rAz8b9klSSnlTxfXR//0RTUFyRBrGNc8IsipGxXJanQoWrdQ2SLPmPzyKrnpApLJY7/f79WvY 7Y8ovqMiyeokNBCYWyTbN+Ef2pbY+JqH86w4zvZWrRXzIfqBA/InyLf33KGlFQFyNwWJ25duvc fQ8cAcaMnGAPCsK/aunJoF4c4qCOOFzX6HJ5+hipjK/+sBCOV20JHhtljMahfzh6AbPIjsvnVB 384= X-IronPort-AV: E=Sophos;i="5.78,368,1599548400"; d="scan'208";a="100348223" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa3.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 25 Nov 2020 04:41:12 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3; Wed, 25 Nov 2020 04:41:12 -0700 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (10.10.215.89) by email.microchip.com (10.10.87.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1979.3 via Frontend Transport; Wed, 25 Nov 2020 04:41:12 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=oXhYO5fYQIJgukikF9hXKrqlbA8J5t6uda3cea5yuasiRguhJDkxy11qBgGqRH9O52zQ/zdp0bZCNSNbbFmnyGOks7TiXR7Ju2RSBRWSbPaVR+Miru0oiI795qO6aKec9rmeV8+YdEZpZDAsFbLmPGR612Ex65Aa50RXLz4Y4lhkf++vj+5JdRT8qbAqw9tmfc/e5zobrgRImOt5OnjIr7KoXKDD67XHBmRaOVey7BAojm606hu9GEOMKxWEx/xte8+TOQ1erdSMCMKsibZUsi9U4/5ZVYVtAsJkQXZVvRYLmm2VLvyz1vodlV5GIXxB+Y+d5JhTORLxjrTT8K7KOw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ebmKOXgmbfDuBc1sdYfAgmXxYoR6wXtCtWAXdVOs+1o=; b=H/YyVo+4sn+51unpYOMxTsO+XzT2yO4zraZiElWTKro/LswW7zi+JzoFTrvOEIZ4jrge3x+1WPXlDOxvYfWbpJJIe7/YbQSR7XpfThRSUmznnwFmcoeeDpxIM/IGic5BURQdW4uTq2LwrqJS3EYEu0BQR7J3q6deYX8uBhQkjNevB5QrjUUpth1e6MpWuzFCJ54jSWT14lfsVTMWIM9k2NOT36zxNXuNxpTbVGEiI8Qkcte+wZVO77F96jbkvon8fPgOwRj4yv6KKCQtmUedsREZpZ6cgYQkzHNq+EMbBnVBfsEmQXfGrFg8aL8QTO3WR9CfZMyLcy+zsmSrXmClnQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=microchip.com; dmarc=pass action=none header.from=microchip.com; dkim=pass header.d=microchip.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microchiptechnology.onmicrosoft.com; s=selector2-microchiptechnology-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ebmKOXgmbfDuBc1sdYfAgmXxYoR6wXtCtWAXdVOs+1o=; b=BnNvQuoczExHU+otBN6mu+7E3pTXkZDICwBx/kj4no97ilv65tuIet+bGdPqCipHlABEc+n7eMedzuBg+wNRR8H9GNnKvsBFb3F8Uk89YWjnDLCISwJ7Uk8VgA0L0BU18J1ttUq6LdoJ2bG//EPl7wSAefoE04+k0OtH2FaEEdw= Received: from CY4PR11MB1286.namprd11.prod.outlook.com (2603:10b6:903:2e::21) by CY4PR11MB1605.namprd11.prod.outlook.com (2603:10b6:910:10::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3589.20; Wed, 25 Nov 2020 11:41:11 +0000 Received: from CY4PR11MB1286.namprd11.prod.outlook.com ([fe80::a0d1:a499:1c83:a988]) by CY4PR11MB1286.namprd11.prod.outlook.com ([fe80::a0d1:a499:1c83:a988%6]) with mapi id 15.20.3589.022; Wed, 25 Nov 2020 11:41:11 +0000 From: To: , CC: , , Subject: [PATCH 5/5] wilc1000: added queue support for WMM Thread-Topic: [PATCH 5/5] wilc1000: added queue support for WMM Thread-Index: AQHWwx/f8upo1qvFUUG5pt57bWxILQ== Date: Wed, 25 Nov 2020 11:41:10 +0000 Message-ID: <20201125114059.10006-6-ajay.kathat@microchip.com> References: <20201125114059.10006-1-ajay.kathat@microchip.com> In-Reply-To: <20201125114059.10006-1-ajay.kathat@microchip.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-mailer: git-send-email 2.17.1 authentication-results: vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=none action=none header.from=microchip.com; x-originating-ip: [171.61.34.149] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 679a7e35-d519-4bf1-dd80-08d8913701be x-ms-traffictypediagnostic: CY4PR11MB1605: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-bypassexternaltag: True x-ms-oob-tlc-oobclassifiers: OLM:612; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: 1cp36si1V1710awpr26r3z42w8tfNWCxL8Vd/d6uzxdjKa1/01wAZ6DJIHPGKlyyxook7hf3sX1zcGw+zPAGukUTiHsZxMKhlqAJIkTLiiFCvn/1r/7sw5vT07v77PZzhGVBMyVYRt25kcIlsDQKb7h+LR4S6vOPclPsp/J+Ff3zHaar717IC9gwkg32GlnaCJBgBvGGeuCUj8fQ3jIGqn/xhO9dt+B23+cpE/RGS+aauwp2bMPddmdLV1J3Ldsdck9Yk0TjgJ7bLmMrkEdPPzwNujuG26HrrjsNjvN6cuSBg+g7uBDpsD6zZv1wUz8y x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:CY4PR11MB1286.namprd11.prod.outlook.com; PTR:; CAT:NONE; SFS:(366004)(346002)(136003)(39860400002)(396003)(376002)(66446008)(66556008)(107886003)(2616005)(6486002)(4326008)(30864003)(5660300002)(66476007)(36756003)(54906003)(71200400001)(76116006)(8936002)(64756008)(110136005)(2906002)(6506007)(66946007)(86362001)(186003)(91956017)(478600001)(83380400001)(26005)(316002)(8676002)(1076003)(6512007); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata: 8RN2o4n115c3tZz0yMl8JetNQSrcAEx7ok7DrNIlwpnphsii4KESKsKUQ6i3J7WJK103LM3BR6QED/7VnDM8GgxPNHW/ZpTyk+B5rSBA0tpIiEC1UdYfZjy8/1dD4GqM8K1U1UmJ8h+M7ZAU6v5AuBvmY0g2mmS2EizH/lXX3ZyImvRSwXl0e1xJ6Usrmkj0XOTRsUm1PDCATYxJMNrVxsl/04QPalM2blhJihcyxf2uIRFRWlm3VoGsjBmPR3bu9Q0ZI99cOM/IrI4vpIOGymZBQ9Mr5BUqFAp2rlj0MoEFLOPVOg29rUnPZ5JVaEdVZeplGTxxyPufFMzbJGVnX/rnbez6VeD/Pjh5aV0g/smL2cMNr+2nVw8Soqn2XPszfm9EsjCBsShS8+Qtm5INHjroBKy0Ft9/m6zxigVKAghdkPb9I7P6rK8o8sHosOhI6C822BhiPaw6JuR7G95rfvSWvxJby9qv/UmwnwSwiH1Fwb3BAi7xy/darDnL/VoYcDSSt0yudVvenlaoWbXM8JJu9lIb5TMTCb+rjzhaNrNAJHSBrga9W6D353w1UI5gymAomdifxdTZihh7hbGQI1L7+sZjqrDRs+QsxJFyk3J0/pSqJHzPt+8a75YzDgaJ5GUxyvQF0w9spQU8HSyd2vyuvBC4p/mtM8wOFIt6y07d6zzhnokTPdXqELbgu+MSm5vgTVgu4B+KU9H2LLGgdupAdE21CufMpm3I3HVMd2lCCwqCzWsiZMHBoarg+T0F+EEGu8WUcN0w2Mw3lRuy62kVkAym1EwFAG7LU0mPZvSR7dnOI44ux424xjJeNf89nrgt4kr/5dB0ZnEw3HZA4WKtcRUgIiz9ULkGAUsut2nBPLfaSowGuTGJYJw/P10FYxkHNR0L4MwnD5vVuCJVcw== Content-ID: <1195003C1D6776408F309065EDD1175F@namprd11.prod.outlook.com> MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: CY4PR11MB1286.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 679a7e35-d519-4bf1-dd80-08d8913701be X-MS-Exchange-CrossTenant-originalarrivaltime: 25 Nov 2020 11:41:11.0180 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3f4057f3-b418-4d4e-ba84-d55b4e897d88 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: KG8paNuAjGoAKXfK9ACgsNHdWRnCNQnFuytMF2ttVSdABEJCqkDTOK9npQc5Xud/cBlFEhJVGJpXKXeNiHrQr7n5mE3xoBCVhk2ZQYBhcc0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR11MB1605 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Ajay Singh Added multiple queues[BK,BE,VI,VO] to handle different priority data packets. Before adding a packet to the queue, checked its priority from the header, and then add to the suitable queue. The limit for each queue is maintained separately. Also while passing the packets to the firmware via VMM take care to select data packets based on priority and available space. Signed-off-by: Ajay Singh --- .../wireless/microchip/wilc1000/cfg80211.c | 7 +- .../net/wireless/microchip/wilc1000/netdev.h | 11 +- .../net/wireless/microchip/wilc1000/wlan.c | 315 ++++++++++++++---- .../net/wireless/microchip/wilc1000/wlan.h | 30 ++ 4 files changed, 302 insertions(+), 61 deletions(-) -- 2.24.0 diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index c1ac1d84790f..e3dd205cbbe5 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1709,7 +1709,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, { struct wilc *wl; struct wilc_vif *vif; - int ret; + int ret, i; wl = wilc_create_wiphy(dev); if (!wl) @@ -1725,7 +1725,10 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, wl->io_type = io_type; wl->hif_func = ops; wl->chip_ps_state = WILC_CHIP_WAKEDUP; - INIT_LIST_HEAD(&wl->txq_head.list); + + for (i = 0; i < NQUEUES; i++) + INIT_LIST_HEAD(&wl->txq[i].txq_head.list); + INIT_LIST_HEAD(&wl->rxq_head.list); INIT_LIST_HEAD(&wl->vif_list); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h index d0a006b68d08..86209b391a3d 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.h +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -197,6 +197,14 @@ struct wilc_vif { struct cfg80211_bss *bss; }; +struct wilc_tx_queue_status { + u8 buffer[AC_BUFFER_SIZE]; + u16 end_index; + u16 cnt[NQUEUES]; + u16 sum; + bool initialized; +}; + struct wilc { struct wiphy *wiphy; const struct wilc_hif_func *hif_func; @@ -245,9 +253,10 @@ struct wilc { u32 rx_buffer_offset; u8 *tx_buffer; - struct txq_entry_t txq_head; + struct txq_handle txq[NQUEUES]; int txq_entries; + struct wilc_tx_queue_status tx_q_limit; struct rxq_entry_t rxq_head; const struct firmware *firmware; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 0ff4de28f622..993ea7c03429 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -6,6 +6,7 @@ #include #include +#include #include "cfg80211.h" #include "wlan_cfg.h" @@ -28,33 +29,34 @@ static inline void release_bus(struct wilc *wilc, enum bus_release release) mutex_unlock(&wilc->hif_cs); } -static void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe) +static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num, + struct txq_entry_t *tqe) { list_del(&tqe->list); wilc->txq_entries -= 1; + wilc->txq[q_num].count--; } static struct txq_entry_t * -wilc_wlan_txq_remove_from_head(struct net_device *dev) +wilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num) { struct txq_entry_t *tqe = NULL; unsigned long flags; - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; spin_lock_irqsave(&wilc->txq_spinlock, flags); - if (!list_empty(&wilc->txq_head.list)) { - tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, - list); + if (!list_empty(&wilc->txq[q_num].txq_head.list)) { + tqe = list_first_entry(&wilc->txq[q_num].txq_head.list, + struct txq_entry_t, list); list_del(&tqe->list); wilc->txq_entries -= 1; + wilc->txq[q_num].count--; } spin_unlock_irqrestore(&wilc->txq_spinlock, flags); return tqe; } -static void wilc_wlan_txq_add_to_tail(struct net_device *dev, +static void wilc_wlan_txq_add_to_tail(struct net_device *dev, u8 q_num, struct txq_entry_t *tqe) { unsigned long flags; @@ -63,15 +65,16 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev, spin_lock_irqsave(&wilc->txq_spinlock, flags); - list_add_tail(&tqe->list, &wilc->txq_head.list); + list_add_tail(&tqe->list, &wilc->txq[q_num].txq_head.list); wilc->txq_entries += 1; + wilc->txq[q_num].count++; spin_unlock_irqrestore(&wilc->txq_spinlock, flags); complete(&wilc->txq_event); } -static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, +static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, u8 q_num, struct txq_entry_t *tqe) { unsigned long flags; @@ -81,8 +84,9 @@ static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, spin_lock_irqsave(&wilc->txq_spinlock, flags); - list_add(&tqe->list, &wilc->txq_head.list); + list_add(&tqe->list, &wilc->txq[q_num].txq_head.list); wilc->txq_entries += 1; + wilc->txq[q_num].count++; spin_unlock_irqrestore(&wilc->txq_spinlock, flags); mutex_unlock(&wilc->txq_add_to_head_cs); @@ -212,7 +216,7 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) tqe = f->pending_acks[i].txqe; if (tqe) { - wilc_wlan_txq_remove(wilc, tqe); + wilc_wlan_txq_remove(wilc, tqe->q_num, tqe); tqe->status = 1; if (tqe->tx_complete_func) tqe->tx_complete_func(tqe->priv, @@ -268,10 +272,138 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, tqe->buffer_size = buffer_size; tqe->tx_complete_func = NULL; tqe->priv = NULL; + tqe->q_num = AC_VO_Q; tqe->ack_idx = NOT_TCP_ACK; tqe->vif = vif; - wilc_wlan_txq_add_to_head(vif, tqe); + wilc_wlan_txq_add_to_head(vif, AC_VO_Q, tqe); + + return 1; +} + +static bool is_ac_q_limit(struct wilc *wl, u8 q_num) +{ + u8 factors[NQUEUES] = {1, 1, 1, 1}; + u16 i; + unsigned long flags; + struct wilc_tx_queue_status *q = &wl->tx_q_limit; + u8 end_index; + u8 q_limit; + bool ret = false; + + spin_lock_irqsave(&wl->txq_spinlock, flags); + if (!q->initialized) { + for (i = 0; i < AC_BUFFER_SIZE; i++) + q->buffer[i] = i % NQUEUES; + + for (i = 0; i < NQUEUES; i++) { + q->cnt[i] = AC_BUFFER_SIZE * factors[i] / NQUEUES; + q->sum += q->cnt[i]; + } + q->end_index = AC_BUFFER_SIZE - 1; + q->initialized = 1; + } + + end_index = q->end_index; + q->cnt[q->buffer[end_index]] -= factors[q->buffer[end_index]]; + q->cnt[q_num] += factors[q_num]; + q->sum += (factors[q_num] - factors[q->buffer[end_index]]); + + q->buffer[end_index] = q_num; + if (end_index > 0) + q->end_index--; + else + q->end_index = AC_BUFFER_SIZE - 1; + + if (!q->sum) + q_limit = 1; + else + q_limit = (q->cnt[q_num] * FLOW_CONTROL_UPPER_THRESHOLD / q->sum) + 1; + + if (wl->txq[q_num].count <= q_limit) + ret = true; + + spin_unlock_irqrestore(&wl->txq_spinlock, flags); + + return ret; +} + +static inline u8 ac_classify(struct wilc *wilc, struct sk_buff *skb) +{ + u8 q_num = AC_BE_Q; + u8 dscp; + + switch (skb->protocol) { + case htons(ETH_P_IP): + dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; + break; + case htons(ETH_P_IPV6): + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc; + break; + default: + return q_num; + } + + switch (dscp) { + case 0x08: + case 0x20: + case 0x40: + q_num = AC_BK_Q; + break; + case 0x80: + case 0xA0: + case 0x28: + q_num = AC_VI_Q; + break; + case 0xC0: + case 0xD0: + case 0xE0: + case 0x88: + case 0xB8: + q_num = AC_VO_Q; + break; + } + + return q_num; +} + +static inline int ac_balance(struct wilc *wl, u8 *ratio) +{ + u8 i, max_count = 0; + + if (!ratio) + return -EINVAL; + + for (i = 0; i < NQUEUES; i++) + if (wl->txq[i].fw.count > max_count) + max_count = wl->txq[i].fw.count; + + for (i = 0; i < NQUEUES; i++) + ratio[i] = max_count - wl->txq[i].fw.count; + + return 0; +} + +static inline void ac_update_fw_ac_pkt_info(struct wilc *wl, u32 reg) +{ + wl->txq[AC_BK_Q].fw.count = FIELD_GET(BK_AC_COUNT_FIELD, reg); + wl->txq[AC_BE_Q].fw.count = FIELD_GET(BE_AC_COUNT_FIELD, reg); + wl->txq[AC_VI_Q].fw.count = FIELD_GET(VI_AC_COUNT_FIELD, reg); + wl->txq[AC_VO_Q].fw.count = FIELD_GET(VO_AC_COUNT_FIELD, reg); + + wl->txq[AC_BK_Q].fw.acm = FIELD_GET(BK_AC_ACM_STAT_FIELD, reg); + wl->txq[AC_BE_Q].fw.acm = FIELD_GET(BE_AC_ACM_STAT_FIELD, reg); + wl->txq[AC_VI_Q].fw.acm = FIELD_GET(VI_AC_ACM_STAT_FIELD, reg); + wl->txq[AC_VO_Q].fw.acm = FIELD_GET(VO_AC_ACM_STAT_FIELD, reg); +} + +static inline u8 ac_change(struct wilc *wilc, u8 *ac) +{ + do { + if (wilc->txq[*ac].fw.acm == 0) + return 0; + (*ac)++; + } while (*ac < NQUEUES); return 1; } @@ -283,6 +415,7 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, struct txq_entry_t *tqe; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc; + u8 q_num; wilc = vif->wilc; @@ -304,10 +437,24 @@ int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->priv = priv; tqe->vif = vif; - tqe->ack_idx = NOT_TCP_ACK; - if (vif->ack_filter.enabled) - tcp_process(dev, tqe); - wilc_wlan_txq_add_to_tail(dev, tqe); + q_num = ac_classify(wilc, priv); + tqe->q_num = q_num; + if (ac_change(wilc, &q_num)) { + tx_complete_fn(priv, 0); + kfree(tqe); + return 0; + } + + if (is_ac_q_limit(wilc, q_num)) { + tqe->ack_idx = NOT_TCP_ACK; + if (vif->ack_filter.enabled) + tcp_process(dev, tqe); + wilc_wlan_txq_add_to_tail(dev, q_num, tqe); + } else { + tx_complete_fn(priv, 0); + kfree(tqe); + } + return wilc->txq_entries; } @@ -337,22 +484,23 @@ int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->buffer_size = buffer_size; tqe->tx_complete_func = tx_complete_fn; tqe->priv = priv; + tqe->q_num = AC_BE_Q; tqe->ack_idx = NOT_TCP_ACK; tqe->vif = vif; - wilc_wlan_txq_add_to_tail(dev, tqe); + wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe); return 1; } -static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc) +static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc, u8 q_num) { struct txq_entry_t *tqe = NULL; unsigned long flags; spin_lock_irqsave(&wilc->txq_spinlock, flags); - if (!list_empty(&wilc->txq_head.list)) - tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, - list); + if (!list_empty(&wilc->txq[q_num].txq_head.list)) + tqe = list_first_entry(&wilc->txq[q_num].txq_head.list, + struct txq_entry_t, list); spin_unlock_irqrestore(&wilc->txq_spinlock, flags); @@ -360,13 +508,14 @@ static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc) } static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc, - struct txq_entry_t *tqe) + struct txq_entry_t *tqe, + u8 q_num) { unsigned long flags; spin_lock_irqsave(&wilc->txq_spinlock, flags); - if (!list_is_last(&tqe->list, &wilc->txq_head.list)) + if (!list_is_last(&tqe->list, &wilc->txq[q_num].txq_head.list)) tqe = list_next_entry(tqe, list); else tqe = NULL; @@ -489,54 +638,92 @@ EXPORT_SYMBOL_GPL(host_sleep_notify); int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) { int i, entries = 0; + u8 k, ac; u32 sum; u32 reg; + u8 ac_desired_ratio[NQUEUES] = {0, 0, 0, 0}; + u8 ac_preserve_ratio[NQUEUES] = {1, 1, 1, 1}; + u8 *num_pkts_to_add; + u8 vmm_entries_ac[WILC_VMM_TBL_SIZE]; u32 offset = 0; + bool max_size_over = 0, ac_exist = 0; int vmm_sz = 0; - struct txq_entry_t *tqe; + struct txq_entry_t *tqe_q[NQUEUES]; int ret = 0; int counter; int timeout; u32 vmm_table[WILC_VMM_TBL_SIZE]; + u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0}; const struct wilc_hif_func *func; + int srcu_idx; u8 *txb = wilc->tx_buffer; - struct net_device *dev; struct wilc_vif *vif; if (wilc->quit) goto out_update_cnt; + if (ac_balance(wilc, ac_desired_ratio)) + return -EINVAL; + mutex_lock(&wilc->txq_add_to_head_cs); - tqe = wilc_wlan_txq_get_first(wilc); - if (!tqe) - goto out_unlock; - dev = tqe->vif->ndev; - wilc_wlan_txq_filter_dup_tcp_ack(dev); + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) + wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev); + srcu_read_unlock(&wilc->srcu, srcu_idx); + + for (ac = 0; ac < NQUEUES; ac++) + tqe_q[ac] = wilc_wlan_txq_get_first(wilc, ac); + i = 0; sum = 0; - while (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { - if (tqe->type == WILC_CFG_PKT) - vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; - else if (tqe->type == WILC_NET_PKT) - vmm_sz = ETH_ETHERNET_HDR_OFFSET; - else - vmm_sz = HOST_HDR_OFFSET; - - vmm_sz += tqe->buffer_size; - vmm_sz = ALIGN(vmm_sz, 4); - - if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) - break; + max_size_over = 0; + num_pkts_to_add = ac_desired_ratio; + do { + ac_exist = 0; + for (ac = 0; (ac < NQUEUES) && (!max_size_over); ac++) { + if (!tqe_q[ac]) + continue; + + vif = tqe_q[ac]->vif; + ac_exist = 1; + for (k = 0; (k < num_pkts_to_add[ac]) && + (!max_size_over) && tqe_q[ac]; k++) { + if (i >= (WILC_VMM_TBL_SIZE - 1)) { + max_size_over = 1; + break; + } - vmm_table[i] = vmm_sz / 4; - if (tqe->type == WILC_CFG_PKT) - vmm_table[i] |= BIT(10); - cpu_to_le32s(&vmm_table[i]); + if (tqe_q[ac]->type == WILC_CFG_PKT) + vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; + else if (tqe_q[ac]->type == WILC_NET_PKT) + vmm_sz = ETH_ETHERNET_HDR_OFFSET; + else + vmm_sz = HOST_HDR_OFFSET; - i++; - sum += vmm_sz; - tqe = wilc_wlan_txq_get_next(wilc, tqe); - } + vmm_sz += tqe_q[ac]->buffer_size; + vmm_sz = ALIGN(vmm_sz, 4); + + if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) { + max_size_over = 1; + break; + } + vmm_table[i] = vmm_sz / 4; + if (tqe_q[ac]->type == WILC_CFG_PKT) + vmm_table[i] |= BIT(10); + + cpu_to_le32s(&vmm_table[i]); + vmm_entries_ac[i] = ac; + + i++; + sum += vmm_sz; + tqe_q[ac] = wilc_wlan_txq_get_next(wilc, + tqe_q[ac], + ac); + } + } + num_pkts_to_add = ac_preserve_ratio; + } while (!max_size_over && ac_exist); if (i == 0) goto out_unlock; @@ -550,8 +737,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) if (ret) break; - if ((reg & 0x1) == 0) + if ((reg & 0x1) == 0) { + ac_update_fw_ac_pkt_info(wilc, reg); break; + } counter++; if (counter > 200) { @@ -620,11 +809,13 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) offset = 0; i = 0; do { + struct txq_entry_t *tqe; u32 header, buffer_offset; char *bssid; u8 mgmt_ptk = 0; - tqe = wilc_wlan_txq_remove_from_head(dev); + tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]); + ac_pkt_num_to_chip[vmm_entries_ac[i]]++; if (!tqe) break; @@ -649,8 +840,11 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) if (tqe->type == WILC_CFG_PKT) { buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; } else if (tqe->type == WILC_NET_PKT) { + int prio = tqe->q_num; + bssid = tqe->vif->bssid; buffer_offset = ETH_ETHERNET_HDR_OFFSET; + memcpy(&txb[offset + 4], &prio, sizeof(prio)); memcpy(&txb[offset + 8], bssid, 6); } else { buffer_offset = HOST_HDR_OFFSET; @@ -668,6 +862,8 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL; kfree(tqe); } while (--entries); + for (i = 0; i < NQUEUES; i++) + wilc->txq[i].fw.count += ac_pkt_num_to_chip[i]; acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); @@ -966,14 +1162,17 @@ void wilc_wlan_cleanup(struct net_device *dev) { struct txq_entry_t *tqe; struct rxq_entry_t *rqe; + u8 ac; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; wilc->quit = 1; - while ((tqe = wilc_wlan_txq_remove_from_head(dev))) { - if (tqe->tx_complete_func) - tqe->tx_complete_func(tqe->priv, 0); - kfree(tqe); + for (ac = 0; ac < NQUEUES; ac++) { + while ((tqe = wilc_wlan_txq_remove_from_head(wilc, ac))) { + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, 0); + kfree(tqe); + } } while ((rqe = wilc_wlan_rxq_remove(wilc))) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index 7689569cd82f..3d2104f19819 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -207,6 +207,18 @@ #define MODALIAS "WILC_SPI" +#define NQUEUES 4 +#define AC_BUFFER_SIZE 1000 + +#define VO_AC_COUNT_FIELD GENMASK(31, 25) +#define VO_AC_ACM_STAT_FIELD BIT(24) +#define VI_AC_COUNT_FIELD GENMASK(23, 17) +#define VI_AC_ACM_STAT_FIELD BIT(16) +#define BE_AC_COUNT_FIELD GENMASK(15, 9) +#define BE_AC_ACM_STAT_FIELD BIT(8) +#define BK_AC_COUNT_FIELD GENMASK(7, 3) +#define BK_AC_ACM_STAT_FIELD BIT(1) + #define WILC_PKT_HDR_CONFIG_FIELD BIT(31) #define WILC_PKT_HDR_OFFSET_FIELD GENMASK(30, 22) #define WILC_PKT_HDR_TOTAL_LEN_FIELD GENMASK(21, 11) @@ -295,10 +307,17 @@ * Tx/Rx Queue Structure * ********************************************/ +enum ip_pkt_priority { + AC_VO_Q = 0, + AC_VI_Q = 1, + AC_BE_Q = 2, + AC_BK_Q = 3 +}; struct txq_entry_t { struct list_head list; int type; + u8 q_num; int ack_idx; u8 *buffer; int buffer_size; @@ -308,6 +327,17 @@ struct txq_entry_t { void (*tx_complete_func)(void *priv, int status); }; +struct txq_fw_recv_queue_stat { + u8 acm; + u8 count; +}; + +struct txq_handle { + struct txq_entry_t txq_head; + u16 count; + struct txq_fw_recv_queue_stat fw; +}; + struct rxq_entry_t { struct list_head list; u8 *buffer;