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

Commit d1bfc82a authored by Yuanyuan Liu's avatar Yuanyuan Liu
Browse files

cnss2: Add new arguments for recovery APIs



Add dev instance and recovery reason for recovery APIs as these
APIs are target specific and have different recovery mode based
on the recovery reason. These changes are added as new APIs
to avoid breaking WLAN functionality. The old recovery APIs
will be removed once WLAN host driver switch to the new APIs.

CRs-Fixed: 1111417
Change-Id: Idc40962f7dde56b4b082594f4ebaea9c4352af43
Signed-off-by: default avatarYuanyuan Liu <yuanliu@codeaurora.org>
parent 02f0c5a1
Loading
Loading
Loading
Loading
+68 −1
Original line number Diff line number Diff line
@@ -556,6 +556,14 @@ static void cnss_driver_event_work(struct work_struct *work)
	spin_unlock_irqrestore(&plat_priv->event_lock, flags);
}

static void cnss_recovery_work_func(struct work_struct *work)
{
	struct cnss_recovery_work_t *ctx =
		container_of(work, struct cnss_recovery_work_t, work);

	cnss_self_recovery(ctx->dev, ctx->reason);
}

int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
			   enum cnss_driver_event_type type,
			   bool sync, void *data)
@@ -1276,6 +1284,51 @@ void cnss_device_self_recovery(void)
}
EXPORT_SYMBOL(cnss_device_self_recovery);

int cnss_self_recovery(struct device *dev,
		       enum cnss_recovery_reason reason)
{
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
	struct cnss_subsys_info *subsys_info;

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

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

	if (!plat_priv->driver_ops) {
		cnss_pr_err("Driver is not registered yet!\n");
		return -EINVAL;
	}

	if (plat_priv->driver_status == CNSS_RECOVERY) {
		cnss_pr_err("Recovery is already in progress!\n");
		return -EINVAL;
	}

	if (plat_priv->driver_status == CNSS_LOAD_UNLOAD) {
		cnss_pr_err("Driver load or unload is in progress!\n");
		return -EINVAL;
	}

	subsys_info = &plat_priv->subsys_info;
	plat_priv->recovery_count++;
	plat_priv->driver_status = CNSS_RECOVERY;
	pm_stay_awake(dev);
	cnss_shutdown(&subsys_info->subsys_desc, false);
	udelay(WLAN_RECOVERY_DELAY);
	cnss_powerup(&subsys_info->subsys_desc);
	pm_relax(dev);
	plat_priv->driver_status = CNSS_INITIALIZED;

	return 0;
}
EXPORT_SYMBOL(cnss_self_recovery);

void cnss_recovery_work_handler(struct work_struct *recovery)
{
	cnss_device_self_recovery();
@@ -1289,6 +1342,18 @@ void cnss_schedule_recovery_work(void)
}
EXPORT_SYMBOL(cnss_schedule_recovery_work);

void cnss_schedule_recovery(struct device *dev,
			    enum cnss_recovery_reason reason)
{
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
	struct cnss_recovery_work_t *work = &plat_priv->cnss_recovery_work;

	work->dev = dev;
	work->reason = reason;
	queue_work(plat_priv->event_wq, &work->work);
}
EXPORT_SYMBOL(cnss_schedule_recovery);

int cnss_register_subsys(struct cnss_plat_data *plat_priv)
{
	int ret = 0;
@@ -1554,7 +1619,7 @@ static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
{
	spin_lock_init(&plat_priv->event_lock);
	plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
					      WQ_UNBOUND, 1);
					      0, 0);
	if (!plat_priv->event_wq) {
		cnss_pr_err("Failed to create event workqueue!\n");
		return -EFAULT;
@@ -1562,6 +1627,8 @@ static int cnss_event_work_init(struct cnss_plat_data *plat_priv)

	INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
	INIT_LIST_HEAD(&plat_priv->event_list);
	INIT_WORK(&plat_priv->cnss_recovery_work.work,
		  cnss_recovery_work_func);
	init_completion(&plat_priv->fw_ready_event);

	return 0;
+7 −0
Original line number Diff line number Diff line
@@ -108,6 +108,12 @@ enum cnss_driver_state {
	CNSS_DRIVER_PROBED,
};

struct cnss_recovery_work_t {
	struct work_struct work;
	struct device *dev;
	enum cnss_recovery_reason reason;
};

struct cnss_plat_data {
	struct platform_device *plat_dev;
	void *bus_priv;
@@ -131,6 +137,7 @@ struct cnss_plat_data {
	spinlock_t event_lock; /* spinlock for driver work event handling */
	struct work_struct event_work;
	struct workqueue_struct *event_wq;
	struct cnss_recovery_work_t cnss_recovery_work;
	struct qmi_handle *qmi_wlfw_clnt;
	struct work_struct qmi_recv_msg_work;
	struct notifier_block qmi_wlfw_clnt_nb;
+35 −0
Original line number Diff line number Diff line
@@ -202,6 +202,41 @@ void cnss_wlan_pci_link_down(void)
}
EXPORT_SYMBOL(cnss_wlan_pci_link_down);

int cnss_pci_link_down(struct device *dev)
{
	unsigned long flags;
	struct pci_dev *pci_dev = to_pci_dev(dev);
	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);

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

	if (!pci_priv) {
		cnss_pr_err("pci_priv is NULL!\n");
		return -EINVAL;
	}

	if (pci_link_down_panic)
		panic("cnss: PCI link is down!\n");

	spin_lock_irqsave(&pci_link_down_lock, flags);
	if (pci_priv->pci_link_down_ind) {
		cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
		spin_unlock_irqrestore(&pci_link_down_lock, flags);
		return -EINVAL;
	}
	pci_priv->pci_link_down_ind = true;
	spin_unlock_irqrestore(&pci_link_down_lock, flags);

	cnss_pr_err("PCI link down is detected by host driver, schedule recovery!\n");
	cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN);
	return 0;
}
EXPORT_SYMBOL(cnss_pci_link_down);

static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
{
	int ret = 0;
+10 −0
Original line number Diff line number Diff line
@@ -127,12 +127,22 @@ enum cnss_driver_mode {
	CNSS_CALIBRATION,
};

enum cnss_recovery_reason {
	CNSS_REASON_DEFAULT,
	CNSS_REASON_LINK_DOWN,
};

extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
extern void cnss_wlan_pci_link_down(void);
extern void cnss_schedule_recovery_work(void);
extern void cnss_device_crashed(void);
extern void cnss_device_self_recovery(void);
extern int cnss_pci_link_down(struct device *dev);
extern void cnss_schedule_recovery(struct device *dev,
				   enum cnss_recovery_reason reason);
extern int cnss_self_recovery(struct device *dev,
			      enum cnss_recovery_reason reason);
extern void *cnss_get_virt_ramdump_mem(unsigned long *size);
extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
					u32 target_type, u32 target_version);