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

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

Merge "cnss2: Add idle shutdown and restart support"

parents c0968ab4 2b45e36a
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -76,6 +76,12 @@ static int cnss_stats_show_state(struct seq_file *s,
		case CNSS_DRIVER_UNLOADING:
		case CNSS_DRIVER_UNLOADING:
			seq_puts(s, "DRIVER_UNLOADING");
			seq_puts(s, "DRIVER_UNLOADING");
			continue;
			continue;
		case CNSS_DRIVER_IDLE_RESTART:
			seq_puts(s, "IDLE_RESTART");
			continue;
		case CNSS_DRIVER_IDLE_SHUTDOWN:
			seq_puts(s, "IDLE_SHUTDOWN");
			continue;
		case CNSS_DRIVER_PROBED:
		case CNSS_DRIVER_PROBED:
			seq_puts(s, "DRIVER_PROBED");
			seq_puts(s, "DRIVER_PROBED");
			continue;
			continue;
+95 −10
Original line number Original line Diff line number Diff line
@@ -482,6 +482,10 @@ static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
		return "POWER_UP";
		return "POWER_UP";
	case CNSS_DRIVER_EVENT_POWER_DOWN:
	case CNSS_DRIVER_EVENT_POWER_DOWN:
		return "POWER_DOWN";
		return "POWER_DOWN";
	case CNSS_DRIVER_EVENT_IDLE_RESTART:
		return "IDLE_RESTART";
	case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
		return "IDLE_SHUTDOWN";
	case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
	case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
		return "QDSS_TRACE_REQ_MEM";
		return "QDSS_TRACE_REQ_MEM";
	case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE:
	case CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE:
@@ -637,13 +641,74 @@ EXPORT_SYMBOL(cnss_power_down);


int cnss_idle_restart(struct device *dev)
int cnss_idle_restart(struct device *dev)
{
{
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
	unsigned int timeout;
	int ret = 0;

	if (!plat_priv) {
		cnss_pr_err("plat_priv is NULL\n");
		return -ENODEV;
	}

	cnss_pr_dbg("Doing idle restart\n");

	ret = cnss_driver_event_post(plat_priv,
				     CNSS_DRIVER_EVENT_IDLE_RESTART,
				     CNSS_EVENT_SYNC, NULL);
	if (ret)
		goto out;

	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
		ret = cnss_bus_call_driver_probe(plat_priv);
		goto out;
	}

	timeout = cnss_get_boot_timeout(dev);

	reinit_completion(&plat_priv->power_up_complete);
	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
					  msecs_to_jiffies(timeout) << 2);
	if (!ret) {
		cnss_pr_err("Timeout waiting for idle restart to complete\n");
		ret = -EAGAIN;
		goto out;
	}

	return 0;
	return 0;

out:
	return ret;
}
}
EXPORT_SYMBOL(cnss_idle_restart);
EXPORT_SYMBOL(cnss_idle_restart);


int cnss_idle_shutdown(struct device *dev)
int cnss_idle_shutdown(struct device *dev)
{
{
	return 0;
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
	int ret;

	if (!plat_priv) {
		cnss_pr_err("plat_priv is NULL\n");
		return -ENODEV;
	}

	cnss_pr_dbg("Doing idle shutdown\n");

	if (!test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
	    !test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
		goto skip_wait;

	reinit_completion(&plat_priv->recovery_complete);
	ret = wait_for_completion_timeout(&plat_priv->recovery_complete,
					  RECOVERY_TIMEOUT);
	if (!ret) {
		cnss_pr_err("Timeout waiting for recovery to complete\n");
		CNSS_ASSERT(0);
	}

skip_wait:
	return cnss_driver_event_post(plat_priv,
				      CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
				      CNSS_EVENT_SYNC, NULL);
}
}
EXPORT_SYMBOL(cnss_idle_shutdown);
EXPORT_SYMBOL(cnss_idle_shutdown);


@@ -965,16 +1030,19 @@ static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
		goto out;
		goto out;
	}
	}


	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
		cnss_pr_err("Driver unload is in progress, ignore recovery\n");
	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
		cnss_pr_err("Driver unload or idle shutdown is in progress, ignore recovery\n");
		ret = -EINVAL;
		ret = -EINVAL;
		goto out;
		goto out;
	}
	}


	switch (plat_priv->device_id) {
	switch (plat_priv->device_id) {
	case QCA6174_DEVICE_ID:
	case QCA6174_DEVICE_ID:
		if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
		if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
			cnss_pr_err("Driver load is in progress, ignore recovery\n");
		    test_bit(CNSS_DRIVER_IDLE_RESTART,
			     &plat_priv->driver_state)) {
			cnss_pr_err("Driver load or idle restart is in progress, ignore recovery\n");
			ret = -EINVAL;
			ret = -EINVAL;
			goto out;
			goto out;
		}
		}
@@ -1012,8 +1080,9 @@ void cnss_schedule_recovery(struct device *dev,


	cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
	cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);


	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
		cnss_pr_dbg("Driver unload is in progress, ignore schedule recovery\n");
	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
		cnss_pr_dbg("Driver unload or idle shutdown is in progress, ignore schedule recovery\n");
		return;
		return;
	}
	}


@@ -1092,8 +1161,10 @@ int cnss_force_collect_rddm(struct device *dev)
	}
	}


	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
	    test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
		cnss_pr_info("Loading/Unloading is in progress, ignore forced collect rddm\n");
	    test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
		cnss_pr_info("Loading/Unloading/idle restart/shutdown is in progress, ignore forced collect rddm\n");
		return 0;
		return 0;
	}
	}


@@ -1152,7 +1223,13 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)


