Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92537f8c authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: fix return code of wmi_mgmt_tx and wmi_mgmt_tx_ext"

parents 18887da8 e439ec74
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -1556,7 +1556,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
			     params->wait);
			     params->wait);


out:
out:
	/* when the sent packet was not acked by receiver(ACK=0), rc will
	 * be -EAGAIN. In this case this function needs to return success,
	 * the ACK=0 will be reflected in tx_status.
	 */
	tx_status = (rc == 0);
	tx_status = (rc == 0);
	rc = (rc == -EAGAIN) ? 0 : rc;
	cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
	cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
				tx_status, GFP_KERNEL);
				tx_status, GFP_KERNEL);


+22 −4
Original line number Original line Diff line number Diff line
@@ -269,6 +269,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,


	wil_halp_vote(wil);
	wil_halp_vote(wil);


	if (wil_mem_access_lock(wil)) {
		wil_halp_unvote(wil);
		return;
	}

	wil_memcpy_fromio_32(&r, off, sizeof(r));
	wil_memcpy_fromio_32(&r, off, sizeof(r));
	wil_mbox_ring_le2cpus(&r);
	wil_mbox_ring_le2cpus(&r);
	/*
	/*
@@ -334,6 +339,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix,
	}
	}
 out:
 out:
	seq_puts(s, "}\n");
	seq_puts(s, "}\n");
	wil_mem_access_unlock(wil);
	wil_halp_unvote(wil);
	wil_halp_unvote(wil);
}
}


@@ -622,6 +628,12 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data)
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;


	ret = wil_mem_access_lock(wil);
	if (ret) {
		wil_pm_runtime_put(wil);
		return ret;
	}

	a = wmi_buffer(wil, cpu_to_le32(mem_addr));
	a = wmi_buffer(wil, cpu_to_le32(mem_addr));


	if (a)
	if (a)
@@ -629,6 +641,8 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data)
	else
	else
		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);


	wil_mem_access_unlock(wil);

	wil_pm_runtime_put(wil);
	wil_pm_runtime_put(wil);


	return 0;
	return 0;
@@ -658,10 +672,6 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
	size_t unaligned_bytes, aligned_count, ret;
	size_t unaligned_bytes, aligned_count, ret;
	int rc;
	int rc;


	if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
	    test_bit(wil_status_suspended, wil_blob->wil->status))
		return 0;

	if (pos < 0)
	if (pos < 0)
		return -EINVAL;
		return -EINVAL;


@@ -688,11 +698,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
		return rc;
		return rc;
	}
	}


	rc = wil_mem_access_lock(wil);
	if (rc) {
		kfree(buf);
		wil_pm_runtime_put(wil);
		return rc;
	}

	wil_memcpy_fromio_32(buf, (const void __iomem *)
	wil_memcpy_fromio_32(buf, (const void __iomem *)
			     wil_blob->blob.data + aligned_pos, aligned_count);
			     wil_blob->blob.data + aligned_pos, aligned_count);


	ret = copy_to_user(user_buf, buf + unaligned_bytes, count);
	ret = copy_to_user(user_buf, buf + unaligned_bytes, count);


	wil_mem_access_unlock(wil);
	wil_pm_runtime_put(wil);
	wil_pm_runtime_put(wil);


	kfree(buf);
	kfree(buf);
+53 −19
Original line number Original line Diff line number Diff line
@@ -173,6 +173,28 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
	}
	}
}
}


/* Device memory access is prohibited while reset or suspend.
 * wil_mem_access_lock protects accessing device memory in these cases
 */
int wil_mem_access_lock(struct wil6210_priv *wil)
{
	if (!down_read_trylock(&wil->mem_lock))
		return -EBUSY;

	if (test_bit(wil_status_suspending, wil->status) ||
	    test_bit(wil_status_suspended, wil->status)) {
		up_read(&wil->mem_lock);
		return -EBUSY;
	}

	return 0;
}

void wil_mem_access_unlock(struct wil6210_priv *wil)
{
	up_read(&wil->mem_lock);
}

static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
static void wil_ring_fini_tx(struct wil6210_priv *wil, int id)
{
{
	struct wil_ring *ring = &wil->ring_tx[id];
	struct wil_ring *ring = &wil->ring_tx[id];
@@ -503,22 +525,16 @@ bool wil_is_recovery_blocked(struct wil6210_priv *wil)
	return no_fw_recovery && (wil->recovery_state == fw_recovery_pending);
	return no_fw_recovery && (wil->recovery_state == fw_recovery_pending);
}
}


