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

Commit 37ee8610 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: add support for status based data path"

parents 3ed74b15 5560c550
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -276,6 +276,23 @@ struct ipa_ep_cfg_deaggr {
	u32 max_packet_len;
};

/**
 * struct ipa_ep_cfg_status - status configuration in IPA end-point
 * @status_en: Determines if end point supports Status Indications. SW should
 *	set this bit in order to enable Statuses. Output Pipe - send
 *	Status indications only if bit is set. Input Pipe - forward Status
 *	indication to STATUS_ENDP only if bit is set. Valid for Input
 *	and Output Pipes (IPA Consumer and Producer)
 * @status_ep: Statuses generated for this endpoint will be forwarded to the
 *	specifed Status End Point. Status endpoint needs to be
 *	configured with STATUS_EN=1 Valid only for Input Pipes (IPA
 *	Consumer)
 */
struct ipa_ep_cfg_status {
	bool status_en;
	u8 status_ep;
};

/**
 * struct ipa_ep_cfg - configuration of IPA end-point
 * @nat:	NAT parmeters
@@ -284,6 +301,7 @@ struct ipa_ep_cfg_deaggr {
 * @aggr:	Aggregation parameters
 * @deaggr:	Deaggregation params
 * @route:	Routing parameters
 * @status:	Status parameters
 */