static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
{
{
	return cnss_bus_dev_powerup(plat_priv);
	int ret;

	ret = cnss_bus_dev_powerup(plat_priv);
	if (ret)
		clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);

	return ret;
}
}


static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
@@ -1332,9 +1409,17 @@ static void cnss_driver_event_work(struct work_struct *work)
		case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
		case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
			ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
			ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
			break;
			break;
		case CNSS_DRIVER_EVENT_IDLE_RESTART:
			set_bit(CNSS_DRIVER_IDLE_RESTART,
				&plat_priv->driver_state);
			/* fall through */
		case CNSS_DRIVER_EVENT_POWER_UP:
		case CNSS_DRIVER_EVENT_POWER_UP:
			ret = cnss_power_up_hdlr(plat_priv);
			ret = cnss_power_up_hdlr(plat_priv);
			break;
			break;
		case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
			set_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
				&plat_priv->driver_state);
			/* fall through */
		case CNSS_DRIVER_EVENT_POWER_DOWN:
		case CNSS_DRIVER_EVENT_POWER_DOWN:
			ret = cnss_power_down_hdlr(plat_priv);
			ret = cnss_power_down_hdlr(plat_priv);
			break;
			break;
+5 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#define QMI_WLFW_MAX_TIMESTAMP_LEN	32
#define QMI_WLFW_MAX_TIMESTAMP_LEN	32
#define QMI_WLFW_MAX_NUM_MEM_SEG	32
#define QMI_WLFW_MAX_NUM_MEM_SEG	32
#define CNSS_RDDM_TIMEOUT_MS		20000
#define CNSS_RDDM_TIMEOUT_MS		20000
#define RECOVERY_TIMEOUT		60000


#define CNSS_EVENT_SYNC   BIT(0)
#define CNSS_EVENT_SYNC   BIT(0)
#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
@@ -161,6 +162,8 @@ enum cnss_driver_event_type {
	CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
	CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
	CNSS_DRIVER_EVENT_POWER_UP,
	CNSS_DRIVER_EVENT_POWER_UP,
	CNSS_DRIVER_EVENT_POWER_DOWN,
	CNSS_DRIVER_EVENT_POWER_DOWN,
	CNSS_DRIVER_EVENT_IDLE_RESTART,
	CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
	CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
	CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
	CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE,
	CNSS_DRIVER_EVENT_QDSS_TRACE_SAVE,
	CNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
	CNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
@@ -174,6 +177,8 @@ enum cnss_driver_state {
	CNSS_COLD_BOOT_CAL,
	CNSS_COLD_BOOT_CAL,
	CNSS_DRIVER_LOADING,
	CNSS_DRIVER_LOADING,
	CNSS_DRIVER_UNLOADING,
	CNSS_DRIVER_UNLOADING,
	CNSS_DRIVER_IDLE_RESTART,
	CNSS_DRIVER_IDLE_SHUTDOWN,
	CNSS_DRIVER_PROBED,
	CNSS_DRIVER_PROBED,
	CNSS_DRIVER_RECOVERY,
	CNSS_DRIVER_RECOVERY,
	CNSS_FW_BOOT_RECOVERY,
	CNSS_FW_BOOT_RECOVERY,
+21 −2
Original line number Original line Diff line number Diff line
@@ -43,7 +43,6 @@


#define FW_ASSERT_TIMEOUT		5000
#define FW_ASSERT_TIMEOUT		5000
#define DEV_RDDM_TIMEOUT		5000
#define DEV_RDDM_TIMEOUT		5000
#define RECOVERY_TIMEOUT		60000


#ifdef CONFIG_CNSS_EMULATION
#ifdef CONFIG_CNSS_EMULATION
#define EMULATION_HW			1
#define EMULATION_HW			1
@@ -460,6 +459,18 @@ int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
		set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
		set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
	} else if (test_bit(CNSS_DRIVER_IDLE_RESTART,
			    &plat_priv->driver_state)) {
		ret = pci_priv->driver_ops->idle_restart(pci_priv->pci_dev,
			pci_priv->pci_device_id);
		if (ret) {
			cnss_pr_err("Failed to idle restart host driver, err = %d\n",
				    ret);
			goto out;
		}
		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
		clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);
		complete(&plat_priv->power_up_complete);
	} else {
	} else {
		complete(&plat_priv->power_up_complete);
		complete(&plat_priv->power_up_complete);
	}
	}
@@ -498,6 +509,10 @@ int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
		pci_priv->driver_ops->remove(pci_priv->pci_dev);
		pci_priv->driver_ops->remove(pci_priv->pci_dev);
		clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
		clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
		clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
		clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
	} else if (test_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
			    &plat_priv->driver_state)) {
		pci_priv->driver_ops->idle_shutdown(pci_priv->pci_dev);
		clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
	}
	}


	return 0;
	return 0;
@@ -641,6 +656,7 @@ static int cnss_qca6174_shutdown(struct cnss_pci_data *pci_priv)
	cnss_power_off_device(plat_priv);
	cnss_power_off_device(plat_priv);


	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
	clear_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state);


	return ret;
	return ret;
}
}
@@ -749,7 +765,9 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
	cnss_pci_set_auto_suspended(pci_priv, 0);
	cnss_pci_set_auto_suspended(pci_priv, 0);


	if ((test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	if ((test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	     test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) &&
	     test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
	     test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) ||
	     test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) &&
	    test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
	    test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
		del_timer(&pci_priv->dev_rddm_timer);
		del_timer(&pci_priv->dev_rddm_timer);
		cnss_pci_collect_dump(pci_priv);
		cnss_pci_collect_dump(pci_priv);
@@ -768,6 +786,7 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
	clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
	clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
	clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
	clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
	clear_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state);


	return ret;
	return ret;
}
}