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

Commit 2bb68dc7 authored by Sameer Thalappil's avatar Sameer Thalappil
Browse files

icnss: Refactor QMI interface



WLAN host uses QMI as the transport to communicate the initial
control messages with WLAN firmware. Refactor the code such a
way that the transport can be ported to other interfaces.

Some of the data structures used by icnss for it's internal
operations are from the QMI generated code; remove all such
dependencies from QMI framework.

This change also makes sure that icnss driver can be compiled
even when QMI framework is not available.

Change-Id: Ib585a611b3dd42e96c810ddb54244bcdc4aaa47c
Signed-off-by: default avatarSameer Thalappil <sameert@codeaurora.org>
parent 4ba9441e
Loading
Loading
Loading
Loading
+52 −1330

File changed.

Preview size limit exceeded, changes collapsed.

+362 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __ICNSS_PRIVATE_H__
#define __ICNSS_PRIVATE_H__

#define icnss_ipc_log_string(_x...) do {				\
	if (icnss_ipc_log_context)					\
		ipc_log_string(icnss_ipc_log_context, _x);		\
	} while (0)

#define icnss_ipc_log_long_string(_x...) do {				\
	if (icnss_ipc_log_long_context)					\
		ipc_log_string(icnss_ipc_log_long_context, _x);		\
	} while (0)

