From patchwork Tue Jul 16 16:42:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11046489 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E889817E0 for ; Tue, 16 Jul 2019 16:42:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D8A272860A for ; Tue, 16 Jul 2019 16:42:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CC7142861E; Tue, 16 Jul 2019 16:42:59 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 49E9C2860A for ; Tue, 16 Jul 2019 16:42:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388173AbfGPQm4 (ORCPT ); Tue, 16 Jul 2019 12:42:56 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:41922 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388088AbfGPQmq (ORCPT ); Tue, 16 Jul 2019 12:42:46 -0400 Received: by mail-pf1-f196.google.com with SMTP id m30so9384490pff.8 for ; Tue, 16 Jul 2019 09:42:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=eGqYmSRY0aX5Z2gwVb+ocjilcWY5xD+m3PbgEthSu3s=; b=J+QejSTqpqmwqp1exIlt6u/JLWNu+5jOtwHjmNNPRjpvrQsfgqWuh28+D+4+nIPO5K YbLtPl8q8y20WuIoPv6idr4xciiwgkEKUNejLjjYgeC/+nVUXRcivwy4+8u+9Py3LNvI 6EqYtSULVOTa8A/l5H0GZBx0X5J2q5b6gRk8g= 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:mime-version:content-transfer-encoding; bh=eGqYmSRY0aX5Z2gwVb+ocjilcWY5xD+m3PbgEthSu3s=; b=gh1a6oVo7rmGLsl14wolOlYkreTPLp7/bBiRkAR1PtjHarlLSURhVQElKYiauHyj6h h4BHWMRrq3jGAw9SP2I2+3OOSxAzrxSUO4pitqjieNGd4c6ghE9bmtyQlGHt5EYYI4hE J4Op6pqRoxQKb/j/jygfMVfUHY6jUTqi7+PEq2BaB8ZTTHDshg8JJXpfQ5sePPyBNdOK VZDAVIKDexe36sA24zRMQtA4i9rtSbIOPX0ot6/1KP4x3UDz2Du6RgL+YdrXL1PThNXi oaQA8G/aOIVZdn1l9+r8T1BZytG/Sz0O8Y+4+mDJiTKZtv+FUAWU0nEarx1snGRqkCEv NTqw== X-Gm-Message-State: APjAAAXPRAN0gYI3SK1funcOIlSnNIUxERmp+TNLiW7klCCRWtAq/Bp+ Bleo43Dp8MYPTMPr6/nSBTGHhg== X-Google-Smtp-Source: APXvYqzTbFdUQvee1WuiqpQUi3ryRdKOs288mKrt4jpytT3apms/GB6jRwGHlDNmWOJfHARW1woJVg== X-Received: by 2002:a17:90a:2305:: with SMTP id f5mr39843967pje.128.1563295365190; Tue, 16 Jul 2019 09:42:45 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r1sm25456468pfq.100.2019.07.16.09.42.44 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Tue, 16 Jul 2019 09:42:44 -0700 (PDT) From: Douglas Anderson To: Ulf Hansson , Kalle Valo , Adrian Hunter Cc: Ganapathi Bhat , linux-wireless@vger.kernel.org, Brian Norris , Amitkumar Karwar , linux-rockchip@lists.infradead.org, Wolfram Sang , Nishant Sarmukadam , netdev@vger.kernel.org, Avri Altman , linux-mmc@vger.kernel.org, davem@davemloft.net, Xinming Hu , Douglas Anderson , Jiong Wu , Ritesh Harjani , linux-kernel@vger.kernel.org, Thomas Gleixner , Greg Kroah-Hartman , =?utf-8?q?Niklas_S=C3=B6de?= =?utf-8?q?rlund?= Subject: [PATCH 1/2] mmc: core: Add sdio_trigger_replug() API Date: Tue, 16 Jul 2019 09:42:08 -0700 Message-Id: <20190716164209.62320-2-dianders@chromium.org> X-Mailer: git-send-email 2.22.0.510.g264f2c817a-goog In-Reply-To: <20190716164209.62320-1-dianders@chromium.org> References: <20190716164209.62320-1-dianders@chromium.org> MIME-Version: 1.0 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 When using Marvell WiFi SDIO cards, it is not uncommon for Linux WiFi driver to fully lose the communication channel to the firmware running on the card. Presumably the firmware on the card has a bug or two in it and occasionally crashes. The Marvell WiFi driver attempts to recover from this problem. Specifically the driver has the function mwifiex_sdio_card_reset() which is called when communcation problems are found. That function attempts to reset the state of things by utilizing the mmc_hw_reset() function. The current solution is a bit complex because the Marvell WiFi driver needs to manually deinit and reinit the WiFi driver around the reset call. This means it's going through a bunch of code paths that aren't normally tested. However, complexity isn't our only problem. The other (bigger) problem is that Marvell WiFi cards are often combo WiFi/Bluetooth cards and Bluetooth runs on a second SDIO func. While the WiFi driver knows that it should re-init its own state around the mmc_hw_reset() call there is no good way to inform the Bluetooth driver. That means that in Linux today when you reset the Marvell WiFi driver you lose all Bluetooth communication. Doh! One way to fix the above problems is to leverage a more standard way to reset the Marvell WiFi card where we go through the same code paths as card unplug and the card plug. In this patch we introduce a new API call for doing just that: sdio_trigger_replug(). This API call will trigger an unplug of the SDIO card followed by a plug of the card. As part of this the card will be nicely reset. Signed-off-by: Douglas Anderson Reviewed-by: Matthias Kaehlcke --- drivers/mmc/core/core.c | 28 ++++++++++++++++++++++++++-- drivers/mmc/core/sdio_io.c | 20 ++++++++++++++++++++ include/linux/mmc/host.h | 15 ++++++++++++++- include/linux/mmc/sdio_func.h | 2 ++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9020cb2490f7..48a7d23aed26 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2164,6 +2164,12 @@ int mmc_sw_reset(struct mmc_host *host) } EXPORT_SYMBOL(mmc_sw_reset); +void mmc_trigger_replug(struct mmc_host *host) +{ + host->trigger_replug_state = MMC_REPLUG_STATE_UNPLUG; + _mmc_detect_change(host, 0, false); +} + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; @@ -2217,6 +2223,11 @@ int _mmc_detect_card_removed(struct mmc_host *host) if (!host->card || mmc_card_removed(host->card)) return 1; + if (host->trigger_replug_state == MMC_REPLUG_STATE_UNPLUG) { + mmc_card_set_removed(host->card); + return 1; + } + ret = host->bus_ops->alive(host); /* @@ -2329,8 +2340,21 @@ void mmc_rescan(struct work_struct *work) mmc_bus_put(host); mmc_claim_host(host); - if (mmc_card_is_removable(host) && host->ops->get_cd && - host->ops->get_cd(host) == 0) { + + /* + * Move through the state machine if we're triggering an unplug + * followed by a re-plug. + */ + if (host->trigger_replug_state == MMC_REPLUG_STATE_UNPLUG) { + host->trigger_replug_state = MMC_REPLUG_STATE_PLUG; + _mmc_detect_change(host, 0, false); + } else if (host->trigger_replug_state == MMC_REPLUG_STATE_PLUG) { + host->trigger_replug_state = MMC_REPLUG_STATE_NONE; + } + + if (host->trigger_replug_state == MMC_REPLUG_STATE_PLUG || + (mmc_card_is_removable(host) && host->ops->get_cd && + host->ops->get_cd(host) == 0)) { mmc_power_off(host); mmc_release_host(host); goto out; diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 2ba00acf64e6..1c5c2a3ebe5e 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -811,3 +811,23 @@ void sdio_retune_release(struct sdio_func *func) mmc_retune_release(func->card->host); } EXPORT_SYMBOL_GPL(sdio_retune_release); + +/** + * sdio_trigger_replug - trigger an "unplug" + "plug" of the card + * @func: SDIO function attached to host + * + * When you call this function we will schedule events that will + * make it look like the card contining the given SDIO func was + * unplugged and then re-plugged-in. This is as close as possible + * to a full reset of the card that can be achieved. + * + * NOTE: routnine will temporarily make the card look as if it is + * removable even if it is marked non-removable. + * + * This function should be called while the host is claimed. + */ +void sdio_trigger_replug(struct sdio_func *func) +{ + mmc_trigger_replug(func->card->host); +} +EXPORT_SYMBOL(sdio_trigger_replug); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index a9b12322c775..e0d41a1bcf17 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -410,6 +410,12 @@ struct mmc_host { bool trigger_card_event; /* card_event necessary */ + /* state machine for triggering unplug/replug */ +#define MMC_REPLUG_STATE_NONE 0 /* not doing unplug/replug */ +#define MMC_REPLUG_STATE_UNPLUG 1 /* do unplug next */ +#define MMC_REPLUG_STATE_PLUG 2 /* do plug next */ + u8 trigger_replug_state; + struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; @@ -530,7 +536,12 @@ int mmc_regulator_get_supply(struct mmc_host *mmc); static inline int mmc_card_is_removable(struct mmc_host *host) { - return !(host->caps & MMC_CAP_NONREMOVABLE); + /* + * A non-removable card briefly looks removable if code has forced + * a re-plug of the card. + */ + return host->trigger_replug_state != MMC_REPLUG_STATE_NONE || + !(host->caps & MMC_CAP_NONREMOVABLE); } static inline int mmc_card_keep_power(struct mmc_host *host) @@ -583,4 +594,6 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_abort_tuning(struct mmc_host *host, u32 opcode); +void mmc_trigger_replug(struct mmc_host *host); + #endif /* LINUX_MMC_HOST_H */ diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 5a177f7a83c3..0d6c73768ae3 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -173,4 +173,6 @@ extern void sdio_retune_crc_enable(struct sdio_func *func); extern void sdio_retune_hold_now(struct sdio_func *func); extern void sdio_retune_release(struct sdio_func *func); +extern void sdio_trigger_replug(struct sdio_func *func); + #endif /* LINUX_MMC_SDIO_FUNC_H */ From patchwork Tue Jul 16 16:42:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 11046483 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-2.web.codeaurora.org (Postfix) with ESMTP id 04AE16C5 for ; Tue, 16 Jul 2019 16:42:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E87692860A for ; Tue, 16 Jul 2019 16:42:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DBFE528610; Tue, 16 Jul 2019 16:42:54 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable 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 8E09F2860A for ; Tue, 16 Jul 2019 16:42:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387977AbfGPQmr (ORCPT ); Tue, 16 Jul 2019 12:42:47 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:42407 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388105AbfGPQmr (ORCPT ); Tue, 16 Jul 2019 12:42:47 -0400 Received: by mail-pf1-f194.google.com with SMTP id q10so9372928pff.9 for ; Tue, 16 Jul 2019 09:42:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=G0ynwreDQx55Cdn2k1+KVcd1p88/D0r6svcv1QlBO3o=; b=irjFbOPzoCsmoIZq13YOds5hccWx9OiE071z79slMWaKwUnr0Gw8NqkCvXGuxofvkE b2DbVQ8khrwbZ1fgtJzGUdLN3xC5o1VqML1rE0tFczdIs5fX+WoRn0m64ZSj09uLaKp8 W4JTJ5GuZwoocTLDXiTmbxT27wq8MYbdfM4/8= 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:mime-version:content-transfer-encoding; bh=G0ynwreDQx55Cdn2k1+KVcd1p88/D0r6svcv1QlBO3o=; b=M9IqtOKUGKPxXofn6CtT6mbdvw6UHrIFh2qJhnfMmWNOjPgjCoug7p562G98p26rAG EUED4p2G3psh5FJoZe4Ji5ZDFLzN3OkIAaaPH7jEzJejkXRLBoLWfFbpTqAuKfWmlYhT pYQCL/+niuq/P+lN3ykknXaGA9lWfDK82EKtjwusXU+QIJwAuH9wzWKtBu/xeFoS1yeR oCqY0USZHLnoZBq5+tofjt3axzdGKqt53DFF/6Ko+BPVoIC/eyb6chBKBaTLrk3SXE7l ZYP1WWPkApcLOfm2cdCf7mM6TldTuJa5d8Kx/DMUhNxHm0Q2BDid7j4sRZdFEVxDQe7c PKFg== X-Gm-Message-State: APjAAAXq19O5PSCLPiUg17HHAXh/0MkalH4WWGBm0yZhTD4yUGvES85v Jz5XNtTVcpGofqKWfMydUJAuCw== X-Google-Smtp-Source: APXvYqxTvrAricfH4zSCJjfNseyILhC1mVPFZVt33bDXH1vSrEY0L19EpCl6w3rTFJO8Jdf66uAxVQ== X-Received: by 2002:a17:90a:cf8f:: with SMTP id i15mr36366127pju.110.1563295366371; Tue, 16 Jul 2019 09:42:46 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:1:24fa:e766:52c9:e3b2]) by smtp.gmail.com with ESMTPSA id r1sm25456468pfq.100.2019.07.16.09.42.45 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Tue, 16 Jul 2019 09:42:45 -0700 (PDT) From: Douglas Anderson To: Ulf Hansson , Kalle Valo , Adrian Hunter Cc: Ganapathi Bhat , linux-wireless@vger.kernel.org, Brian Norris , Amitkumar Karwar , linux-rockchip@lists.infradead.org, Wolfram Sang , Nishant Sarmukadam , netdev@vger.kernel.org, Avri Altman , linux-mmc@vger.kernel.org, davem@davemloft.net, Xinming Hu , Douglas Anderson , linux-kernel@vger.kernel.org Subject: [PATCH 2/2] mwifiex: Make use of the new sdio_trigger_replug() API to reset Date: Tue, 16 Jul 2019 09:42:09 -0700 Message-Id: <20190716164209.62320-3-dianders@chromium.org> X-Mailer: git-send-email 2.22.0.510.g264f2c817a-goog In-Reply-To: <20190716164209.62320-1-dianders@chromium.org> References: <20190716164209.62320-1-dianders@chromium.org> MIME-Version: 1.0 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 As described in the patch ("mmc: core: Add sdio_trigger_replug() API"), the current mwifiex_sdio_card_reset() is broken in the cases where we're running Bluetooth on a second SDIO func on the same card as WiFi. The problem goes away if we just use the sdio_trigger_replug() API call. NOTE: Even though with this new solution there is less of a reason to do our work from a workqueue (the unplug / plug mechanism we're using is possible for a human to perform at any time so the stack is supposed to handle it without it needing to be called from a special context), we still need a workqueue because the Marvell reset function could called from a context where sleeping is invalid and thus we can't claim the host. One example is Marvell's wakeup_timer_fn(). Signed-off-by: Douglas Anderson Reviewed-by: Brian Norris --- drivers/net/wireless/marvell/mwifiex/sdio.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 24c041dad9f6..f77ad2615f08 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -2218,14 +2218,6 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; struct sdio_func *func = card->func; - int ret; - - mwifiex_shutdown_sw(adapter); - - /* power cycle the adapter */ - sdio_claim_host(func); - mmc_hw_reset(func->card->host); - sdio_release_host(func); /* Previous save_adapter won't be valid after this. We will cancel * pending work requests. @@ -2233,9 +2225,9 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); - ret = mwifiex_reinit_sw(adapter); - if (ret) - dev_err(&func->dev, "reinit failed: %d\n", ret); + sdio_claim_host(func); + sdio_trigger_replug(func); + sdio_release_host(func); } /* This function read/write firmware */