struct ipa_ep_cfg {
	struct ipa_ep_cfg_nat nat;
@@ -293,6 +311,7 @@ struct ipa_ep_cfg {
	struct ipa_ep_cfg_aggr aggr;
	struct ipa_ep_cfg_deaggr deaggr;
	struct ipa_ep_cfg_route route;
	struct ipa_ep_cfg_status status;
};

typedef void (*ipa_notify_cb)(void *priv, enum ipa_dp_evt_type evt,
@@ -397,6 +416,9 @@ struct ipa_sys_connect_params {
struct ipa_tx_meta {
	u8 mbim_stream_id;
	bool mbim_stream_id_valid;
	u8 pkt_init_dst_ep;
	bool pkt_init_dst_ep_valid;
	bool pkt_init_dst_ep_remote;
};

/**
@@ -601,6 +623,8 @@ int ipa_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg);

int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg);

int ipa_cfg_ep_status(u32 clnt_hdl, const struct ipa_ep_cfg_status *ipa_ep_cfg);

int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
				const struct ipa_ep_cfg_holb *ipa_ep_cfg);

@@ -903,6 +927,12 @@ static inline int ipa_cfg_ep_holb(u32 clnt_hdl,
	return -EPERM;
}

static inline int ipa_cfg_ep_status(u32 clnt_hdl,
		const struct ipa_ep_cfg_status *ipa_ep_cfg)
{
	return -EPERM;
}

/*
 * Header removal / addition
 */
+33 −107
Original line number Diff line number Diff line
@@ -126,13 +126,6 @@ static struct msm_bus_scale_pdata ipa_bus_client_pdata = {

struct ipa_context *ipa_ctx;

static bool polling_mode;
module_param(polling_mode, bool, 0644);
MODULE_PARM_DESC(polling_mode,
		"1 - pure polling mode; 0 - interrupt+polling mode");
static uint polling_delay_ms = 50;
module_param(polling_delay_ms, uint, 0644);
MODULE_PARM_DESC(polling_delay_ms, "set to desired delay between polls");
static bool hdr_tbl_lcl = 1;
module_param(hdr_tbl_lcl, bool, 0644);
MODULE_PARM_DESC(hdr_tbl_lcl, "where hdr tbl resides 1-local; 0-system");
@@ -724,10 +717,19 @@ static int ipa_setup_exception_path(void)
	hdr->num_hdrs = 1;
	hdr->commit = 1;
	hdr_entry = &hdr->hdr[0];
	strlcpy(hdr_entry->name, IPA_A5_MUX_HDR_NAME, IPA_RESOURCE_NAME_MAX);

	/* set template for the A5_MUX header in header addition block */
	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
		strlcpy(hdr_entry->name, IPA_A5_MUX_HDR_NAME,
				IPA_RESOURCE_NAME_MAX);
		/* set template for the A5_MUX hdr in header addition block */
		hdr_entry->hdr_len = IPA_A5_MUX_HEADER_LENGTH;
	} else if (ipa_ctx->ipa_hw_type == IPA_HW_v2_0) {
		strlcpy(hdr_entry->name, IPA_LAN_RX_HDR_NAME,
				IPA_RESOURCE_NAME_MAX);
		hdr_entry->hdr_len = IPA_LAN_RX_HEADER_LENGTH;
	} else {
		WARN_ON(1);
	}

	if (ipa_add_hdr(hdr)) {
		IPAERR("fail to add exception hdr\n");
@@ -744,8 +746,10 @@ static int ipa_setup_exception_path(void)
	ipa_ctx->excp_hdr_hdl = hdr_entry->hdr_hdl;

	/* set the route register to pass exception packets to Apps */
	route.route_def_pipe = IPA_A5_LAN_WAN_IN;
	route.route_frag_def_pipe = IPA_A5_LAN_WAN_IN;
	route.route_def_pipe = ipa_get_ep_mapping(ipa_ctx->mode,
			IPA_CLIENT_A5_LAN_WAN_CONS);
	route.route_frag_def_pipe = ipa_get_ep_mapping(ipa_ctx->mode,
			IPA_CLIENT_A5_LAN_WAN_CONS);
	route.route_def_hdr_table = !ipa_ctx->hdr_tbl_lcl;

	if (ipa_cfg_route(&route)) {
@@ -760,44 +764,6 @@ bail:
	return ret;
}

static void ipa_poll_function(struct work_struct *work)
{
	int ret;
	int tx_pipes[] = { IPA_A5_CMD, IPA_A5_LAN_WAN_OUT,
		IPA_A5_WLAN_AMPDU_OUT };
	int i;
	int num_tx_pipes;
	int cnt;

	num_tx_pipes = sizeof(tx_pipes) / sizeof(tx_pipes[0]);

	if (!IPA_MOBILE_AP_MODE(ipa_ctx->mode))
		num_tx_pipes--;

	do {
		cnt = 0;

		/* check all the system pipes for tx comp and rx avail */
		if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
			cnt |= ipa_handle_rx_core(
					&ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
					false, true);

		for (i = 0; i < num_tx_pipes; i++)
			if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
				cnt |= ipa_handle_tx_core(
						&ipa_ctx->sys[tx_pipes[i]],
						false, true);
	} while (cnt);

	/* re-post the poll work */
	INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
	ret = schedule_delayed_work_on(smp_processor_id(), &ipa_ctx->poll_work,
			msecs_to_jiffies(polling_delay_ms));

	return;
}

static int ipa_setup_apps_pipes(void)
{
	struct ipa_sys_connect_params sys_in;
@@ -816,20 +782,6 @@ static int ipa_setup_apps_pipes(void)
	}
	IPADBG("Apps to IPA cmd pipe is connected\n");

	/* Start polling, only if needed */
	if (ipa_ctx->polling_mode) {
		INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
		result =
		   schedule_delayed_work_on(smp_processor_id(),
					&ipa_ctx->poll_work,
					msecs_to_jiffies(polling_delay_ms));
		if (!result) {
			IPAERR(":schedule delayed work failed.\n");
			goto fail_schedule_delayed_work;
		}
		IPADBG("polling mode enabled\n\n");
	}

	if (ipa_setup_exception_path()) {
		IPAERR(":fail to setup excp path\n");
		result = -EPERM;
@@ -848,13 +800,28 @@ static int ipa_setup_apps_pipes(void)
	memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
	sys_in.client = IPA_CLIENT_A5_LAN_WAN_CONS;
	sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
	if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
		sys_in.ipa_ep_cfg.hdr.hdr_a5_mux = 1;
	sys_in.ipa_ep_cfg.hdr.hdr_len = 8;  /* size of A5 exception hdr */
		sys_in.ipa_ep_cfg.hdr.hdr_len = IPA_A5_MUX_HEADER_LENGTH;
	} else if (ipa_ctx->ipa_hw_type == IPA_HW_v2_0) {
		sys_in.notify = ipa_lan_rx_cb;
		sys_in.priv = NULL;
		sys_in.ipa_ep_cfg.hdr.hdr_len = IPA_LAN_RX_HEADER_LENGTH;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_little_endian = false;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid = true;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad = IPA_HDR_PAD;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding = false;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset = 0;
		sys_in.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
	} else {
		WARN_ON(1);
	}
	if (ipa_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_data_in)) {
		IPAERR(":setup sys pipe failed.\n");
		result = -EPERM;
		goto fail_schedule_delayed_work;
	}

	/* LAN-WAN OUT (A5->IPA) */
	memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
	sys_in.client = IPA_CLIENT_A5_LAN_WAN_PROD;
@@ -885,7 +852,6 @@ fail_cmd:

static void ipa_teardown_apps_pipes(void)
{
	cancel_delayed_work(&ipa_ctx->poll_work);
	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_out);
	ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
	__ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
@@ -1609,8 +1575,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
		goto fail_mem_ctx;
	}

	IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
	ipa_ctx->polling_mode = polling_mode;
	IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
	       hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
	       ip6_flt_tbl_lcl);
@@ -1857,35 +1821,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
	mutex_init(&ipa_ctx->lock);
	mutex_init(&ipa_ctx->nat_mem.lock);

