From patchwork Fri Feb 16 22:30:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 10225849 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 0F12B603EE for ; Fri, 16 Feb 2018 22:30:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D711229543 for ; Fri, 16 Feb 2018 22:30:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CB6BA29683; Fri, 16 Feb 2018 22:30:14 +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=-6.9 required=2.0 tests=BAYES_00,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 5B22B29543 for ; Fri, 16 Feb 2018 22:30:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750769AbeBPWaM (ORCPT ); Fri, 16 Feb 2018 17:30:12 -0500 Received: from mail-wm0-f66.google.com ([74.125.82.66]:39900 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750734AbeBPWaM (ORCPT ); Fri, 16 Feb 2018 17:30:12 -0500 Received: by mail-wm0-f66.google.com with SMTP id b21so5570991wme.4 for ; Fri, 16 Feb 2018 14:30:11 -0800 (PST) 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=8hW/EKC4QaJCyvyV0CbYGg7x148jdrGFI8KcVjD2yZY=; b=XGY4T9TmPGiIhnlU7xgwyE6zpGYr5b0+qat2xqg/iNu/87+z1XZiHS4ilHGeZ4DHgT jTDYVte5JzILf93nUm48rWoxpufVyfTWfsFXB9UYySAdCSbKTJf0BPEP/7nTLFbAHafG VWxRlPfZCPYndcEsGJyk+9XyKGrdIjoLu++YoM79SJ5eC8BnoEEnZEaxZKJtjuO/VJ4l p0jUQpKPxVwj9fqr4yioTFlL4u4Fe9cSdkk98TlYOSnmK2zBqe3Rr8DEbowtoCx6QLbx 4ZqbpfiaIwnDmlpCPpcbXR4q4y1IC+AzaGPifhJg3a6jIyYo0whqYjB1kedqAXIDSawk FqpA== X-Gm-Message-State: APf1xPAsMgMSUCn5t0uEtnpu8D1TYH3AoTkqQOvVH9b7K2RnCFBAK6hV vm8fu/VXk6363aeh9Rn7njneYQ== X-Google-Smtp-Source: AH8x225HKZS93uuK8hfbSEkA+A+E3Q5xCrWnfUeEHs3iRRHFsOggkUvFh56ptUzkVeW6ilsxGKBCHA== X-Received: by 10.28.126.133 with SMTP id z127mr6515704wmc.64.1518820210641; Fri, 16 Feb 2018 14:30:10 -0800 (PST) Received: from localhost.localdomain.com ([151.66.66.80]) by smtp.gmail.com with ESMTPSA id k20sm29685385wmh.20.2018.02.16.14.30.09 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 16 Feb 2018 14:30:10 -0800 (PST) From: Lorenzo Bianconi To: kubakici@wp.pl Cc: linux-wireless@vger.kernel.org Subject: [PATCH v2] mt7601u: make write with mask access atomic Date: Fri, 16 Feb 2018 23:30:01 +0100 Message-Id: <4a8ec536fda4741ef88618493d0641fbd497314c.1518819577.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: References: 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 Introduce __mt7601u_rr and __mt7601u_vendor_single_wr routines in order to make mt7601u_rmw and mt7601u_rmc atomic. This patch does not fix a reported issue but makes the usb access more robust to concurrent operations on the same register since it is theoretically possible that read and write accesses of mt7601u_rmw/mt7601u_rmc can be interleaved with a different write operation on the same register. Moreover using __mt7601u_rr and __mt7601u_vendor_single_wr in mt7601u_rmw/mt7601u_rmc allows to grab vendor_req_mutex mutex once instead of twice Signed-off-by: Lorenzo Bianconi Acked-by: Jakub Kicinski --- Changes since v1: - improve commit log --- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 3 +- drivers/net/wireless/mediatek/mt7601u/usb.c | 52 ++++++++++++++++++------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index c7ec40475a5f..9233744451a9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -147,7 +147,8 @@ enum { * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. - * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. + * @vendor_req_mutex: protects @vend_buf, ensures atomicity of read/write + * accesses * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). * @hw_atomic_mutex: ensures exclusive access to HW during critical diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index b9e4f6793138..d8b7863f7926 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -129,15 +129,14 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) MT_VEND_DEV_MODE_RESET, 0, NULL, 0); } -u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) +/* should be called with vendor_req_mutex held */ +static u32 __mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { int ret; u32 val = ~0; WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); - mutex_lock(&dev->vendor_req_mutex); - ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, 0, offset, dev->vend_buf, MT_VEND_BUF); if (ret == MT_VEND_BUF) @@ -146,25 +145,41 @@ u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", ret, offset); - mutex_unlock(&dev->vendor_req_mutex); - trace_reg_read(dev, offset, val); return val; } -int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, - const u16 offset, const u32 val) +u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { - int ret; + u32 ret; mutex_lock(&dev->vendor_req_mutex); + ret = __mt7601u_rr(dev, offset); + mutex_unlock(&dev->vendor_req_mutex); - ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, - val & 0xffff, offset, NULL, 0); + return ret; +} + +/* should be called with vendor_req_mutex held */ +static int __mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val) +{ + int ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val & 0xffff, offset, NULL, 0); if (!ret) ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, val >> 16, offset + 2, NULL, 0); + trace_reg_write(dev, offset, val); + return ret; +} + +int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val) +{ + int ret; + mutex_lock(&dev->vendor_req_mutex); + ret = __mt7601u_vendor_single_wr(dev, req, offset, val); mutex_unlock(&dev->vendor_req_mutex); return ret; @@ -175,23 +190,30 @@ void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset); mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); - trace_reg_write(dev, offset, val); } u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { - val |= mt7601u_rr(dev, offset) & ~mask; - mt7601u_wr(dev, offset, val); + mutex_lock(&dev->vendor_req_mutex); + val |= __mt7601u_rr(dev, offset) & ~mask; + __mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); + mutex_unlock(&dev->vendor_req_mutex); + return val; } u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) { - u32 reg = mt7601u_rr(dev, offset); + u32 reg; + mutex_lock(&dev->vendor_req_mutex); + reg = __mt7601u_rr(dev, offset); val |= reg & ~mask; if (reg != val) - mt7601u_wr(dev, offset, val); + __mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, + offset, val); + mutex_unlock(&dev->vendor_req_mutex); + return val; }