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

Commit f60b827c authored by Sujeev Dias's avatar Sujeev Dias
Browse files

mhi: core: add support for early error notifications



Some MHI based devices transfer time sensitive data and require
early termination of active transfers even before MHI teardown
happens. This change immediately transitions MHI into an error
state and notify such devices.

CRs-Fixed: 2459916
Change-Id: Ic647bd34e01f39389f3eda0f8a0dc096190fe39b
Signed-off-by: default avatarSujeev Dias <sdias@codeaurora.org>
parent 5294afaf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -757,6 +757,7 @@ int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl);
int mhi_create_vote_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_vote_sysfs(struct mhi_controller *mhi_cntrl);
int mhi_early_notify_device(struct device *dev, void *data);

/* timesync log support */
static inline void mhi_timesync_log(struct mhi_controller *mhi_cntrl)
+23 −0
Original line number Diff line number Diff line
@@ -637,6 +637,22 @@ int mhi_destroy_device(struct device *dev, void *data)
	return 0;
}

int mhi_early_notify_device(struct device *dev, void *data)
{
	struct mhi_device *mhi_dev = to_mhi_device(dev);
	struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;

	/* skip early notification */
	if (!mhi_dev->early_notif)
		return 0;

	MHI_LOG("Early notification for dev:%s\n", mhi_dev->chan_name);

	mhi_notify(mhi_dev, MHI_CB_FATAL_ERROR);

	return 0;
}

void mhi_notify(struct mhi_device *mhi_dev, enum MHI_CB cb_reason)
{
	struct mhi_driver *mhi_drv;
@@ -847,6 +863,13 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl)
		/* add if there is a matching DT node */
		mhi_assign_of_node(mhi_cntrl, mhi_dev);

		/*
		 * if set, these device should get a early notification during
		 * early notification state
		 */
		mhi_dev->early_notif =
			of_property_read_bool(mhi_dev->dev.of_node,
					      "mhi,early-notify");
		/* init wake source */
		if (mhi_dev->dl_chan && mhi_dev->dl_chan->wake_capable)
			device_init_wakeup(&mhi_dev->dev, true);
+30 −0
Original line number Diff line number Diff line
@@ -873,6 +873,36 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
}
EXPORT_SYMBOL(mhi_async_power_up);

/* Transition MHI into error state and notify critical clients */
void mhi_control_error(struct mhi_controller *mhi_cntrl)
{
	enum MHI_PM_STATE cur_state;

	MHI_LOG("Enter with pm_state:%s MHI_STATE:%s\n",
		to_mhi_pm_state_str(mhi_cntrl->pm_state),
		TO_MHI_STATE_STR(mhi_cntrl->dev_state));

	write_lock_irq(&mhi_cntrl->pm_lock);
	cur_state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_LD_ERR_FATAL_DETECT);
	write_unlock_irq(&mhi_cntrl->pm_lock);

	if (cur_state != MHI_PM_LD_ERR_FATAL_DETECT) {
		MHI_ERR("Failed to transition to state:%s from:%s\n",
			to_mhi_pm_state_str(MHI_PM_LD_ERR_FATAL_DETECT),
			to_mhi_pm_state_str(cur_state));
		goto exit_control_error;
	}

	/* start notifying all clients who request early notification */
	device_for_each_child(mhi_cntrl->dev, NULL, mhi_early_notify_device);

exit_control_error:
	MHI_LOG("Exit with pm_state:%s MHI_STATE:%s\n",
		to_mhi_pm_state_str(mhi_cntrl->pm_state),
		TO_MHI_STATE_STR(mhi_cntrl->dev_state));
}
EXPORT_SYMBOL(mhi_control_error);

void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
{
	enum MHI_PM_STATE cur_state;
+11 −0
Original line number Diff line number Diff line
@@ -331,6 +331,8 @@ struct mhi_controller {
 * @ul_chan_id: MHI channel id for UL transfer
 * @dl_chan_id: MHI channel id for DL transfer
 * @tiocm: Device current terminal settings
 * @early_notif: This device needs an early notification in case of error
 * with external modem.
 * @dev_vote: Keep external device in active state
 * @bus_vote: Keep physical bus (pci, spi) in active state
 * @priv: Driver private data
@@ -347,6 +349,7 @@ struct mhi_device {
	int ul_event_id;
	int dl_event_id;
	u32 tiocm;
	bool early_notif;
	const struct mhi_device_id *id;
	const char *chan_name;
	struct mhi_controller *mhi_cntrl;
@@ -699,6 +702,14 @@ static inline bool mhi_is_active(struct mhi_device *mhi_dev)
		mhi_cntrl->dev_state <= MHI_STATE_M3_FAST);
}

/**
 * mhi_control_error - MHI controller went into unrecoverable error state.
 * Will transition MHI into Linkdown state. Do not call from atomic
 * context.
 * @mhi_cntrl: MHI controller
 */
void mhi_control_error(struct mhi_controller *mhi_cntrl);

/**
 * mhi_debug_reg_dump - dump MHI registers for debug purpose
 * @mhi_cntrl: MHI controller