	for (i = 0; i < IPA_A5_SYS_MAX; i++) {
		INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
		spin_lock_init(&ipa_ctx->sys[i].spinlock);
		if (i != IPA_A5_WLAN_AMPDU_OUT)
			ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
		else
			ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
		if (ipa_ctx->polling_mode)
			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
		else
			atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
	}

	ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
	if (!ipa_ctx->rx_wq) {
		IPAERR(":fail to create rx wq\n");
		result = -ENOMEM;
		goto fail_rx_wq;
	}

	ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
			WQ_CPU_INTENSIVE, 1);
	if (!ipa_ctx->tx_wq) {
		IPAERR(":fail to create tx wq\n");
		result = -ENOMEM;
		goto fail_tx_wq;
	}
	IPADBG("workqueues were created\n");

	ipa_ctx->hdr_hdl_tree = RB_ROOT;
	ipa_ctx->rt_rule_hdl_tree = RB_ROOT;
	ipa_ctx->rt_tbl_hdl_tree = RB_ROOT;
@@ -1916,10 +1851,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
	}
	IPADBG("IPA System2Bam pipes were connected\n");

	ipa_replenish_rx_cache();
	IPADBG("Rx cache was replenished to %d packets wrapper",
			IPA_RX_POOL_CEIL);

	if (ipa_init_flt_block()) {
		IPAERR("fail to setup dummy filter rules\n");
		result = -ENODEV;
@@ -2037,13 +1968,8 @@ fail_alloc_chrdev_region:
			  ipa_ctx->empty_rt_tbl_mem.base,
			  ipa_ctx->empty_rt_tbl_mem.phys_base);
fail_empty_rt_tbl:
	ipa_cleanup_rx();
	ipa_teardown_apps_pipes();
fail_apps_pipes:
	destroy_workqueue(ipa_ctx->tx_wq);
fail_tx_wq:
	destroy_workqueue(ipa_ctx->rx_wq);
fail_rx_wq:
	/*
	 * DMA pool need to be released only for IPA HW v1.0 only.
	 */
