msm: ipa: create ipa_client for ethernet

Create the ipa_client interface for ethernet offloading.

Change-Id: I8120b0cca9e42a75153fb1468dc1b8bcbd43484c
Signed-off-by: Bojun Pan <bojunp@codeaurora.org>
Signed-off-by: Amir Levy <alevy@codeaurora.org>
This commit is contained in:
Amir Levy 2020-11-08 10:42:54 +02:00
parent 8543fd31f2
commit 7d0bf74852
5 changed files with 500 additions and 7 deletions

View File

@ -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;
struct ipa_uc_ready_params param;
if (ipa_fmwk_ctx->uc_ready_cb) {
struct ipa_uc_ready_params param;
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)
{

View File

@ -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
include/linux/ipa_eth.h Normal file
View File

@ -0,0 +1,255 @@
/* 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_

View File

@ -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_ */

View File

@ -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