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

Commit ec9c04b8 authored by Naman Padhiar's avatar Naman Padhiar
Browse files

icnss: Synchronize idle shutdown and restart



If WLAN interface is not brought up for certain amount of time
after it is created, idle shutdown will happen to power off WLAN
device. Idle restart will happen to power up WLAN device if WLAN
is needed by user again. Add the support in platform driver.

Change-Id: I63e85c7de20536fc4146e05146e72537095025e5
Signed-off-by: default avatarNaman Padhiar <npadhiar@codeaurora.org>
parent 07b2428d
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -199,6 +199,8 @@ enum icnss_driver_event_type {
	ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
	ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
	ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
	ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
	ICNSS_DRIVER_EVENT_IDLE_RESTART,
	ICNSS_DRIVER_EVENT_MAX,
};

@@ -291,6 +293,7 @@ enum icnss_driver_state {
	ICNSS_MODE_ON,
	ICNSS_BLOCK_SHUTDOWN,
	ICNSS_PDR,
	ICNSS_MODEM_CRASHED,
};

struct ce_irq_list {
@@ -626,6 +629,10 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type)
		return "PD_SERVICE_DOWN";
	case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
		return "FW_EARLY_CRASH_IND";
	case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
		return "IDLE_SHUTDOWN";
	case ICNSS_DRIVER_EVENT_IDLE_RESTART:
		return "IDLE_RESTART";
	case ICNSS_DRIVER_EVENT_MAX:
		return "EVENT_MAX";
	}
@@ -2361,6 +2368,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
	icnss_call_driver_shutdown(priv);

	clear_bit(ICNSS_PDR, &priv->state);
	clear_bit(ICNSS_MODEM_CRASHED, &priv->state);
	clear_bit(ICNSS_REJUVENATE, &priv->state);
	clear_bit(ICNSS_PD_RESTART, &priv->state);
	priv->early_crash_ind = false;
@@ -2707,6 +2715,51 @@ static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv,
	return ret;
}

static int icnss_driver_event_idle_shutdown(void *data)
{
	int ret = 0;

	if (!penv->ops || !penv->ops->idle_shutdown)
		return 0;

	if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
			test_bit(ICNSS_PDR, &penv->state) ||
			test_bit(ICNSS_REJUVENATE, &penv->state)) {
		icnss_pr_err("SSR/PDR is already in-progress during idle shutdown callback\n");
		ret = -EBUSY;
	} else {
		icnss_pr_dbg("Calling driver idle shutdown, state: 0x%lx\n",
								penv->state);
		icnss_block_shutdown(true);
		ret = penv->ops->idle_shutdown(&penv->pdev->dev);
		icnss_block_shutdown(false);
	}

	return ret;
}

static int icnss_driver_event_idle_restart(void *data)
{
	int ret = 0;

	if (!penv->ops || !penv->ops->idle_restart)
		return 0;

	if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
			test_bit(ICNSS_PDR, &penv->state) ||
			test_bit(ICNSS_REJUVENATE, &penv->state)) {
		icnss_pr_err("SSR/PDR is already in-progress during idle restart callback\n");
		ret = -EBUSY;
	} else {
		icnss_pr_dbg("Calling driver idle restart, state: 0x%lx\n",
								penv->state);
		icnss_block_shutdown(true);
		ret = penv->ops->idle_restart(&penv->pdev->dev);
		icnss_block_shutdown(false);
	}

	return ret;
}

static void icnss_driver_event_work(struct work_struct *work)
{
@@ -2753,6 +2806,12 @@ static void icnss_driver_event_work(struct work_struct *work)
			ret = icnss_driver_event_early_crash_ind(penv,
								 event->data);
			break;
		case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
			ret = icnss_driver_event_idle_shutdown(event->data);
			break;
		case ICNSS_DRIVER_EVENT_IDLE_RESTART:
			ret = icnss_driver_event_idle_restart(event->data);
			break;
		default:
			icnss_pr_err("Invalid Event type: %d", event->type);
			kfree(event);
@@ -2861,6 +2920,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,

	priv->is_ssr = true;

	if (notif->crashed)
		set_bit(ICNSS_MODEM_CRASHED, &priv->state);

	if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed &&
	    test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
		if (!wait_for_completion_timeout(&priv->unblock_shutdown,
@@ -3745,6 +3807,48 @@ int icnss_trigger_recovery(struct device *dev)
}
EXPORT_SYMBOL(icnss_trigger_recovery);

int icnss_idle_shutdown(struct device *dev)
{
	struct icnss_priv *priv = dev_get_drvdata(dev);

	if (!priv) {
		icnss_pr_err("Invalid drvdata: dev %pK", dev);
		return -EINVAL;
	}

	if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
			test_bit(ICNSS_PDR, &priv->state) ||
			test_bit(ICNSS_REJUVENATE, &penv->state)) {
		icnss_pr_err("SSR/PDR is already in-progress during idle shutdown\n");
		return -EBUSY;
	}

	return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
					ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
}
EXPORT_SYMBOL(icnss_idle_shutdown);

int icnss_idle_restart(struct device *dev)
{
	struct icnss_priv *priv = dev_get_drvdata(dev);

	if (!priv) {
		icnss_pr_err("Invalid drvdata: dev %pK", dev);
		return -EINVAL;
	}

	if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
			test_bit(ICNSS_PDR, &priv->state) ||
			test_bit(ICNSS_REJUVENATE, &penv->state)) {
		icnss_pr_err("SSR/PDR is already in-progress during idle restart\n");
		return -EBUSY;
	}

	return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_RESTART,
					ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
}
EXPORT_SYMBOL(icnss_idle_restart);


static int icnss_smmu_init(struct icnss_priv *priv)
{
@@ -4241,6 +4345,10 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
			continue;
		case ICNSS_PDR:
			seq_puts(s, "PDR TRIGGERED");
			continue;
		case ICNSS_MODEM_CRASHED:
			seq_puts(s, "MODEM CRASHED");
			continue;
		}

		seq_printf(s, "UNKNOWN-%d", i);
+4 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ struct icnss_driver_ops {
	int (*resume_noirq)(struct device *dev);
	int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
	int (*set_therm_state)(struct device *dev, unsigned long thermal_state);
	int (*idle_shutdown)(struct device *dev);
	int (*idle_restart)(struct device *dev);
};


@@ -151,4 +153,6 @@ extern int icnss_thermal_register(struct device *dev, unsigned long max_state);
extern void icnss_thermal_unregister(struct device *dev);
extern int icnss_get_curr_therm_state(struct device *dev,
					unsigned long *thermal_state);
extern int icnss_idle_restart(struct device *dev);
extern int icnss_idle_shutdown(struct device *dev);
#endif /* _ICNSS_WLAN_H_ */