+2 −1
Original line number Diff line number Diff line
@@ -579,7 +579,8 @@ EXPORT_SYMBOL(ipa_bridge_teardown);
bool ipa_emb_ul_pipes_empty(void)
{
	struct sps_pipe *emb_ipa_ul =
		ipa_ctx->sys[IPA_A5_LAN_WAN_OUT].ep->ep_hdl;
		ipa_ctx->ep[ipa_get_ep_mapping(
			ipa_ctx->mode, IPA_CLIENT_A5_LAN_WAN_PROD)].ep_hdl;
	struct sps_pipe *emb_ipa_to_dma =
		bridge[IPA_BRIDGE_TYPE_EMBEDDED].pipe[IPA_UL_FROM_IPA].pipe;
	struct sps_pipe *emb_dma_to_a2 =
+693 −333

File changed.

Preview size limit exceeded, changes collapsed.

+79 −0
Original line number Diff line number Diff line
@@ -275,4 +275,83 @@ struct ipa_ip_packet_tag {
	u32 tag;
};

/*! @brief Struct for the the IPA UL packet status header */
struct ipa_hw_pkt_status {
	u32 status_opcode:8;
	u32 exception:8;
	u32 status_mask:16;
	u32 pkt_len:16;
	u32 endp_src_idx:5;
	u32 reserved_1:3;
	u32 endp_dest_idx:5;
	u32 reserved_2:3;
	u32 metadata:32;
	u32 filt_local:1;
	u32 filt_global:1;
	u32 filt_pipe_idx:5;
	u32 filt_match:1;
	u32 filt_rule_idx:6;
	u32 ret_hdr:1;
	u32 reserved_3:1;
	u32 tag_f_1:16;
	u32 tag_f_2:32;
	u32 time_day_ctr:32;
	u32 nat_hit:1;
	u32 nat_tbl_idx:13;
	u32 nat_type:2;
	u32 route_local:1;
	u32 route_tbl_idx:5;
	u32 route_match:1;
	u32 reserved_4:1;
	u32 route_rule_idx:8;
	u32 hdr_local:1;
	u32 hdr_offset:10;
	u32 frag_hit:1;
	u32 frag_rule:4;
	u32 reserved_5:16;
};

#define IPA_PKT_STATUS_SIZE sizeof(struct ipa_hw_pkt_status)

/*! @brief Status header opcodes */
enum ipa_hw_status_opcode {
	IPA_HW_STATUS_OPCODE_MIN,
	IPA_HW_STATUS_OPCODE_PACKET = IPA_HW_STATUS_OPCODE_MIN,
	IPA_HW_STATUS_OPCODE_NEW_FRAG_RULE,
	IPA_HW_STATUS_OPCODE_DROPPED_PACKET,
	IPA_HW_STATUS_OPCODE_MAX
};

/*! @brief Possible Masks received in status */
enum ipa_hw_pkt_status_mask {
	IPA_HW_PKT_STATUS_MASK_FRAG_PROCESS      = 0x1,
	IPA_HW_PKT_STATUS_MASK_FILT_PROCESS      = 0x2,
	IPA_HW_PKT_STATUS_MASK_NAT_PROCESS       = 0x4,
	IPA_HW_PKT_STATUS_MASK_ROUTE_PROCESS     = 0x8,
	IPA_HW_PKT_STATUS_MASK_TAG_VALID         = 0x10,
	IPA_HW_PKT_STATUS_MASK_FRAGMENT          = 0x20,
	IPA_HW_PKT_STATUS_MASK_FIRST_FRAGMENT    = 0x40,
	IPA_HW_PKT_STATUS_MASK_V4                = 0x80,
	IPA_HW_PKT_STATUS_MASK_CKSUM_PROCESS     = 0x100,
	IPA_HW_PKT_STATUS_MASK_AGGR_PROCESS      = 0x200,
	IPA_HW_PKT_STATUS_MASK_DEST_EOT          = 0x400,
	IPA_HW_PKT_STATUS_MASK_DEAGGR_PROCESS    = 0x800,
	IPA_HW_PKT_STATUS_MASK_DEAGG_FIRST       = 0x1000,
	IPA_HW_PKT_STATUS_MASK_SRC_EOT           = 0x2000
};

/*! @brief Possible Exceptions received in status */
enum ipa_hw_pkt_status_exception {
	IPA_HW_PKT_STATUS_EXCEPTION_NONE           = 0x0,
	IPA_HW_PKT_STATUS_EXCEPTION_DEAGGR         = 0x1,
	IPA_HW_PKT_STATUS_EXCEPTION_REPL           = 0x2,
	IPA_HW_PKT_STATUS_EXCEPTION_IPTYPE         = 0x4,
	IPA_HW_PKT_STATUS_EXCEPTION_IHL            = 0x8,
	IPA_HW_PKT_STATUS_EXCEPTION_FRAG_RULE_MISS = 0x10,
	IPA_HW_PKT_STATUS_EXCEPTION_SW_FILT        = 0x20,
	IPA_HW_PKT_STATUS_EXCEPTION_NAT            = 0x40,
	IPA_HW_PKT_STATUS_EXCEPTION_ACTUAL_MAX,
	IPA_HW_PKT_STATUS_EXCEPTION_MAX            = 0xFF
};

#endif /* _IPA_HW_DEFS_H */
Loading