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

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

Merge "msm_11ad: support pcie linkdown recovery"

parents 2326e3cf 6e7458a4
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -536,23 +536,16 @@ bool wil_is_recovery_blocked(struct wil6210_priv *wil)
	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 wireless_dev *wdev;

	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_dbg_misc(wil, "fw recovery\n");

	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
	 */
	if (time_is_after_jiffies(wil->last_fw_recovery +
@@ -612,6 +605,22 @@ static void wil_fw_error_worker(struct work_struct *work)
	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)
{
	int i;
@@ -724,6 +733,8 @@ int wil_priv_init(struct wil6210_priv *wil)

	INIT_WORK(&wil->wmi_event_worker, wmi_event_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);
	spin_lock_init(&wil->wmi_ev_lock);
@@ -839,6 +850,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)

	wil_set_recovery_state(wil, fw_recovery_idle);
	cancel_work_sync(&wil->fw_error_worker);
	cancel_work_sync(&wil->pci_linkdown_recovery_worker);
	wmi_event_flush(wil);
	destroy_workqueue(wil->wq_service);
	destroy_workqueue(wil->wmi_wq);
+109 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2012-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
@@ -298,6 +298,108 @@ static int wil_platform_rop_fw_recovery(void *wil_handle)
	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)
{
	if (wil->platform_ops.uninit)
@@ -313,6 +415,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	const struct wil_platform_rops rops = {
		.ramdump = wil_platform_rop_ramdump,
		.fw_recovery = wil_platform_rop_fw_recovery,
		.notify = wil_platform_rop_notify,
	};
	u32 bar_size = pci_resource_len(pdev, 0);
	int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */
@@ -560,6 +663,11 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
	struct wil6210_priv *wil = pci_get_drvdata(pdev);
	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");

	mutex_lock(&wil->vif_mutex);
+6 −0
Original line number Diff line number Diff line
@@ -101,6 +101,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
		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);
	active_ifaces = wil_has_active_ifaces(wil, true, false);
	mutex_unlock(&wil->vif_mutex);
+6 −0
Original line number Diff line number Diff line
@@ -661,6 +661,7 @@ enum { /* for wil6210_priv.status */
	wil_status_suspending, /* suspend in progress */
	wil_status_suspended, /* suspend completed, device is suspended */
	wil_status_resuming, /* resume in progress */
	wil_status_pci_linkdown, /* pci linkdown occurred */
	wil_status_last /* keep last */
};

@@ -1074,6 +1075,8 @@ struct wil6210_priv {
	u32 max_ampdu_size;

	struct wil_fw_stats_global fw_stats_global;

	struct work_struct pci_linkdown_recovery_worker;
};

#define wil_to_wiphy(i) (i->wiphy)
@@ -1365,6 +1368,9 @@ void wil_disconnect_worker(struct work_struct *work);

void wil_init_txrx_ops(struct wil6210_priv *wil);

void wil_fw_recovery(struct wil6210_priv *wil);
void wil_pci_linkdown_recovery_worker(struct work_struct *work);

/* TX API */
int wil_ring_init_tx(struct wil6210_vif *vif, int cid);
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
+9 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 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
@@ -27,6 +28,10 @@ enum wil_platform_event {
	WIL_PLATFORM_EVT_POST_SUSPEND = 4,
};

enum wil_platform_notif {
	WIL_PLATFORM_NOTIF_PCI_LINKDOWN = 0,
};

enum wil_platform_features {
	WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0,
	WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1,
@@ -52,6 +57,7 @@ struct wil_platform_ops {
	int (*notify)(void *handle, enum wil_platform_event evt);
	int (*get_capa)(void *handle);
	void (*set_features)(void *handle, int features);
	int (*pci_linkdown_recovery)(void *handle);
};

/**
@@ -63,10 +69,13 @@ struct wil_platform_ops {
 * @fw_recovery: start a firmware recovery process. Called as
 *      part of a crash recovery process which may include other
 *      related platform subsystems.
 * @notify: get notifications from the Platform driver, such as
 *      pci linkdown
 */
struct wil_platform_rops {
	int (*ramdump)(void *wil_handle, void *buf, uint32_t size);
	int (*fw_recovery)(void *wil_handle);
	int (*notify)(void *wil_handle, enum wil_platform_notif notif);
};

/**
Loading