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

Commit de20a599 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "icnss: Synchronize idle shutdown and restart"

parents c3ebb2d5 ec9c04b8
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_ */