static void wil_fw_error_worker(struct work_struct *work)
void wil_fw_recovery(struct wil6210_priv *wil)
{
{
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
	struct net_device *ndev = wil->main_ndev;
	struct net_device *ndev = wil->main_ndev;
	struct wireless_dev *wdev;
	struct wireless_dev *wdev;


	wil_dbg_misc(wil, "fw error worker\n");
	wil_dbg_misc(wil, "fw recovery\n");


	if (!ndev || !(ndev->flags & IFF_UP)) {
		wil_info(wil, "No recovery - interface is down\n");
		return;
	}
	wdev = ndev->ieee80211_ptr;
	wdev = ndev->ieee80211_ptr;


	/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
	/* increment @recovery_count if less than WIL6210_FW_RECOVERY_TO
	 * passed since last recovery attempt
	 * passed since last recovery attempt
	 */
	 */
	if (time_is_after_jiffies(wil->last_fw_recovery +
	if (time_is_after_jiffies(wil->last_fw_recovery +
@@ -578,6 +594,22 @@ static void wil_fw_error_worker(struct work_struct *work)
	rtnl_unlock();
	rtnl_unlock();
}
}


static void wil_fw_error_worker(struct work_struct *work)
{
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
	struct net_device *ndev = wil->main_ndev;

	wil_dbg_misc(wil, "fw error worker\n");

	if (!ndev || !(ndev->flags & IFF_UP)) {
		wil_info(wil, "No recovery - interface is down\n");
		return;
	}

	wil_fw_recovery(wil);
}

static int wil_find_free_ring(struct wil6210_priv *wil)
static int wil_find_free_ring(struct wil6210_priv *wil)
{
{
	int i;
	int i;
@@ -690,11 +722,14 @@ int wil_priv_init(struct wil6210_priv *wil)


	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
	INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
	INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
	INIT_WORK(&wil->pci_linkdown_recovery_worker,
		  wil_pci_linkdown_recovery_worker);


	INIT_LIST_HEAD(&wil->pending_wmi_ev);
	INIT_LIST_HEAD(&wil->pending_wmi_ev);
	spin_lock_init(&wil->wmi_ev_lock);
	spin_lock_init(&wil->wmi_ev_lock);
	spin_lock_init(&wil->net_queue_lock);
	spin_lock_init(&wil->net_queue_lock);
	init_waitqueue_head(&wil->wq);
	init_waitqueue_head(&wil->wq);
	init_rwsem(&wil->mem_lock);


	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
	if (!wil->wmi_wq)
	if (!wil->wmi_wq)
@@ -804,6 +839,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)


	wil_set_recovery_state(wil, fw_recovery_idle);
	wil_set_recovery_state(wil, fw_recovery_idle);
	cancel_work_sync(&wil->fw_error_worker);
	cancel_work_sync(&wil->fw_error_worker);
	cancel_work_sync(&wil->pci_linkdown_recovery_worker);
	wmi_event_flush(wil);
	wmi_event_flush(wil);
	destroy_workqueue(wil->wq_service);
	destroy_workqueue(wil->wq_service);
	destroy_workqueue(wil->wmi_wq);
	destroy_workqueue(wil->wmi_wq);
@@ -1624,15 +1660,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
	}
	}


	set_bit(wil_status_resetting, wil->status);
	set_bit(wil_status_resetting, wil->status);
	if (test_bit(wil_status_collecting_dumps, wil->status)) {
		/* Device collects crash dump, cancel the reset.
		 * following crash dump collection, reset would take place.
		 */
		wil_dbg_misc(wil, "reject reset while collecting crash dump\n");
		rc = -EBUSY;
		goto out;
	}

	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	wil_abort_scan_all_vifs(wil, false);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);
@@ -1816,7 +1843,9 @@ int __wil_up(struct wil6210_priv *wil)


	WARN_ON(!mutex_is_locked(&wil->mutex));
	WARN_ON(!mutex_is_locked(&wil->mutex));


	down_write(&wil->mem_lock);
	rc = wil_reset(wil, true);
	rc = wil_reset(wil, true);
	up_write(&wil->mem_lock);
	if (rc)
	if (rc)
		return rc;
		return rc;


@@ -1888,6 +1917,7 @@ int wil_up(struct wil6210_priv *wil)


int __wil_down(struct wil6210_priv *wil)
int __wil_down(struct wil6210_priv *wil)
{
{
	int rc;
	WARN_ON(!mutex_is_locked(&wil->mutex));
	WARN_ON(!mutex_is_locked(&wil->mutex));


	set_bit(wil_status_resetting, wil->status);
	set_bit(wil_status_resetting, wil->status);
@@ -1908,7 +1938,11 @@ int __wil_down(struct wil6210_priv *wil)
	wil_abort_scan_all_vifs(wil, false);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);


	return wil_reset(wil, false);
	down_write(&wil->mem_lock);
	rc = wil_reset(wil, false);
	up_write(&wil->mem_lock);

	return rc;
}
}


int wil_down(struct wil6210_priv *wil)
int wil_down(struct wil6210_priv *wil)
+108 −0
Original line number Original line Diff line number Diff line
@@ -283,6 +283,108 @@ static int wil_platform_rop_fw_recovery(void *wil_handle)
	return 0;
	return 0;
}
}