#define icnss_pr_err(_fmt, ...) do {					\
	printk("%s" pr_fmt(_fmt), KERN_ERR, ##__VA_ARGS__);		\
	icnss_ipc_log_string("%s" pr_fmt(_fmt), "",			\
			     ##__VA_ARGS__);				\
	} while (0)

#define icnss_pr_warn(_fmt, ...) do {					\
	printk("%s" pr_fmt(_fmt), KERN_WARNING, ##__VA_ARGS__);		\
	icnss_ipc_log_string("%s" pr_fmt(_fmt), "",			\
			     ##__VA_ARGS__);				\
	} while (0)

#define icnss_pr_info(_fmt, ...) do {					\
	printk("%s" pr_fmt(_fmt), KERN_INFO, ##__VA_ARGS__);		\
	icnss_ipc_log_string("%s" pr_fmt(_fmt), "",			\
			     ##__VA_ARGS__);				\
	} while (0)

#if defined(CONFIG_DYNAMIC_DEBUG)
#define icnss_pr_dbg(_fmt, ...) do {					\
	pr_debug(_fmt, ##__VA_ARGS__);					\
	icnss_ipc_log_string(pr_fmt(_fmt), ##__VA_ARGS__);		\
	} while (0)

#define icnss_pr_vdbg(_fmt, ...) do {					\
	pr_debug(_fmt, ##__VA_ARGS__);					\
	icnss_ipc_log_long_string(pr_fmt(_fmt), ##__VA_ARGS__);		\
	} while (0)
#elif defined(DEBUG)
#define icnss_pr_dbg(_fmt, ...) do {					\
	printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__);		\
	icnss_ipc_log_string("%s" pr_fmt(_fmt), "",			\
			     ##__VA_ARGS__);				\
	} while (0)

#define icnss_pr_vdbg(_fmt, ...) do {					\
	printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__);		\
	icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "",		\
				  ##__VA_ARGS__);			\
	} while (0)
#else
#define icnss_pr_dbg(_fmt, ...) do {					\
	no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__);	\
	icnss_ipc_log_string("%s" pr_fmt(_fmt), "",			\
		     ##__VA_ARGS__);					\
	} while (0)

#define icnss_pr_vdbg(_fmt, ...) do {					\
	no_printk("%s" pr_fmt(_fmt), KERN_DEBUG, ##__VA_ARGS__);	\
	icnss_ipc_log_long_string("%s" pr_fmt(_fmt), "",		\
				  ##__VA_ARGS__);			\
	} while (0)
#endif

#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do {					\
		if (!(_condition)) {					\
			icnss_pr_err("ASSERT at line %d\n", __LINE__);	\
			BUG();						\
		}							\
	} while (0)
#else
#define ICNSS_ASSERT(_condition) do { } while (0)
#endif

enum icnss_debug_quirks {
	HW_ALWAYS_ON,
	HW_DEBUG_ENABLE,
	SKIP_QMI,
	HW_ONLY_TOP_LEVEL_RESET,
	RECOVERY_DISABLE,
	SSR_ONLY,
	PDR_ONLY,
	VBATT_DISABLE,
	FW_REJUVENATE_ENABLE,
};

extern uint64_t dynamic_feature_mask;
extern void *icnss_ipc_log_context;
extern void *icnss_ipc_log_long_context;
extern unsigned long quirks;

enum icnss_driver_event_type {
	ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
	ICNSS_DRIVER_EVENT_SERVER_EXIT,
	ICNSS_DRIVER_EVENT_FW_READY_IND,
	ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
	ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
	ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
	ICNSS_DRIVER_EVENT_MAX,
};

struct icnss_event_pd_service_down_data {
	bool crashed;
	bool fw_rejuvenate;
	bool wdog_bite;
};

struct icnss_driver_event {
	struct list_head list;
	enum icnss_driver_event_type type;
	bool sync;
	struct completion complete;
	int ret;
	void *data;
};

enum icnss_driver_state {
	ICNSS_WLFW_CONNECTED,
	ICNSS_POWER_ON,
	ICNSS_FW_READY,
	ICNSS_DRIVER_PROBED,
	ICNSS_FW_TEST_MODE,
	ICNSS_PM_SUSPEND,
	ICNSS_PM_SUSPEND_NOIRQ,
	ICNSS_SSR_REGISTERED,
	ICNSS_PDR_REGISTERED,
	ICNSS_PD_RESTART,
	ICNSS_MSA0_ASSIGNED,
	ICNSS_WLFW_EXISTS,
	ICNSS_WDOG_BITE,
	ICNSS_SHUTDOWN_DONE,
	ICNSS_HOST_TRIGGERED_PDR,
};

struct ce_irq_list {
	int irq;
	irqreturn_t (*handler)(int, void *);
};

struct icnss_vreg_info {
	struct regulator *reg;
	const char *name;
	u32 min_v;
	u32 max_v;
	u32 load_ua;
	unsigned long settle_delay;
	bool required;
};

struct icnss_clk_info {
	struct clk *handle;
	const char *name;
	u32 freq;
	bool required;
};

struct icnss_stats {
	struct {
		uint32_t posted;
		uint32_t processed;
	} events[ICNSS_DRIVER_EVENT_MAX];

	struct {
		uint32_t request;
		uint32_t free;
		uint32_t enable;
		uint32_t disable;
	} ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];

	struct {
		uint32_t pdr_fw_crash;
		uint32_t pdr_host_error;
		uint32_t root_pd_crash;
		uint32_t root_pd_shutdown;
	} recovery;

	uint32_t pm_suspend;
	uint32_t pm_suspend_err;
	uint32_t pm_resume;
	uint32_t pm_resume_err;
	uint32_t pm_suspend_noirq;
	uint32_t pm_suspend_noirq_err;
	uint32_t pm_resume_noirq;
	uint32_t pm_resume_noirq_err;
	uint32_t pm_stay_awake;
	uint32_t pm_relax;

	uint32_t ind_register_req;
	uint32_t ind_register_resp;
	uint32_t ind_register_err;
	uint32_t msa_info_req;
	uint32_t msa_info_resp;
	uint32_t msa_info_err;
	uint32_t msa_ready_req;
	uint32_t msa_ready_resp;
	uint32_t msa_ready_err;
	uint32_t msa_ready_ind;
	uint32_t cap_req;
	uint32_t cap_resp;
	uint32_t cap_err;
	uint32_t pin_connect_result;
	uint32_t cfg_req;
	uint32_t cfg_resp;
	uint32_t cfg_req_err;
	uint32_t mode_req;
	uint32_t mode_resp;
	uint32_t mode_req_err;
	uint32_t ini_req;
	uint32_t ini_resp;
	uint32_t ini_req_err;
	uint32_t vbatt_req;
	uint32_t vbatt_resp;
	uint32_t vbatt_req_err;
	u32 rejuvenate_ind;
	uint32_t rejuvenate_ack_req;
	uint32_t rejuvenate_ack_resp;
	uint32_t rejuvenate_ack_err;
};

