From 7d0bf748520f7d7809ec19560ed801eb9ba2f377 Mon Sep 17 00:00:00 2001 From: Amir Levy Date: Sun, 8 Nov 2020 10:42:54 +0200 Subject: [PATCH] msm: ipa: create ipa_client for ethernet Create the ipa_client interface for ethernet offloading. Change-Id: I8120b0cca9e42a75153fb1468dc1b8bcbd43484c Signed-off-by: Bojun Pan Signed-off-by: Amir Levy --- drivers/platform/msm/ipa_fmwk/ipa_fmwk.c | 200 +++++++++++++++++- include/linux/ipa.h | 18 ++ include/linux/ipa_eth.h | 255 +++++++++++++++++++++++ include/linux/ipa_fmwk.h | 29 +++ include/uapi/linux/msm_ipa.h | 5 +- 5 files changed, 500 insertions(+), 7 deletions(-) create mode 100644 include/linux/ipa_eth.h diff --git a/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c b/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c index 9459dff2a648..9ca56405f60a 100644 --- a/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c +++ b/drivers/platform/msm/ipa_fmwk/ipa_fmwk.c @@ -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(¶m); + ipa_fmwk_ctx->ipa_uc_offload_reg_rdyCB(¶m); /* 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) { diff --git a/include/linux/ipa.h b/include/linux/ipa.h index ec06d3d1dddd..f336aae42ddd 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -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 diff --git a/include/linux/ipa_eth.h b/include/linux/ipa_eth.h new file mode 100644 index 000000000000..ce0775accde1 --- /dev/null +++ b/include/linux/ipa_eth.h @@ -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 +#include +#include + +/* 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_ diff --git a/include/linux/ipa_fmwk.h b/include/linux/ipa_fmwk.h index 0a8de09c805a..e366d58081fc 100644 --- a/include/linux/ipa_fmwk.h +++ b/include/linux/ipa_fmwk.h @@ -15,6 +15,7 @@ #include #include #include +#include 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_ */ diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 3a1c31657c92..49418c173a65 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -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