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

Commit 0e8beccd authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: create ipa_client for ethernet"

parents 8de57403 7d0bf748
Loading
Loading
Loading
Loading
+194 −6
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ struct ipa_fmwk_contex {
	struct mutex lock;
	ipa_uc_ready_cb uc_ready_cb;
	void *uc_ready_priv;
	ipa_eth_ready_cb eth_ready_cb;
	void *eth_userdata;
	enum ipa_uc_offload_proto proto;

	/* ipa core driver APIs */
@@ -356,6 +358,26 @@ struct ipa_fmwk_contex {
	int (*ipa_wigig_set_perf_profile)(u32 max_supported_bw_mbps);

	int (*ipa_wigig_save_regs)(void);

	/* ipa eth APIs */
	int (*ipa_eth_register_ready_cb)(struct ipa_eth_ready *ready_info);

	int (*ipa_eth_unregister_ready_cb)(struct ipa_eth_ready *ready_info);

	int (*ipa_eth_client_conn_pipes)(struct ipa_eth_client *client);

	int (*ipa_eth_client_disconn_pipes)(struct ipa_eth_client *client);

	int (*ipa_eth_client_reg_intf)(struct ipa_eth_intf_info *intf);

	int (*ipa_eth_client_unreg_intf)(struct ipa_eth_intf_info *intf);

	int (*ipa_eth_client_set_perf_profile)(struct ipa_eth_client *client,
		struct ipa_eth_perf_profile *profile);

	int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg);

	int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg);
};

static struct ipa_fmwk_contex *ipa_fmwk_ctx;
@@ -376,23 +398,34 @@ static inline void ipa_trigger_ipa_ready_cbs(void)
	}
}

static inline void ipa_register_uc_ready_cb(void)
static inline void ipa_late_register_ready_cb(void)
{
	int ret;
	if (ipa_fmwk_ctx->uc_ready_cb) {
		struct ipa_uc_ready_params param;

	if (ipa_fmwk_ctx->uc_ready_cb) {
		param.notify = ipa_fmwk_ctx->uc_ready_cb;
		param.priv = ipa_fmwk_ctx->uc_ready_priv;
		param.proto = ipa_fmwk_ctx->proto;

		ret = ipa_fmwk_ctx->ipa_uc_offload_reg_rdyCB(&param);
		ipa_fmwk_ctx->ipa_uc_offload_reg_rdyCB(&param);
		/* if uc is already ready, client expects cb to be called */
		if (param.is_uC_ready) {
			ipa_fmwk_ctx->uc_ready_cb(
				ipa_fmwk_ctx->uc_ready_priv);
		}
	}

	if (ipa_fmwk_ctx->eth_ready_cb) {
		struct ipa_eth_ready ready_info;

		/* just late call to ipa_eth_register_ready_cb */
		ready_info.notify = ipa_fmwk_ctx->eth_ready_cb;
		ready_info.userdata = ipa_fmwk_ctx->eth_userdata;
		ipa_fmwk_ctx->ipa_eth_register_ready_cb(&ready_info);
		/* nobody cares anymore about ready_info->is_eth_ready since
		 * if we got here it means that we already returned false there
		 */
	}
}

/* registration API for IPA core module */
@@ -452,7 +485,7 @@ int ipa_fmwk_register_ipa(const struct ipa_core_data *in)
	ipa_fmwk_ctx->ipa_ready = true;
	ipa_trigger_ipa_ready_cbs();

	ipa_register_uc_ready_cb();
	ipa_late_register_ready_cb();
	mutex_unlock(&ipa_fmwk_ctx->lock);

	pr_info("IPA driver is now in ready state\n");
@@ -1781,6 +1814,161 @@ int ipa_wigig_save_regs(void)
}
EXPORT_SYMBOL(ipa_wigig_save_regs);