#define MAX_NO_OF_MAC_ADDR 4

#define WLFW_MAX_TIMESTAMP_LEN 32
#define WLFW_MAX_BUILD_ID_LEN 128
#define WLFW_MAX_NUM_MEMORY_REGIONS 2
#define WLFW_FUNCTION_NAME_LEN 129
#define WLFW_MAX_DATA_SIZE 6144
#define WLFW_MAX_STR_LEN 16
#define WLFW_MAX_NUM_CE 12
#define WLFW_MAX_NUM_SVC 24
#define WLFW_MAX_NUM_SHADOW_REG 24

struct icnss_wlan_mac_addr {
	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
	uint32_t no_of_mac_addr_set;
};

struct service_notifier_context {
	void *handle;
	uint32_t instance_id;
	char name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1];
};

struct wlfw_rf_chip_info {
	uint32_t chip_id;
	uint32_t chip_family;
};

struct wlfw_rf_board_info {
	uint32_t board_id;
};

struct wlfw_fw_version_info {
	uint32_t fw_version;
	char fw_build_timestamp[WLFW_MAX_TIMESTAMP_LEN + 1];
};

enum icnss_msa_perm {
	ICNSS_MSA_PERM_HLOS_ALL = 0,
	ICNSS_MSA_PERM_WLAN_HW_RW = 1,
	ICNSS_MSA_PERM_DUMP_COLLECT = 2,
	ICNSS_MSA_PERM_MAX,
};

#define ICNSS_MAX_VMIDS     4

struct icnss_mem_region_info {
	uint64_t reg_addr;
	uint32_t size;
	uint8_t secure_flag;
	enum icnss_msa_perm perm;
};

struct icnss_msa_perm_list_t {
	int vmids[ICNSS_MAX_VMIDS];
	int perms[ICNSS_MAX_VMIDS];
	int nelems;
};

struct icnss_priv {
	uint32_t magic;
	struct platform_device *pdev;
	struct icnss_driver_ops *ops;
	struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
	struct icnss_vreg_info *vreg_info;
	struct icnss_clk_info *clk_info;
	u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
	phys_addr_t mem_base_pa;
	void __iomem *mem_base_va;
	struct dma_iommu_mapping *smmu_mapping;
	dma_addr_t smmu_iova_start;
	size_t smmu_iova_len;
	dma_addr_t smmu_iova_ipa_start;
	size_t smmu_iova_ipa_len;
	struct qmi_handle *wlfw_clnt;
	struct list_head event_list;
	spinlock_t event_lock;
	struct work_struct event_work;
	struct work_struct fw_recv_msg_work;
	struct workqueue_struct *event_wq;
	phys_addr_t msa_pa;
	uint32_t msa_mem_size;
	void *msa_va;
	unsigned long state;
	struct wlfw_rf_chip_info chip_info;
	uint32_t board_id;
	uint32_t soc_id;
	struct wlfw_fw_version_info fw_version_info;
	char fw_build_id[WLFW_MAX_BUILD_ID_LEN + 1];
	u32 pwr_pin_result;
	u32 phy_io_pin_result;
	u32 rf_pin_result;
	uint32_t nr_mem_region;
	struct icnss_mem_region_info
		mem_region[WLFW_MAX_NUM_MEMORY_REGIONS];
	struct dentry *root_dentry;
	spinlock_t on_off_lock;
	struct icnss_stats stats;
	struct work_struct service_notifier_work;
	struct service_notifier_context *service_notifier;
	struct notifier_block service_notifier_nb;
	int total_domains;
	struct notifier_block get_service_nb;
	void *modem_notify_handler;
	struct notifier_block modem_ssr_nb;
	uint32_t diag_reg_read_addr;
	uint32_t diag_reg_read_mem_type;
	uint32_t diag_reg_read_len;
	uint8_t *diag_reg_read_buf;
	atomic_t pm_count;
	struct ramdump_device *msa0_dump_dev;
	bool is_wlan_mac_set;
	struct icnss_wlan_mac_addr wlan_mac_addr;
	bool bypass_s1_smmu;
	u8 cause_for_rejuvenation;
	u8 requesting_sub_system;
	u16 line_number;
	struct mutex dev_lock;
	char function_name[WLFW_FUNCTION_NAME_LEN + 1];
};