void wil_pci_linkdown_recovery_worker(struct work_struct *work)
{
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						pci_linkdown_recovery_worker);
	int rc, i;
	struct wil6210_vif *vif;
	struct net_device *ndev = wil->main_ndev;

	wil_dbg_misc(wil, "starting pci_linkdown recovery\n");

	rtnl_lock();
	mutex_lock(&wil->mutex);
	down_write(&wil->mem_lock);
	clear_bit(wil_status_fwready, wil->status);
	set_bit(wil_status_pci_linkdown, wil->status);
	set_bit(wil_status_resetting, wil->status);
	up_write(&wil->mem_lock);

	if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
		napi_disable(&wil->napi_rx);
		napi_disable(&wil->napi_tx);
	}

	mutex_unlock(&wil->mutex);
	rtnl_unlock();

	mutex_lock(&wil->mutex);

	mutex_lock(&wil->vif_mutex);
	wil_ftm_stop_operations(wil);
	wil_p2p_stop_radio_operations(wil);
	wil_abort_scan_all_vifs(wil, false);
	mutex_unlock(&wil->vif_mutex);

	for (i = 0; i < wil->max_vifs; i++) {
		vif = wil->vifs[i];
		if (vif) {
			cancel_work_sync(&vif->disconnect_worker);
			wil6210_disconnect(vif, NULL,
					   WLAN_REASON_DEAUTH_LEAVING);
		}
	}

	wmi_event_flush(wil);
	flush_workqueue(wil->wq_service);
	flush_workqueue(wil->wmi_wq);

	/* Recover PCIe */
	if (wil->platform_ops.pci_linkdown_recovery) {
		rc = wil->platform_ops.pci_linkdown_recovery(
			wil->platform_handle);
		if (rc) {
			wil_err(wil,
				"platform device failed to recover from pci linkdown (%d)\n",
				rc);
			mutex_unlock(&wil->mutex);
			goto out;
		}
	} else {
		wil_err(wil,
			"platform device doesn't support pci_linkdown recovery\n");
		mutex_unlock(&wil->mutex);
		goto out;
	}

	if (!ndev || !(ndev->flags & IFF_UP)) {
		wil_reset(wil, false);
		mutex_unlock(&wil->mutex);
	} else {
		mutex_unlock(&wil->mutex);
		wil->recovery_state = fw_recovery_pending;
		wil_fw_recovery(wil);
	}

out:
	return;
}

static int wil_platform_rop_notify(void *wil_handle,
				   enum wil_platform_notif notif)
{
	struct wil6210_priv *wil = wil_handle;

	if (!wil)
		return -EINVAL;

	switch (notif) {
	case WIL_PLATFORM_NOTIF_PCI_LINKDOWN:
		wil_info(wil, "received WIL_PLATFORM_NOTIF_PCI_LINKDOWN\n");
		clear_bit(wil_status_fwready, wil->status);
		set_bit(wil_status_resetting, wil->status);
		set_bit(wil_status_pci_linkdown, wil->status);

		schedule_work(&wil->pci_linkdown_recovery_worker);
		break;
	default:
		break;
	}

	return 0;
}

