msm: ipa: add AQC support in ipa_eth client

Add AQC support in ipa_eth client framework.

Change-Id: I1eb17ebf02813d59977c8c792923e70f348c9ea9
Signed-off-by: Bojun Pan <bojunp@codeaurora.org>
This commit is contained in:
Amir Levy
2020-11-11 12:42:12 +02:00
committed by Gerrit - the friendly Code Review server
parent ace2384057
commit 40fcad23c6
5 changed files with 536 additions and 145 deletions

View File

@@ -4726,6 +4726,30 @@ static union __packed gsi_channel_scratch __gsi_update_mhi_channel_scratch(
return scr;
}
int gsi_query_aqc_msi_addr(unsigned long chan_hdl, u32 *addr)
{
if (!gsi_ctx) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
if (chan_hdl >= gsi_ctx->max_ch) {
GSIERR("bad params chan_hdl=%lu\n", chan_hdl);
return -GSI_STATUS_INVALID_PARAMS;
}
if (gsi_ctx->chan[chan_hdl].state == GSI_CHAN_STATE_NOT_ALLOCATED) {
GSIERR("bad state %d\n",
gsi_ctx->chan[chan_hdl].state);
return -GSI_STATUS_UNSUPPORTED_OP;
}
*addr = gsihal_get_reg_nk_ofst(GSI_EE_n_GSI_CH_k_CNTXT_8,
gsi_ctx->per.ee, chan_hdl);
return 0;
}
EXPORT_SYMBOL(gsi_query_aqc_msi_addr);
static int msm_gsi_probe(struct platform_device *pdev)
{

View File

@@ -978,6 +978,26 @@ union __packed gsi_wdi3_channel_scratch2_reg {
uint32_t reserved2;
};
/**
* gsi_aqc_channel_scratch - AQC SW config area of
* channel scratch
*
* @buff_addr_lsb: AQC buffer address LSB (RX)
* @buff_addr_msb: AQC buffer address MSB (RX)
* @fix_buff_size: buff size in log2
* @head_ptr_lsb: head pointer address LSB (RX)
* @head_ptr_msb: head pointer address MSB (RX)
*/
struct __packed gsi_aqc_channel_scratch {
uint32_t buff_addr_lsb;
uint32_t buff_addr_msb : 8;
uint32_t reserved1 : 8;
unsigned fix_buff_size : 16;
uint32_t head_ptr_lsb;
uint32_t head_ptr_msb : 9;
uint32_t reserved2 : 23;
};
/**
* gsi_channel_scratch - channel scratch SW config area
*
@@ -993,6 +1013,7 @@ union __packed gsi_channel_scratch {
struct __packed gsi_wdi3_channel_scratch wdi3;
struct __packed gsi_mhip_channel_scratch mhip;
struct __packed gsi_wdi2_channel_scratch_new wdi2_new;
struct __packed gsi_aqc_channel_scratch aqc;
struct __packed gsi_rtk_channel_scratch rtk;
struct __packed {
uint32_t word1;
@@ -1139,6 +1160,17 @@ struct __packed gsi_rtk_evt_scratch {
uint32_t reserved2;
};
/**
* gsi_aqc_evt_scratch - AQC protocol SW config area of
* event scratch
* @reserved1: reserve bit.
* @reserved2: reserve bit.
*/
struct __packed gsi_aqc_evt_scratch {
uint32_t reserved1;
uint32_t reserved2;
};
/**
* gsi_evt_scratch - event scratch SW config area
*
@@ -1150,6 +1182,7 @@ union __packed gsi_evt_scratch {
struct __packed gsi_11ad_evt_scratch w11ad;
struct __packed gsi_wdi3_evt_scratch wdi3;
struct __packed gsi_mhip_evt_scratch mhip;
struct __packed gsi_aqc_evt_scratch aqc;
struct __packed gsi_rtk_evt_scratch rtk;
struct __packed {
uint32_t word1;
@@ -2190,6 +2223,16 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code);
int gsi_enable_flow_control_ee(unsigned int chan_idx, unsigned int ee,
int *code);
/**
* gsi_query_aqc_msi_addr - get aqc channel msi address
*
* @chan_id: channel id
* @addr: [out] aqc channel msi address
*
* @Return gsi_status
*/
int gsi_query_aqc_msi_addr(unsigned long chan_hdl, u32 *addr);
/*
* Here is a typical sequence of calls
*

View File

@@ -38,6 +38,8 @@
OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \
} while (0)
#define IPA_ETH_PIPES_NO 6
struct ipa_eth_ready_cb_wrapper {
struct list_head link;
struct ipa_eth_ready *info;
@@ -83,6 +85,36 @@ static struct notifier_block uc_rdy_cb = {
static DECLARE_WORK(ipa_eth_ready_notify, ipa_eth_ready_notify_work);
static bool pipe_connected[IPA_ETH_PIPES_NO];
static u8 client_to_pipe_index(enum ipa_client_type client_type)
{
switch (client_type) {
case IPA_CLIENT_ETHERNET_CONS:
return 0;
break;
case IPA_CLIENT_ETHERNET_PROD:
return 1;
break;
case IPA_CLIENT_RTK_ETHERNET_CONS:
return 2;
break;
case IPA_CLIENT_RTK_ETHERNET_PROD:
return 3;
break;
case IPA_CLIENT_AQC_ETHERNET_CONS:
return 4;
break;
case IPA_CLIENT_AQC_ETHERNET_PROD:
return 5;
break;
default:
IPAERR("invalid eth client_type\n");
ipa_assert();
}
return 0;
}
static int ipa_eth_init_internal(void)
{
char buff[IPA_RESOURCE_NAME_MAX];
@@ -389,6 +421,7 @@ static int ipa_eth_client_connect_pipe(
{
enum ipa_client_type client_type;
struct ipa_eth_client *client;
int ret;
if (!pipe) {
IPA_ETH_ERR("invalid pipe\n");
@@ -405,26 +438,20 @@ static int ipa_eth_client_connect_pipe(
IPA_ETH_ERR("invalid client type\n");
return -EFAULT;
}
pipe->pipe_hdl = ipa_eth_pipe_hdl_alloc((void *)pipe);
switch (client->client_type) {
case IPA_ETH_CLIENT_AQC107:
case IPA_ETH_CLIENT_AQC113:
ipa3_eth_aqc_connect(pipe, client_type);
break;
case IPA_ETH_CLIENT_RTK8111K:
case IPA_ETH_CLIENT_RTK8125B:
ipa3_eth_rtk_connect(pipe, client_type);
break;
case IPA_ETH_CLIENT_NTN:
case IPA_ETH_CLIENT_EMAC:
/* add support if needed */
break;
default:
IPA_ETH_ERR("invalid client type%d\n",
client->client_type);
ipa_eth_pipe_hdl_remove(pipe->pipe_hdl);
if (pipe_connected[client_to_pipe_index(client_type)]) {
IPA_ETH_ERR("client already connected\n");
return -EFAULT;
}
return 0;
pipe->pipe_hdl = ipa_eth_pipe_hdl_alloc((void *)pipe);
ret = ipa3_eth_connect(pipe, client_type);
if (!ret) {
pipe_connected[client_to_pipe_index(client_type)] = true;
}
return ret;
}
static int ipa_eth_client_disconnect_pipe(
@@ -432,6 +459,7 @@ static int ipa_eth_client_disconnect_pipe(
{
enum ipa_client_type client_type;
struct ipa_eth_client *client;
int result;
if (!pipe) {
IPA_ETH_ERR("invalid pipe\n");
@@ -449,24 +477,18 @@ static int ipa_eth_client_disconnect_pipe(
IPA_ETH_ERR("invalid client type\n");
return -EFAULT;
}
switch (client->client_type) {
case IPA_ETH_CLIENT_AQC107:
case IPA_ETH_CLIENT_AQC113:
ipa3_eth_aqc_disconnect(pipe, client_type);
break;
case IPA_ETH_CLIENT_RTK8111K:
case IPA_ETH_CLIENT_RTK8125B:
ipa3_eth_rtk_disconnect(pipe, client_type);
break;
case IPA_ETH_CLIENT_NTN:
case IPA_ETH_CLIENT_EMAC:
ipa3_eth_emac_disconnect(pipe, client_type);
break;
default:
IPA_ETH_ERR("invalid client type%d\n",
client->client_type);
if (!pipe_connected[client_to_pipe_index(client_type)]) {
IPA_ETH_ERR("client not connected\n");
return -EFAULT;
}
result = ipa3_eth_disconnect(pipe, client_type);
if (result)
return result;
pipe_connected[client_to_pipe_index(client_type)] = false;
ipa_eth_pipe_hdl_remove(pipe->pipe_hdl);
return 0;
}

View File

@@ -10,6 +10,10 @@
#define IPA_ETH_RTK_MODT (32)
#define IPA_ETH_RTK_MODC (128)
#define IPA_ETH_AQC_MODT (32)
#define IPA_ETH_AQC_MODC (128)
#define IPA_ETH_AGGR_PKT_LIMIT 1
#define IPA_ETH_AGGR_BYTE_LIMIT 2 /*2 Kbytes Agger hard byte limit*/
@@ -53,10 +57,90 @@ static void ipa3_eth_save_client_mapping(
}
}
static void ipa3_eth_release_client_mapping(
struct ipa_eth_client_pipe_info *pipe,
int id)
{
struct ipa_eth_client *client_info;
enum ipa_eth_client_type client_type;
u8 inst_id, pipe_hdl;
struct ipa3_eth_info *eth_info;
client_info = pipe->client_info;
client_type = client_info->client_type;
inst_id = client_info->inst_id;
pipe_hdl = pipe->pipe_hdl;
eth_info = &ipa3_ctx->eth_info[client_type][inst_id];
if (eth_info->map[id].valid) {
eth_info->num_ch--;
eth_info->map[id].type = 0;
eth_info->map[id].pipe_id = 0;
eth_info->map[id].ch_id = 0;
eth_info->map[id].valid = false;
eth_info->map[id].pipe_hdl = 0;
}
}
static int ipa3_eth_uc_init_peripheral(bool init, u64 per_base)
{
struct ipa_mem_buffer cmd;
enum ipa_cpu_2_hw_offload_commands command;
int result;
if (init) {
struct IpaHwAQCInitCmdData_t *cmd_data;
cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
if (cmd.base == NULL) {
IPAERR("fail to get DMA memory.\n");
return -ENOMEM;
}
cmd_data =
(struct IpaHwAQCInitCmdData_t *)cmd.base;
cmd_data->periph_baddr_lsb = lower_32_bits(per_base);
cmd_data->periph_baddr_msb = upper_32_bits(per_base);
command = IPA_CPU_2_HW_CMD_PERIPHERAL_INIT;
} else {
struct IpaHwAQCDeinitCmdData_t *cmd_data;
cmd.size = sizeof(*cmd_data);
cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
&cmd.phys_base, GFP_KERNEL);
if (cmd.base == NULL) {
IPAERR("fail to get DMA memory.\n");
return -ENOMEM;
}
cmd_data =
(struct IpaHwAQCDeinitCmdData_t *)cmd.base;
cmd_data->reserved = 0;
command = IPA_CPU_2_HW_CMD_PERIPHERAL_DEINIT;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
result = ipa3_uc_send_cmd((u32)(cmd.phys_base),
command,
IPA_HW_2_CPU_OFFLOAD_CMD_STATUS_SUCCESS,
false, 10 * HZ);
if (result) {
IPAERR("fail to %s uc\n",
init ? "init" : "deinit");
}
dma_free_coherent(ipa3_ctx->uc_pdev,
cmd.size, cmd.base, cmd.phys_base);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
IPADBG("exit\n");
return result;
}
static int ipa3_eth_config_uc(bool init,
u8 protocol,
u8 dir,
u8 gsi_ch)
u8 gsi_ch,
u8 peripheral_ch)
{
struct ipa_mem_buffer cmd;
enum ipa_cpu_2_hw_offload_commands command;
@@ -78,7 +162,12 @@ static int ipa3_eth_config_uc(bool init,
cmd_data->protocol = protocol;
switch (protocol) {
case IPA_HW_PROTOCOL_AQC:
/* TODO: add support for AQC */
cmd_data->SetupCh_params.AqcSetupCh_params.dir =
dir;
cmd_data->SetupCh_params.AqcSetupCh_params.gsi_ch =
gsi_ch;
cmd_data->SetupCh_params.AqcSetupCh_params.aqc_ch =
peripheral_ch;
break;
case IPA_HW_PROTOCOL_RTK:
cmd_data->SetupCh_params.RtkSetupCh_params.dir =
@@ -108,7 +197,8 @@ static int ipa3_eth_config_uc(bool init,
cmd_data->protocol = protocol;
switch (protocol) {
case IPA_HW_PROTOCOL_AQC:
/* TODO: add support for AQC */
cmd_data->CommonCh_params.AqcCommonCh_params.gsi_ch =
gsi_ch;
break;
case IPA_HW_PROTOCOL_RTK:
cmd_data->CommonCh_params.RtkCommonCh_params.gsi_ch =
@@ -323,7 +413,7 @@ fail_get_gsi_ep_info:
return result;
}
static int ipa3_smmu_map_rtk_pipes(struct ipa_eth_client_pipe_info *pipe,
static int ipa3_smmu_map_eth_pipes(struct ipa_eth_client_pipe_info *pipe,
bool map)
{
struct iommu_domain *smmu_domain;
@@ -395,7 +485,154 @@ fail_map_buffer_smmu_enabled:
return result;
}
int ipa3_eth_rtk_connect(
static int ipa_eth_setup_aqc_gsi_channel(
struct ipa_eth_client_pipe_info *pipe,
struct ipa3_ep_context *ep)
{
struct gsi_evt_ring_props gsi_evt_ring_props;
struct gsi_chan_props gsi_channel_props;
union __packed gsi_channel_scratch ch_scratch;
union __packed gsi_evt_scratch evt_scratch;
const struct ipa_gsi_ep_config *gsi_ep_info;
int result, len;
u64 bar_addr;
u64 head_ptr;
if (unlikely(!pipe->info.is_transfer_ring_valid)) {
IPAERR("RTK transfer ring invalid\n");
ipa_assert();
return -EFAULT;
}
/* setup event ring */
bar_addr =
IPA_ETH_PCIE_SET(pipe->info.client_info.aqc.bar_addr);
memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props));
gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_AQC_EV;
gsi_evt_ring_props.intr = GSI_INTR_MSI;
gsi_evt_ring_props.re_size = GSI_EVT_RING_RE_SIZE_16B;
gsi_evt_ring_props.int_modt = IPA_ETH_AQC_MODT;
gsi_evt_ring_props.int_modc = IPA_ETH_AQC_MODC;
gsi_evt_ring_props.exclusive = true;
gsi_evt_ring_props.err_cb = ipa_eth_gsi_evt_ring_err_cb;
gsi_evt_ring_props.user_data = NULL;
gsi_evt_ring_props.msi_addr =
bar_addr +
pipe->info.client_info.aqc.dest_tail_ptr_offs;
len = pipe->info.transfer_ring_size;
gsi_evt_ring_props.ring_len = len;
gsi_evt_ring_props.ring_base_addr =
(u64)pipe->info.transfer_ring_base;
result = gsi_alloc_evt_ring(&gsi_evt_ring_props,
ipa3_ctx->gsi_dev_hdl,
&ep->gsi_evt_ring_hdl);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("fail to alloc RX event ring\n");
result = -EFAULT;
}
ep->gsi_mem_info.evt_ring_len =
gsi_evt_ring_props.ring_len;
ep->gsi_mem_info.evt_ring_base_addr =
gsi_evt_ring_props.ring_base_addr;
/* setup channel ring */
memset(&gsi_channel_props, 0, sizeof(gsi_channel_props));
gsi_channel_props.prot = GSI_CHAN_PROT_AQC;
if (pipe->dir == IPA_ETH_PIPE_DIR_TX)
gsi_channel_props.dir = GSI_CHAN_DIR_FROM_GSI;
else
gsi_channel_props.dir = GSI_CHAN_DIR_TO_GSI;
gsi_ep_info = ipa3_get_gsi_ep_info(ep->client);
if (!gsi_ep_info) {
IPAERR("Failed getting GSI EP info for client=%d\n",
ep->client);
result = -EINVAL;
} else
gsi_channel_props.ch_id = gsi_ep_info->ipa_gsi_chan_num;
gsi_channel_props.evt_ring_hdl = ep->gsi_evt_ring_hdl;
gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_16B;
gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE;
gsi_channel_props.db_in_bytes = 0;
gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG;
gsi_channel_props.prefetch_mode =
gsi_ep_info->prefetch_mode;
gsi_channel_props.empty_lvl_threshold =
gsi_ep_info->prefetch_threshold;
gsi_channel_props.low_weight = 1;
gsi_channel_props.err_cb = ipa_eth_gsi_chan_err_cb;
gsi_channel_props.ring_len = len;
gsi_channel_props.ring_base_addr =
(u64)pipe->info.transfer_ring_base;
result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl,
&ep->gsi_chan_hdl);
if (result != GSI_STATUS_SUCCESS)
goto fail_get_gsi_ep_info;
ep->gsi_mem_info.chan_ring_len = gsi_channel_props.ring_len;
ep->gsi_mem_info.chan_ring_base_addr =
gsi_channel_props.ring_base_addr;
/* write event scratch */
memset(&evt_scratch, 0, sizeof(evt_scratch));
/* nothing is needed for AQC event scratch */
/* write ch scratch */
memset(&ch_scratch, 0, sizeof(ch_scratch));
ch_scratch.aqc.fix_buff_size =
ilog2(pipe->info.fix_buffer_size);
head_ptr = pipe->info.client_info.aqc.head_ptr_offs;
if (pipe->dir == IPA_ETH_PIPE_DIR_RX) {
ch_scratch.aqc.buff_addr_lsb =
(u32)pipe->info.data_buff_list[0].iova;
ch_scratch.aqc.buff_addr_msb =
(u32)((u64)(pipe->info.data_buff_list[0].iova) >> 32);
ch_scratch.aqc.head_ptr_lsb = (u32)(bar_addr + head_ptr);
ch_scratch.aqc.head_ptr_msb = (u32)((bar_addr +
head_ptr) >> 32);
}
result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("failed to write evt ring scratch\n");
goto fail_write_scratch;
}
return 0;
fail_write_scratch:
gsi_dealloc_channel(ep->gsi_chan_hdl);
ep->gsi_chan_hdl = ~0;
fail_get_gsi_ep_info:
gsi_dealloc_evt_ring(ep->gsi_evt_ring_hdl);
ep->gsi_evt_ring_hdl = ~0;
return result;
}
static int ipa3_eth_get_prot(struct ipa_eth_client_pipe_info *pipe,
enum ipa4_hw_protocol *prot)
{
int ret = 0;
switch (pipe->client_info->client_type) {
case IPA_ETH_CLIENT_AQC107:
case IPA_ETH_CLIENT_AQC113:
*prot = IPA_HW_PROTOCOL_AQC;
break;
case IPA_ETH_CLIENT_RTK8111K:
case IPA_ETH_CLIENT_RTK8125B:
*prot = IPA_HW_PROTOCOL_RTK;
break;
case IPA_ETH_CLIENT_NTN:
case IPA_ETH_CLIENT_EMAC:
*prot = IPA_HW_PROTOCOL_ETH;
break;
default:
IPAERR("invalid client type%d\n",
pipe->client_info->client_type);
*prot = IPA_HW_PROTOCOL_MAX;
ret = -EFAULT;
}
return ret;
}
int ipa3_eth_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
@@ -407,6 +644,9 @@ int ipa3_eth_rtk_connect(
void __iomem *db_addr;
u32 evt_ring_db_addr_low, evt_ring_db_addr_high, db_val = 0;
int id;
int ch;
u64 bar_addr;
enum ipa4_hw_protocol prot;
ep_idx = ipa_get_ep_mapping(client_type);
if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES) {
@@ -419,11 +659,24 @@ int ipa3_eth_rtk_connect(
IPAERR("Could not determine IPA VLAN mode\n");
return result;
}
result = ipa3_smmu_map_rtk_pipes(pipe, true);
result = ipa3_eth_get_prot(pipe, &prot);
if (result) {
IPAERR("Could not determine protocol\n");
return result;
}
if (prot == IPA_HW_PROTOCOL_ETH) {
IPAERR("EMAC\\NTN still not supported using this framework\n");
return -EFAULT;
}
result = ipa3_smmu_map_eth_pipes(pipe, true);
if (result) {
IPAERR("failed to map SMMU %d\n", result);
return result;
}
ep = &ipa3_ctx->ep[ep_idx];
memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
@@ -435,8 +688,9 @@ int ipa3_eth_rtk_connect(
ep_idx);
goto disable_data_path_fail;
}
ep->cfg.nat.nat_en = IPA_CLIENT_IS_PROD(client_type) ?
IPA_SRC_NAT : IPA_BYPASS_NAT;
IPA_SRC_NAT : IPA_BYPASS_NAT;
ep->cfg.hdr.hdr_len = vlan_mode ? VLAN_ETH_HLEN : ETH_HLEN;
ep->cfg.mode.mode = IPA_BASIC;
if (IPA_CLIENT_IS_CONS(client_type)) {
@@ -457,11 +711,21 @@ int ipa3_eth_rtk_connect(
ipa3_install_dflt_flt_rules(ep_idx);
IPADBG("client %d (ep: %d) connected\n", client_type,
ep_idx);
if (ipa_eth_setup_rtk_gsi_channel(pipe, ep)) {
IPAERR("fail to setup eth gsi rx channel\n");
result = -EFAULT;
goto setup_rtk_gsi_ch_fail;
if (prot == IPA_HW_PROTOCOL_RTK) {
if (ipa_eth_setup_rtk_gsi_channel(pipe, ep)) {
IPAERR("fail to setup eth gsi rx channel\n");
result = -EFAULT;
goto setup_gsi_ch_fail;
}
} else if (prot == IPA_HW_PROTOCOL_AQC) {
if (ipa_eth_setup_aqc_gsi_channel(pipe, ep)) {
IPAERR("fail to setup eth gsi rx channel\n");
result = -EFAULT;
goto setup_gsi_ch_fail;
}
}
if (gsi_query_channel_db_addr(ep->gsi_chan_hdl,
&gsi_db_addr_low, &gsi_db_addr_high)) {
IPAERR("failed to query gsi rx db addr\n");
@@ -488,35 +752,49 @@ int ipa3_eth_rtk_connect(
/* only 32 bit lsb is used */
db_addr = ioremap((phys_addr_t)(evt_ring_db_addr_low), 4);
/*
* IPA/GSI driver should ring the event DB once after
* initialization of the event, with a value that is
* outside of the ring range. Eg: ring base = 0x1000,
* ring size = 0x100 => AP can write value > 0x1100
* into the doorbell address. Eg: 0x 1110.
* Use event ring base addr + event ring size + 1 element size.
*/
* IPA/GSI driver should ring the event DB once after
* initialization of the event, with a value that is
* outside of the ring range. Eg: ring base = 0x1000,
* ring size = 0x100 => AP can write value > 0x1100
* into the doorbell address. Eg: 0x 1110.
* Use event ring base addr + event ring size + 1 element size.
*/
db_val = (u32)ep->gsi_mem_info.evt_ring_base_addr;
db_val += (u32)ep->gsi_mem_info.evt_ring_len;
db_val += GSI_EVT_RING_RE_SIZE_16B;
iowrite32(db_val, db_addr);
iounmap(db_addr);
if (IPA_CLIENT_IS_PROD(client_type)) {
/* RX mailbox */
pipe->info.db_pa = ipa3_ctx->ipa_wrapper_base +
ipahal_get_reg_base() +
ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
IPA_ETH_MBOX_M,
IPA_ETH_RX_MBOX_N);
pipe->info.db_val = IPA_ETH_RX_MBOX_VAL;
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v5_0) {
if (IPA_CLIENT_IS_PROD(client_type)) {
if (gsi_query_aqc_msi_addr(ep->gsi_chan_hdl,
&pipe->info.db_pa)) {
result = -EFAULT;
goto query_msi_fail;
}
} else {
pipe->info.db_pa = 0;
}
} else {
/* TX mailbox */
pipe->info.db_pa = ipa3_ctx->ipa_wrapper_base +
ipahal_get_reg_base() +
ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
IPA_ETH_MBOX_M,
IPA_ETH_TX_MBOX_N);
pipe->info.db_val = IPA_ETH_TX_MBOX_VAL;
if (IPA_CLIENT_IS_PROD(client_type)) {
/* RX mailbox */
pipe->info.db_pa = ipa3_ctx->ipa_wrapper_base +
ipahal_get_reg_base() +
ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
IPA_ETH_MBOX_M,
IPA_ETH_RX_MBOX_N);
pipe->info.db_val = IPA_ETH_RX_MBOX_VAL;
} else {
/* TX mailbox */
pipe->info.db_pa = ipa3_ctx->ipa_wrapper_base +
ipahal_get_reg_base() +
ipahal_get_reg_mn_ofst(IPA_UC_MAILBOX_m_n,
IPA_ETH_MBOX_M,
IPA_ETH_TX_MBOX_N);
pipe->info.db_val = IPA_ETH_TX_MBOX_VAL;
}
}
/* enable data path */
result = ipa3_enable_data_path(ep_idx);
if (result) {
@@ -533,69 +811,84 @@ int ipa3_eth_rtk_connect(
}
id = (pipe->dir == IPA_ETH_PIPE_DIR_TX) ? 1 : 0;
/* start uC gsi dbg stats monitor */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) {
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].ch_id
ipa3_ctx->gsi_info[prot].ch_id_info[id].ch_id
= ep->gsi_chan_hdl;
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].dir
ipa3_ctx->gsi_info[prot].ch_id_info[id].dir
= pipe->dir;
ipa3_uc_debug_stats_alloc(
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK]);
ipa3_ctx->gsi_info[prot]);
}
ch = 0;
if ((ipa3_ctx->ipa_hw_type == IPA_HW_v4_5) &&
(prot == IPA_HW_PROTOCOL_AQC)) {
enum ipa_eth_client_type type;
u8 inst_id;
struct ipa3_eth_info *eth_info;
type = pipe->client_info->client_type;
inst_id = pipe->client_info->inst_id;
eth_info = &ipa3_ctx->eth_info[type][inst_id];
if (!eth_info->num_ch) {
bar_addr =
IPA_ETH_PCIE_SET(pipe->info.client_info.aqc.bar_addr);
result = ipa3_eth_uc_init_peripheral(true, bar_addr);
if (result) {
IPAERR("failed to init peripheral from uc\n");
goto uc_init_peripheral_fail;
}
}
ch = pipe->info.client_info.aqc.aqc_ch;
}
ipa3_eth_save_client_mapping(pipe, client_type,
id, ep_idx, ep->gsi_chan_hdl);
result = ipa3_eth_config_uc(true,
IPA_HW_PROTOCOL_RTK,
(pipe->dir == IPA_ETH_PIPE_DIR_TX)
? IPA_ETH_TX : IPA_ETH_RX,
ep->gsi_chan_hdl);
if (result) {
IPAERR("failed to config uc\n");
goto config_uc_fail;
if ((ipa3_ctx->ipa_hw_type == IPA_HW_v4_5) ||
(prot != IPA_HW_PROTOCOL_AQC)) {
result = ipa3_eth_config_uc(true,
prot,
(pipe->dir == IPA_ETH_PIPE_DIR_TX)
? IPA_ETH_TX : IPA_ETH_RX,
ep->gsi_chan_hdl, ch);
if (result) {
IPAERR("failed to config uc\n");
goto config_uc_fail;
}
}
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return 0;
config_uc_fail:
/* stop uC gsi dbg stats monitor */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) {
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].ch_id
ipa3_ctx->gsi_info[prot].ch_id_info[id].ch_id
= 0xff;
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].dir
ipa3_ctx->gsi_info[prot].ch_id_info[id].dir
= pipe->dir;
ipa3_uc_debug_stats_alloc(
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK]);
ipa3_ctx->gsi_info[prot]);
}
uc_init_peripheral_fail:
ipa3_stop_gsi_channel(ep->gsi_chan_hdl);
start_channel_fail:
ipa3_disable_data_path(ep_idx);
enable_data_path_fail:
query_msi_fail:
query_ch_db_fail:
setup_rtk_gsi_ch_fail:
setup_gsi_ch_fail:
cfg_ep_fail:
disable_data_path_fail:
ipa3_smmu_map_rtk_pipes(pipe, false);
ipa3_smmu_map_eth_pipes(pipe, false);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return result;
}
EXPORT_SYMBOL(ipa3_eth_rtk_connect);
EXPORT_SYMBOL(ipa3_eth_connect);
int ipa3_eth_aqc_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
return 0;
}
EXPORT_SYMBOL(ipa3_eth_aqc_connect);
int ipa3_eth_emac_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
return 0;
}
EXPORT_SYMBOL(ipa3_eth_emac_connect);
int ipa3_eth_rtk_disconnect(
int ipa3_eth_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
@@ -603,6 +896,18 @@ int ipa3_eth_rtk_disconnect(
struct ipa3_ep_context *ep;
int ep_idx;
int id;
enum ipa4_hw_protocol prot;
result = ipa3_eth_get_prot(pipe, &prot);
if (result) {
IPAERR("Could not determine protocol\n");
return result;
}
if (prot == IPA_HW_PROTOCOL_ETH) {
IPAERR("EMAC\\NTN still not supported using this framework\n");
return -EFAULT;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ep_idx = ipa_get_ep_mapping(client_type);
@@ -620,15 +925,16 @@ int ipa3_eth_rtk_disconnect(
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -EFAULT;
}
id = (pipe->dir == IPA_ETH_PIPE_DIR_TX) ? 1 : 0;
/* stop uC gsi dbg stats monitor */
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) {
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].ch_id
ipa3_ctx->gsi_info[prot].ch_id_info[id].ch_id
= 0xff;
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK].ch_id_info[id].dir
ipa3_ctx->gsi_info[prot].ch_id_info[id].dir
= pipe->dir;
ipa3_uc_debug_stats_alloc(
ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_RTK]);
ipa3_ctx->gsi_info[prot]);
}
/* stop gsi channel */
result = ipa3_stop_gsi_channel(ep_idx);
@@ -638,13 +944,17 @@ int ipa3_eth_rtk_disconnect(
ipa_assert();
goto fail;
}
result = ipa3_eth_config_uc(false,
IPA_HW_PROTOCOL_RTK,
(pipe->dir == IPA_ETH_PIPE_DIR_TX)
? IPA_ETH_TX : IPA_ETH_RX,
ep->gsi_chan_hdl);
if (result)
IPAERR("failed to config uc\n");
if ((ipa3_ctx->ipa_hw_type == IPA_HW_v4_5) ||
(prot != IPA_HW_PROTOCOL_AQC)) {
result = ipa3_eth_config_uc(false,
prot,
(pipe->dir == IPA_ETH_PIPE_DIR_TX)
? IPA_ETH_TX : IPA_ETH_RX,
ep->gsi_chan_hdl, 0);
if (result)
IPAERR("failed to config uc\n");
}
/* tear down pipe */
result = ipa3_reset_gsi_channel(ep_idx);
@@ -667,32 +977,36 @@ int ipa3_eth_rtk_disconnect(
}
memset(ep, 0, sizeof(struct ipa3_ep_context));
IPADBG("client (ep: %d) disconnected\n", ep_idx);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
ipa3_uc_debug_stats_dealloc(IPA_HW_PROTOCOL_RTK);
ipa3_uc_debug_stats_dealloc(prot);
if (IPA_CLIENT_IS_PROD(client_type))
ipa3_delete_dflt_flt_rules(ep_idx);
/* unmap th pipe */
result = ipa3_smmu_map_rtk_pipes(pipe, false);
result = ipa3_smmu_map_eth_pipes(pipe, false);
if (result)
IPAERR("failed to unmap SMMU %d\n", result);
ipa3_eth_release_client_mapping(pipe, id);
if ((ipa3_ctx->ipa_hw_type == IPA_HW_v4_5) &&
(prot == IPA_HW_PROTOCOL_AQC)) {
enum ipa_eth_client_type type;
u8 inst_id;
struct ipa3_eth_info *eth_info;
type = pipe->client_info->client_type;
inst_id = pipe->client_info->inst_id;
eth_info = &ipa3_ctx->eth_info[type][inst_id];
if (!eth_info->num_ch) {
result = ipa3_eth_uc_init_peripheral(false, 0);
if (result) {
IPAERR("failed to de-init peripheral %d\n", result);
goto fail;
}
}
}
fail:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return result;
}
EXPORT_SYMBOL(ipa3_eth_rtk_disconnect);
int ipa3_eth_aqc_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
return 0;
}
EXPORT_SYMBOL(ipa3_eth_aqc_disconnect);
int ipa3_eth_emac_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type)
{
return 0;
}
EXPORT_SYMBOL(ipa3_eth_emac_disconnect);
EXPORT_SYMBOL(ipa3_eth_disconnect);

View File

@@ -3157,22 +3157,10 @@ static inline int ipa_eth_init(void) { return 0; }
static inline void ipa_eth_exit(void) { }
#endif
void ipa3_eth_debugfs_add_node(struct ipa_eth_client *client);
int ipa3_eth_rtk_connect(
int ipa3_eth_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_aqc_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_emac_connect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_rtk_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_aqc_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_emac_disconnect(
int ipa3_eth_disconnect(
struct ipa_eth_client_pipe_info *pipe,
enum ipa_client_type client_type);
int ipa3_eth_client_conn_evt(struct ipa_ecm_msg *msg);