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:

committed by
Gerrit - the friendly Code Review server

parent
ace2384057
commit
40fcad23c6
@@ -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)
|
||||
{
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user