int icnss_call_driver_uevent(struct icnss_priv *priv,
				    enum icnss_uevent uevent, void *data);
int icnss_driver_event_post(enum icnss_driver_event_type type,
				   u32 flags, void *data);
#endif
+1102 −0

File added.

Preview size limit exceeded, changes collapsed.

+121 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __ICNSS_QMI_H__
#define __ICNSS_QMI_H__

#ifndef ICNSS_QMI

static inline int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv)
{
	return 0;
}
static inline int icnss_connect_to_fw_server(struct icnss_priv *priv)
{
	return 0;
}
static inline int wlfw_msa_mem_info_send_sync_msg(struct icnss_priv *priv)
{
	return 0;
}
static inline int wlfw_msa_ready_send_sync_msg(struct icnss_priv *priv)
{
	return 0;
}
static inline int wlfw_cap_send_sync_msg(struct icnss_priv *priv)
{
	return 0;
}
static inline int wlfw_dynamic_feature_mask_send_sync_msg(
		struct icnss_priv *priv, uint64_t dynamic_feature_mask)
{
	return 0;
}
static inline int icnss_clear_server(struct icnss_priv *priv)
{
	return 0;
}
static inline int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv)
{
	return 0;
}
static inline void icnss_ignore_fw_timeout(bool ignore) {}

static inline int wlfw_ini_send_sync_msg(struct icnss_priv *priv,
		uint8_t fw_log_mode)
{
	return 0;
}
static inline int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv,
					   uint32_t offset, uint32_t mem_type,
					   uint32_t data_len, uint8_t *data)
{
	return 0;
}
static inline int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
					    uint32_t offset, uint32_t mem_type,
					    uint32_t data_len, uint8_t *data)
{
	return 0;
}
static inline int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv,
		enum icnss_driver_mode mode)
{
	return 0;
}
static inline int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv,
		struct icnss_wlan_enable_cfg *config,
		enum icnss_driver_mode mode,
		const char *host_version)
{
	return 0;
}
static inline int icnss_send_wlan_disable_to_fw(struct icnss_priv *priv)
{
	return 0;
}
static inline int icnss_register_fw_service(struct icnss_priv *priv)
{
	return 0;
}
static inline void icnss_unregister_fw_service(struct icnss_priv *priv) {}

#else
int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv);
int icnss_connect_to_fw_server(struct icnss_priv *priv);
int wlfw_msa_mem_info_send_sync_msg(struct icnss_priv *priv);
int wlfw_msa_ready_send_sync_msg(struct icnss_priv *priv);
int wlfw_cap_send_sync_msg(struct icnss_priv *priv);
int icnss_qmi_pin_connect_result_ind(struct icnss_priv *priv,
					void *msg, unsigned int msg_len);
int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv,
					   uint64_t dynamic_feature_mask);
int icnss_clear_server(struct icnss_priv *priv);
int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv);
void icnss_ignore_fw_timeout(bool ignore);
int wlfw_ini_send_sync_msg(struct icnss_priv *priv, uint8_t fw_log_mode);
int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv,
					   uint32_t offset, uint32_t mem_type,
					   uint32_t data_len, uint8_t *data);
int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
					    uint32_t offset, uint32_t mem_type,
					    uint32_t data_len, uint8_t *data);
int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv,
		struct icnss_wlan_enable_cfg *config,
		enum icnss_driver_mode mode,
		const char *host_version);
int icnss_send_wlan_disable_to_fw(struct icnss_priv *priv);
int icnss_register_fw_service(struct icnss_priv *priv);
void icnss_unregister_fw_service(struct icnss_priv *priv);
#endif

#endif /* __ICNSS_QMI_H__*/