static void wil_platform_ops_uninit(struct wil6210_priv *wil)
static void wil_platform_ops_uninit(struct wil6210_priv *wil)
{
{
	if (wil->platform_ops.uninit)
	if (wil->platform_ops.uninit)
@@ -298,6 +400,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	const struct wil_platform_rops rops = {
	const struct wil_platform_rops rops = {
		.ramdump = wil_platform_rop_ramdump,
		.ramdump = wil_platform_rop_ramdump,
		.fw_recovery = wil_platform_rop_fw_recovery,
		.fw_recovery = wil_platform_rop_fw_recovery,
		.notify = wil_platform_rop_notify,
	};
	};
	u32 bar_size = pci_resource_len(pdev, 0);
	u32 bar_size = pci_resource_len(pdev, 0);
	int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */
	int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */
@@ -536,6 +639,11 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
	struct wil6210_priv *wil = pci_get_drvdata(pdev);
	struct wil6210_priv *wil = pci_get_drvdata(pdev);
	bool keep_radio_on, active_ifaces;
	bool keep_radio_on, active_ifaces;


	if (test_bit(wil_status_pci_linkdown, wil->status)) {
		wil_dbg_pm(wil, "ignore resume during pci linkdown\n");
		return 0;
	}

	wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
	wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");


	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
+25 −23
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
/*
 * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
 */


#include "wil6210.h"
#include "wil6210.h"
@@ -101,6 +90,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
		goto out;
		goto out;
	}
	}


	if (test_bit(wil_status_pci_linkdown, wil->status)) {
		wil_dbg_pm(wil, "Delay suspend during pci linkdown\n");
		rc = -EBUSY;
		goto out;
	}

	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	active_ifaces = wil_has_active_ifaces(wil, true, false);
	active_ifaces = wil_has_active_ifaces(wil, true, false);
	mutex_unlock(&wil->vif_mutex);
	mutex_unlock(&wil->vif_mutex);
@@ -195,14 +190,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
	wil_dbg_pm(wil, "suspend keep radio on\n");
	wil_dbg_pm(wil, "suspend keep radio on\n");


	/* Prevent handling of new tx and wmi commands */
	/* Prevent handling of new tx and wmi commands */
	set_bit(wil_status_suspending, wil->status);
	rc = down_write_trylock(&wil->mem_lock);
	if (test_bit(wil_status_collecting_dumps, wil->status)) {
	if (!rc) {
		/* Device collects crash dump, cancel the suspend */
		wil_err(wil,
		wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
			"device is busy. down_write_trylock failed, returned (0x%x)\n",
		clear_bit(wil_status_suspending, wil->status);
			rc);
		wil->suspend_stats.rejected_by_host++;
		wil->suspend_stats.rejected_by_host++;
		return -EBUSY;
		return -EBUSY;
	}
	}

	set_bit(wil_status_suspending, wil->status);
	up_write(&wil->mem_lock);

	wil_pm_stop_all_net_queues(wil);
	wil_pm_stop_all_net_queues(wil);


	if (!wil_is_tx_idle(wil)) {
	if (!wil_is_tx_idle(wil)) {
@@ -311,15 +310,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)


	wil_dbg_pm(wil, "suspend radio off\n");
	wil_dbg_pm(wil, "suspend radio off\n");


	set_bit(wil_status_suspending, wil->status);
	rc = down_write_trylock(&wil->mem_lock);
	if (test_bit(wil_status_collecting_dumps, wil->status)) {
	if (!rc) {
		/* Device collects crash dump, cancel the suspend */
		wil_err(wil,
		wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
			"device is busy. down_write_trylock failed, returned (0x%x)\n",
		clear_bit(wil_status_suspending, wil->status);
			rc);
		wil->suspend_stats.rejected_by_host++;
		wil->suspend_stats.rejected_by_host++;
		return -EBUSY;
		return -EBUSY;
	}
	}


	set_bit(wil_status_suspending, wil->status);
	up_write(&wil->mem_lock);

	/* if netif up, hardware is alive, shut it down */
	/* if netif up, hardware is alive, shut it down */
	mutex_lock(&wil->vif_mutex);
	mutex_lock(&wil->vif_mutex);
	active_ifaces = wil_has_active_ifaces(wil, true, false);
	active_ifaces = wil_has_active_ifaces(wil, true, false);
Loading