/* registration API for IPA eth module */
int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in)
{
	if (!ipa_fmwk_ctx) {
		pr_err("ipa framework hasn't been initialized yet\n");
		return -EPERM;
	}

	if (ipa_fmwk_ctx->ipa_eth_register_ready_cb
		|| ipa_fmwk_ctx->ipa_eth_unregister_ready_cb
		|| ipa_fmwk_ctx->ipa_eth_client_conn_pipes
		|| ipa_fmwk_ctx->ipa_eth_client_disconn_pipes
		|| ipa_fmwk_ctx->ipa_eth_client_reg_intf
		|| ipa_fmwk_ctx->ipa_eth_client_unreg_intf
		|| ipa_fmwk_ctx->ipa_eth_client_set_perf_profile
		|| ipa_fmwk_ctx->ipa_eth_client_conn_evt
		|| ipa_fmwk_ctx->ipa_eth_client_disconn_evt) {
		pr_err("ipa_eth APIs were already initialized\n");
		return -EPERM;
	}

	ipa_fmwk_ctx->ipa_eth_register_ready_cb = in->ipa_eth_register_ready_cb;
	ipa_fmwk_ctx->ipa_eth_unregister_ready_cb =
		in->ipa_eth_unregister_ready_cb;
	ipa_fmwk_ctx->ipa_eth_client_conn_pipes = in->ipa_eth_client_conn_pipes;
	ipa_fmwk_ctx->ipa_eth_client_disconn_pipes =
		in->ipa_eth_client_disconn_pipes;
	ipa_fmwk_ctx->ipa_eth_client_reg_intf = in->ipa_eth_client_reg_intf;
	ipa_fmwk_ctx->ipa_eth_client_unreg_intf = in->ipa_eth_client_unreg_intf;
	ipa_fmwk_ctx->ipa_eth_client_set_perf_profile =
		in->ipa_eth_client_set_perf_profile;
	ipa_fmwk_ctx->ipa_eth_client_conn_evt = in->ipa_eth_client_conn_evt;
	ipa_fmwk_ctx->ipa_eth_client_disconn_evt =
		in->ipa_eth_client_disconn_evt;

	pr_info("ipa_eth registered successfully\n");

	return 0;
}
EXPORT_SYMBOL(ipa_fmwk_register_ipa_eth);

int ipa_eth_register_ready_cb(struct ipa_eth_ready *ready_info)
{
	int ret;

	if (!ipa_fmwk_ctx) {
		pr_err("ipa framework hasn't been initialized yet\n");
		return -EPERM;
	}

	mutex_lock(&ipa_fmwk_ctx->lock);
	if (ipa_fmwk_ctx->ipa_ready) {
		/* call real func, unlock and return */
		ret = ipa_fmwk_ctx->ipa_eth_register_ready_cb(ready_info);
		mutex_unlock(&ipa_fmwk_ctx->lock);
		return ret;
	}
	ipa_fmwk_ctx->eth_ready_cb = ready_info->notify;
	ipa_fmwk_ctx->eth_userdata = ready_info->userdata;
	ready_info->is_eth_ready = false;
	mutex_unlock(&ipa_fmwk_ctx->lock);

	return 0;
}
EXPORT_SYMBOL(ipa_eth_register_ready_cb);

int ipa_eth_unregister_ready_cb(struct ipa_eth_ready *ready_info)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_unregister_ready_cb,
		ready_info);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_unregister_ready_cb);

int ipa_eth_client_conn_pipes(struct ipa_eth_client *client)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_conn_pipes,
		client);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_conn_pipes);

int ipa_eth_client_disconn_pipes(struct ipa_eth_client *client)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_disconn_pipes,
		client);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_disconn_pipes);

int ipa_eth_client_reg_intf(struct ipa_eth_intf_info *intf)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_reg_intf,
		intf);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_reg_intf);

int ipa_eth_client_unreg_intf(struct ipa_eth_intf_info *intf)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_unreg_intf,
		intf);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_unreg_intf);

int ipa_eth_client_set_perf_profile(struct ipa_eth_client *client,
	struct ipa_eth_perf_profile *profile)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_set_perf_profile,
		client, profile);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_set_perf_profile);

int ipa_eth_client_conn_evt(struct ipa_ecm_msg *msg)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_conn_evt,
		msg);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_conn_evt);

int ipa_eth_client_disconn_evt(struct ipa_ecm_msg *msg)
{
	int ret;

	IPA_FMWK_DISPATCH_RETURN_DP(ipa_eth_client_disconn_evt,
		msg);

	return ret;
}
EXPORT_SYMBOL(ipa_eth_client_disconn_evt);

/* module functions */
static int __init ipa_fmwk_init(void)
{
+18 −0
Original line number Diff line number Diff line
@@ -889,6 +889,24 @@ struct IpaHwRingStats_t {
	u32 RingUtilCount;
} __packed;

/**
 * struct ipa_uc_dbg_rtk_ring_stats - uC dbg stats info for RTK
 * offloading protocol
 * @commStats: common stats
 * @trCount: transfer ring count
 * @erCount: event ring count
 * @totalAosCount: total AoS completion count
 * @busyTime: total busy time
 */
struct ipa_uc_dbg_rtk_ring_stats {
	struct IpaHwRingStats_t commStats;
	u32 trCount;
	u32 erCount;
	u32 totalAosCount;
	u64 busyTime;
} __packed;


/**
 * struct IpaHwStatsWDIRxInfoData_t - Structure holding the WDI Rx channel
 * structures
+255 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 */

#ifndef _IPA_ETH_H_
#define _IPA_ETH_H_

#include <linux/ipa.h>
#include <linux/msm_ipa.h>
#include <linux/msm_gsi.h>

/* New architecture prototypes */

typedef void (*ipa_eth_ready_cb)(void *user_data);
typedef u32 ipa_eth_hdl_t;

/**
 * struct ipa_eth_ready_cb - eth readiness parameters
 *
 * @notify: ipa_eth client ready callback notifier
 * @userdata: userdata for ipa_eth ready cb
 * @is_eth_ready: true if ipa_eth client is already ready
 */
struct ipa_eth_ready {
	ipa_eth_ready_cb notify;
	void *userdata;

	/* out params */
	bool is_eth_ready;
};

/**
 * enum ipa_eth_client_type - names for the various IPA
 * eth "clients".
 */
enum ipa_eth_client_type {
	IPA_ETH_CLIENT_AQC107,
	IPA_ETH_CLIENT_AQC113,
	IPA_ETH_CLIENT_RTK8111K,
	IPA_ETH_CLIENT_RTK8125B,
	IPA_ETH_CLIENT_NTN,
	IPA_ETH_CLIENT_EMAC,
	IPA_ETH_CLIENT_MAX,
};

/**
 * enum ipa_eth_pipe_traffic_type - traffic type for the various IPA
 * eth "pipes".
 */
enum ipa_eth_pipe_traffic_type {
	IPA_ETH_PIPE_BEST_EFFORT,
	IPA_ETH_PIPE_LOW_LATENCY,
	IPA_ETH_PIPE_TRAFFIC_TYPE_MAX,
};

/**
 * enum ipa_eth_pipe_direction - pipe direcitons for same
 * ethernet client.
 */
enum ipa_eth_pipe_direction {
	IPA_ETH_PIPE_DIR_TX,
	IPA_ETH_PIPE_DIR_RX,
	IPA_ETH_PIPE_DIR_MAX,
};

#define IPA_ETH_INST_ID_MAX (2)

/**
 * struct ipa_eth_aqc_setup_info - parameters for aqc ethernet
 * offloading
 *
 * @bar_addr: bar PA to access AQC register
 * @head_ptr_offs: head ptr offset
 * @aqc_ch: AQC ch number
 * @dest_tail_ptr_offs: tail ptr offset
 */
struct ipa_eth_aqc_setup_info {
	phys_addr_t bar_addr;
	phys_addr_t head_ptr_offs;
	u8 aqc_ch;
	phys_addr_t dest_tail_ptr_offs;
};


/**
 * struct ipa_eth_realtek_setup_info - parameters for realtek ethernet
 * offloading
 *
 * @bar_addr: bar PA to access RTK register
 * @bar_size: bar region size
 * @queue_number: Which RTK queue to check the status on
 * @dest_tail_ptr_offs: tail ptr offset
 */
struct ipa_eth_realtek_setup_info {
	phys_addr_t bar_addr;
	u32 bar_size;
	u8 queue_number;
	phys_addr_t dest_tail_ptr_offs;
};

/**
 * struct ipa_eth_buff_smmu_map -  IPA iova->pa SMMU mapping
 * @iova: virtual address of the data buffer
 * @pa: physical address of the data buffer
 */
struct ipa_eth_buff_smmu_map {
	dma_addr_t iova;
	phys_addr_t pa;
};

/**
 * struct  ipa_eth_pipe_setup_info - info needed for IPA setups
 * @is_transfer_ring_valid: if transfer ring is needed
 * @transfer_ring_base:  the base of the transfer ring
 * @transfer_ring_sgt: sgtable of transfer ring
 * @transfer_ring_size:  size of the transfer ring
 * @is_buffer_pool_valid: if buffer pool is needed
 * @buffer_pool_base_addr:  base of buffer pool address
 * @buffer_pool_base_sgt:  sgtable of buffer pool
 * @data_buff_list_size: number of buffers
 * @data_buff_list: array of data buffer list
 * @fix_buffer_size: buffer size
 * @notify:	callback for exception/embedded packets
 * @priv: priv for exception callback
 * @client_info: vendor specific pipe setup info
 * @db_pa: doorbell physical address
 * @db_val: doorbell value ethernet HW need to ring
 */
struct ipa_eth_pipe_setup_info {
	/* transfer ring info */
	bool is_transfer_ring_valid;
	dma_addr_t  transfer_ring_base;
	struct sg_table *transfer_ring_sgt;
	u32 transfer_ring_size;

	/* buffer pool info */
	bool is_buffer_pool_valid;
	dma_addr_t buffer_pool_base_addr;
	struct sg_table *buffer_pool_base_sgt;

	/* buffer info */
	u32 data_buff_list_size;
	struct ipa_eth_buff_smmu_map *data_buff_list;
	u32 fix_buffer_size;

	/* client notify cb */
	ipa_notify_cb notify;
	void *priv;

	/* vendor specific info */
	union {
		struct ipa_eth_aqc_setup_info aqc;
		struct ipa_eth_realtek_setup_info rtk;
	} client_info;

	/* output params */
	phys_addr_t db_pa;
	u32 db_val;
};

/**
 * struct  ipa_eth_client_pipe_info - ETH pipe/gsi related configuration
 * @link: link of ep for different client function on same ethernet HW
 * @dir: TX or RX direction
 * @info: tx/rx pipe setup info
 * @client_info: client the pipe belongs to
 * @pipe_hdl: output params, pipe handle
 */
struct ipa_eth_client_pipe_info {
	struct list_head link;
	enum ipa_eth_pipe_direction dir;
	struct ipa_eth_pipe_setup_info info;
	struct ipa_eth_client *client_info;

	/* output params */
	ipa_eth_hdl_t pipe_hdl;
};

/**
 * struct  ipa_eth_client - client info per traffic type
 * provided by offload client
 * @client_type: ethernet client type
 * @inst_id: instance id for dual NIC support
 * @traffic_type: traffic type
 * @pipe_list: list of pipes with same traffic type
 * @priv: private data for client
 */
struct ipa_eth_client {
	/* vendor driver */
	enum ipa_eth_client_type client_type;
	u8 inst_id;

	/* traffic type */
	enum ipa_eth_pipe_traffic_type traffic_type;
	struct list_head pipe_list;

	/* client specific priv data*/
	void *priv;
};

/**
 * struct  ipa_eth_perf_profile - To set BandWidth profile
 *
 * @max_supported_bw_mbps: maximum bandwidth needed (in Mbps)
 */
struct ipa_eth_perf_profile {
	u32 max_supported_bw_mbps;
};

/**
 * struct ipa_eth_hdr_info - Header to install on IPA HW
 *
 * @hdr: header to install on IPA HW
 * @hdr_len: length of header
 * @dst_mac_addr_offset: destination mac address offset
 * @hdr_type: layer two header type
 */
struct ipa_eth_hdr_info {
	u8 *hdr;
	u8 hdr_len;
	u8 dst_mac_addr_offset;
	enum ipa_hdr_l2_type hdr_type;
};

/**
 * struct ipa_eth_intf_info - parameters for ipa offload
 *	interface registration
 *
 * @netdev_name: network interface name
 * @hdr: hdr for ipv4/ipv6
 * @pipe_hdl_list_size: number of pipes prop needed for this interface
 * @pipe_hdl_list: array of pipes used for this interface
 */
struct ipa_eth_intf_info {
	const char *netdev_name;
	struct ipa_eth_hdr_info hdr[IPA_IP_MAX];

	/* tx/rx pipes for same netdev */
	int pipe_hdl_list_size;
	ipa_eth_hdl_t *pipe_hdl_list;
};

int ipa_eth_register_ready_cb(struct ipa_eth_ready *ready_info);
int ipa_eth_unregister_ready_cb(struct ipa_eth_ready *ready_info);
int ipa_eth_client_conn_pipes(struct ipa_eth_client *client);
int ipa_eth_client_disconn_pipes(struct ipa_eth_client *client);
int ipa_eth_client_reg_intf(struct ipa_eth_intf_info *intf);
int ipa_eth_client_unreg_intf(struct ipa_eth_intf_info *intf);
int ipa_eth_client_set_perf_profile(struct ipa_eth_client *client,
	struct ipa_eth_perf_profile *profile);
int ipa_eth_client_conn_evt(struct ipa_ecm_msg *msg);
int ipa_eth_client_disconn_evt(struct ipa_ecm_msg *msg);

#endif // _IPA_ETH_H_
+29 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/ipa_usb.h>
#include <linux/ipa_odu_bridge.h>
#include <linux/ipa_qmi_service_v01.h>
#include <linux/ipa_eth.h>

struct ipa_core_data {
	int (*ipa_tx_dp)(enum ipa_client_type dst, struct sk_buff *skb,
@@ -268,6 +269,27 @@ struct ipa_wigig_data {
	int (*ipa_wigig_save_regs)(void);
};

struct ipa_eth_data {
	int (*ipa_eth_register_ready_cb)(struct ipa_eth_ready *ready_info);

	int (*ipa_eth_unregister_ready_cb)(struct ipa_eth_ready *ready_info);

	int (*ipa_eth_client_conn_pipes)(struct ipa_eth_client *client);

	int (*ipa_eth_client_disconn_pipes)(struct ipa_eth_client *client);

	int (*ipa_eth_client_reg_intf)(struct ipa_eth_intf_info *intf);

	int (*ipa_eth_client_unreg_intf)(struct ipa_eth_intf_info *intf);

	int (*ipa_eth_client_set_perf_profile)(struct ipa_eth_client *client,
		struct ipa_eth_perf_profile *profile);

	int (*ipa_eth_client_conn_evt)(struct ipa_ecm_msg *msg);

	int (*ipa_eth_client_disconn_evt)(struct ipa_ecm_msg *msg);
};

#if IS_ENABLED(CONFIG_IPA3)

int ipa_fmwk_register_ipa(const struct ipa_core_data *in);
@@ -284,6 +306,8 @@ int ipa_fmwk_register_ipa_mhi(const struct ipa_mhi_data *in);

int ipa_fmwk_register_ipa_wigig(const struct ipa_wigig_data *in);

int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in);

#else /* IS_ENABLED(CONFIG_IPA3) */

int ipa_fmwk_register_ipa(const struct ipa_core_data *in)
@@ -321,6 +345,11 @@ int ipa_fmwk_register_ipa_wigig(const struct ipa_wigig_data *in)
	return -EPERM;
}

int ipa_fmwk_register_ipa_eth(const struct ipa_eth_data *in)
{
	return -EPERM;
}

#endif /* IS_ENABLED(CONFIG_IPA3) */

#endif /* _IPA_FMWK_H_ */
+4 −1
Original line number Diff line number Diff line
@@ -401,9 +401,12 @@ enum ipa_client_type {

	IPA_CLIENT_QDSS_PROD			= 106,
	IPA_CLIENT_MHI_QDSS_CONS		= 107,

	IPA_CLIENT_RTK_ETHERNET_PROD = 108,
	IPA_CLIENT_RTK_ETHERNET_CONS = 109,
};

#define IPA_CLIENT_MAX (IPA_CLIENT_MHI_QDSS_CONS + 1)
#define IPA_CLIENT_MAX (IPA_CLIENT_RTK_ETHERNET_CONS + 1)

#define IPA_CLIENT_WLAN2_PROD IPA_CLIENT_A5_WLAN_AMPDU_PROD
#define IPA_CLIENT_Q6_DL_NLO_DATA_PROD IPA_CLIENT_Q6_DL_NLO_DATA_PROD