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

Commit df4ddd95 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: add NULL pointer check to ipa gsb"

parents 6295107a 0427a579
Loading
Loading
Loading
Loading
+195 −77
Original line number Diff line number Diff line
@@ -67,7 +67,8 @@
static char dbg_buff[IPA_GSB_MAX_MSG_LEN];

#define IPA_GSB_SKB_HEADROOM 256
#define IPA_GSB_AGGR_BYTE_LIMIT 6
#define IPA_GSB_SKB_DUMMY_HEADER 42
#define IPA_GSB_AGGR_BYTE_LIMIT 14
#define IPA_GSB_AGGR_TIME_LIMIT 1

static struct dentry *dent;
@@ -131,7 +132,7 @@ struct ipa_gsb_iface_info {
 * struct ipa_gsb_context - GSB driver context information
 * @logbuf: buffer of ipc logging
 * @logbuf_low: buffer of ipc logging (low priority)
 * @lock: mutex lock
 * @lock: global mutex lock for global variables
 * @prod_hdl: handle for prod pipe
 * @cons_hdl: handle for cons pipe
 * @ipa_sys_desc_size: sys pipe desc size
@@ -140,6 +141,8 @@ struct ipa_gsb_iface_info {
 * @num_connected_iface: number of connected interface
 * @num_resumed_iface: number of resumed interface
 * @iface: interface information
 * @iface_lock: interface mutex lock for control path
 * @iface_spinlock: interface spinlock for data path
 * @pm_hdl: IPA PM handle
 */
struct ipa_gsb_context {
@@ -154,6 +157,8 @@ struct ipa_gsb_context {
	int num_connected_iface;
	int num_resumed_iface;
	struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE];
	struct mutex iface_lock[MAX_SUPPORTED_IFACE];
	spinlock_t iface_spinlock[MAX_SUPPORTED_IFACE];
	u32 pm_hdl;
};

@@ -241,6 +246,7 @@ static void ipa_gsb_debugfs_destroy(void)

static int ipa_gsb_driver_init(struct odu_bridge_params *params)
{
	int i;
	if (!ipa_is_ready()) {
		IPA_GSB_ERR("IPA is not ready\n");
		return -EFAULT;
@@ -253,6 +259,10 @@ static int ipa_gsb_driver_init(struct odu_bridge_params *params)
		return -ENOMEM;

	mutex_init(&ipa_gsb_ctx->lock);
	for (i = 0; i < MAX_SUPPORTED_IFACE; i++) {
		mutex_init(&ipa_gsb_ctx->iface_lock[i]);
		spin_lock_init(&ipa_gsb_ctx->iface_spinlock[i]);
	}
	ipa_gsb_debugfs_init();

	return 0;
@@ -280,22 +290,36 @@ static int ipa_gsb_commit_partial_hdr(struct ipa_gsb_iface_info *iface_info)
			 "%s_ipv4", iface_info->netdev_name);
	snprintf(hdr->hdr[1].name, sizeof(hdr->hdr[1].name),
			 "%s_ipv6", iface_info->netdev_name);
	/* partial header: [hdl][QMAP ID][pkt size][ETH header] */
	/*
	 * partial header:
	 * [hdl][QMAP ID][pkt size][Dummy Header][ETH header]
	 */
	for (i = IPA_IP_v4; i < IPA_IP_MAX; i++) {
		hdr->hdr[i].hdr_len = ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr);
		/*
		 * Optimization: add dummy header to reserve space
		 * for rndis header, so we can do the skb_clone
		 * instead of deep copy.
		 */
		hdr->hdr[i].hdr_len = ETH_HLEN +
			sizeof(struct ipa_gsb_mux_hdr) +
			IPA_GSB_SKB_DUMMY_HEADER;
		hdr->hdr[i].type = IPA_HDR_L2_ETHERNET_II;
		hdr->hdr[i].is_partial = 1;
		hdr->hdr[i].is_eth2_ofst_valid = 1;
		hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr);
		hdr->hdr[i].eth2_ofst = sizeof(struct ipa_gsb_mux_hdr) +
			IPA_GSB_SKB_DUMMY_HEADER;
		/* populate iface handle */
		hdr->hdr[i].hdr[0] = iface_info->iface_hdl;
		/* populate src ETH address */
		memcpy(&hdr->hdr[i].hdr[10], iface_info->device_ethaddr, 6);
		memcpy(&hdr->hdr[i].hdr[10 + IPA_GSB_SKB_DUMMY_HEADER],
			iface_info->device_ethaddr, 6);
		/* populate Ethertype */
		if (i == IPA_IP_v4)
			*(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IP);
			*(u16 *)(hdr->hdr[i].hdr + 16 +
				IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IP);
		else
			*(u16 *)(hdr->hdr[i].hdr + 16) = htons(ETH_P_IPV6);
			*(u16 *)(hdr->hdr[i].hdr + 16 +
				IPA_GSB_SKB_DUMMY_HEADER) = htons(ETH_P_IPV6);
	}

	if (ipa_add_hdr(hdr)) {
@@ -412,7 +436,7 @@ static void ipa_gsb_pm_cb(void *user_data, enum ipa_pm_cb_event event)
		return;
	}

	IPA_GSB_DBG("wake up clients\n");
	IPA_GSB_DBG_LOW("wake up clients\n");
	for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
		if (ipa_gsb_ctx->iface[i] != NULL)
			ipa_gsb_ctx->iface[i]->wakeup_request(
@@ -462,7 +486,7 @@ int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
	if (!params || !params->wakeup_request || !hdl ||
		!params->info.netdev_name || !params->info.tx_dp_notify ||
		!params->info.send_dl_skb) {
		IPA_GSB_ERR("NULL parameters\n");
		IPA_GSB_ERR("Invalid parameters\n");
		return -EINVAL;
	}

@@ -583,6 +607,7 @@ static void ipa_gsb_deregister_pm(void)

int ipa_bridge_cleanup(u32 hdl)
{
	int i;
	if (!ipa_gsb_ctx) {
		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
		return -EFAULT;
@@ -593,59 +618,49 @@ int ipa_bridge_cleanup(u32 hdl)
		return -EINVAL;
	}

	if (ipa_gsb_ctx->iface[hdl] == NULL) {
		IPA_GSB_ERR("fail to find interface\n");
	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	IPA_GSB_DBG("client hdl: %d\n", hdl);
	mutex_lock(&ipa_gsb_ctx->lock);

	if (ipa_gsb_ctx->iface[hdl]->is_connected) {
		IPA_GSB_ERR("cannot cleanup when iface is connected\n");
		mutex_unlock(&ipa_gsb_ctx->lock);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]);
	ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]);
	spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]);
	kfree(ipa_gsb_ctx->iface[hdl]);
	ipa_gsb_ctx->iface[hdl] = NULL;
	ipa_gsb_ctx->iface_hdl[hdl] = false;
	spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	mutex_lock(&ipa_gsb_ctx->lock);
	ipa_gsb_ctx->num_iface--;
	IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface);

	if (ipa_gsb_ctx->num_iface == 0) {
		ipa_gsb_deregister_pm();
		ipa_gsb_debugfs_destroy();
		ipc_log_context_destroy(ipa_gsb_ctx->logbuf);
		ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low);
		mutex_unlock(&ipa_gsb_ctx->lock);
		mutex_destroy(&ipa_gsb_ctx->lock);
		for (i = 0; i < MAX_SUPPORTED_IFACE; i++)
			mutex_destroy(&ipa_gsb_ctx->iface_lock[i]);
		kfree(ipa_gsb_ctx);
		ipa_gsb_ctx = NULL;
		return 0;
	}

	mutex_unlock(&ipa_gsb_ctx->lock);
	return 0;
}
EXPORT_SYMBOL(ipa_bridge_cleanup);

static struct sk_buff *ipa_gsb_skb_copy(struct sk_buff *skb, int len)
{
	struct sk_buff *skb2 = NULL;

	skb2 = __dev_alloc_skb(len + IPA_GSB_SKB_HEADROOM, GFP_KERNEL);
	if (likely(skb2)) {
		skb_reserve(skb2, IPA_GSB_SKB_HEADROOM);
		memcpy(skb2->data, skb->data, len);
		skb2->len = len;
		skb_set_tail_pointer(skb2, len);
	}

	return skb2;
}

static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt,
	unsigned long data)
{
@@ -663,24 +678,56 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt,

	skb = (struct sk_buff *)data;

	if (skb == NULL) {
		IPA_GSB_ERR("unexpected NULL data\n");
		WARN_ON(1);
		return;
	}

	while (skb->len) {
		mux_hdr = (struct ipa_gsb_mux_hdr *)skb->data;
		pkt_size = mux_hdr->pkt_size;
		/* 4-byte padding */
		pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN + 3) & ~3)
			- (pkt_size + sizeof(*mux_hdr) + ETH_HLEN);
		pad_byte = ((pkt_size + sizeof(*mux_hdr) + ETH_HLEN +
			3 + IPA_GSB_SKB_DUMMY_HEADER) & ~3) -
			(pkt_size + sizeof(*mux_hdr) +
			ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER);
		hdl = mux_hdr->iface_hdl;
		IPA_GSB_DBG("pkt_size: %d, pad_byte: %d, hdl: %d\n",
		if (hdl >= MAX_SUPPORTED_IFACE) {
			IPA_GSB_ERR("invalid hdl: %d\n", hdl);
			break;
		}
		IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n",
			pkt_size, pad_byte, hdl);

		/* remove 4 byte mux header */
		skb_pull(skb, sizeof(*mux_hdr));
		skb2 = ipa_gsb_skb_copy(skb, pkt_size + ETH_HLEN);
		/* remove 4 byte mux header AND dummy header*/
		skb_pull(skb, sizeof(*mux_hdr) + IPA_GSB_SKB_DUMMY_HEADER);

		skb2 = skb_clone(skb, GFP_KERNEL);
		if (!skb2) {
			IPA_GSB_ERR("skb_clone failed\n");
			WARN_ON(1);
			break;
		}
		skb_trim(skb2, pkt_size + ETH_HLEN);
		spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]);
		if (ipa_gsb_ctx->iface[hdl] != NULL) {
			ipa_gsb_ctx->iface[hdl]->send_dl_skb(
				ipa_gsb_ctx->iface[hdl]->priv, skb2);
			ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++;

			spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]);
			skb_pull(skb, pkt_size + ETH_HLEN + pad_byte);
		} else {
			IPA_GSB_ERR("Invalid hdl: %d, drop the skb\n", hdl);
			spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]);
			dev_kfree_skb_any(skb2);
			break;
		}
	}

	if (skb) {
		dev_kfree_skb_any(skb);
		skb = NULL;
	}
}

@@ -693,6 +740,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt,

	skb = (struct sk_buff *)data;

	if (skb == NULL) {
		IPA_GSB_ERR("unexpected NULL data\n");
		WARN_ON(1);
		return;
	}

	if (evt != IPA_WRITE_DONE && evt != IPA_RECEIVE) {
		IPA_GSB_ERR("unexpected event: %d\n", evt);
		dev_kfree_skb_any(skb);
@@ -704,7 +757,12 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt,
	/* change to host order */
	*(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr);
	hdl = mux_hdr->iface_hdl;
	IPA_GSB_DBG("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("invalid hdl: %d and cb, drop the skb\n", hdl);
		dev_kfree_skb_any(skb);
		return;
	}
	IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl);

	/* remove 4 byte mux header */
	skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr));
@@ -742,7 +800,8 @@ static int ipa_gsb_connect_sys_pipe(void)
	/* configure TX EP */
	cons_params.client = IPA_CLIENT_ODU_EMB_CONS;
	cons_params.ipa_ep_cfg.hdr.hdr_len =
		ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr);
		ETH_HLEN + sizeof(struct ipa_gsb_mux_hdr) +
		IPA_GSB_SKB_DUMMY_HEADER;
	cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1;
	cons_params.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2;
	cons_params.ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment = 2;
@@ -786,13 +845,23 @@ int ipa_bridge_connect(u32 hdl)
		return -EFAULT;
	}

	if (hdl >= MAX_SUPPORTED_IFACE) {
		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
		return -EINVAL;
	}

	IPA_GSB_DBG("client hdl: %d\n", hdl);

	mutex_lock(&ipa_gsb_ctx->lock);
	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (ipa_gsb_ctx->iface[hdl]->is_connected) {
		IPA_GSB_DBG("iface was already connected\n");
		mutex_unlock(&ipa_gsb_ctx->lock);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return 0;
	}

@@ -800,13 +869,13 @@ int ipa_bridge_connect(u32 hdl)
		ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl);
		if (ret) {
			IPA_GSB_ERR("failed to activate ipa pm\n");
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}
		ret = ipa_gsb_connect_sys_pipe();
		if (ret) {
			IPA_GSB_ERR("fail to connect pipe\n");
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}
	}
@@ -822,7 +891,7 @@ int ipa_bridge_connect(u32 hdl)
	IPA_GSB_DBG("num resumed iface: %d\n",
		ipa_gsb_ctx->num_resumed_iface);

	mutex_unlock(&ipa_gsb_ctx->lock);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	return 0;
}
EXPORT_SYMBOL(ipa_bridge_connect);
@@ -860,13 +929,23 @@ int ipa_bridge_disconnect(u32 hdl)
		return -EFAULT;
	}

	if (hdl >= MAX_SUPPORTED_IFACE) {
		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
		return -EINVAL;
	}

	IPA_GSB_DBG("client hdl: %d\n", hdl);

	mutex_lock(&ipa_gsb_ctx->lock);
	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
		IPA_GSB_DBG("iface was not connected\n");
		mutex_unlock(&ipa_gsb_ctx->lock);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return 0;
	}

@@ -874,14 +953,14 @@ int ipa_bridge_disconnect(u32 hdl)
		ret = ipa_gsb_disconnect_sys_pipe();
		if (ret) {
			IPA_GSB_ERR("fail to discon pipes\n");
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return -EFAULT;
		}

		ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl);
		if (ret) {
			IPA_GSB_ERR("failed to deactivate ipa pm\n");
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return -EFAULT;
		}
	}
@@ -899,7 +978,7 @@ int ipa_bridge_disconnect(u32 hdl)
			ipa_gsb_ctx->num_resumed_iface);
	}

	mutex_unlock(&ipa_gsb_ctx->lock);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	return 0;
}
EXPORT_SYMBOL(ipa_bridge_disconnect);
@@ -913,25 +992,37 @@ int ipa_bridge_resume(u32 hdl)
		return -EFAULT;
	}

	IPA_GSB_DBG("client hdl: %d\n", hdl);
	if (hdl >= MAX_SUPPORTED_IFACE) {
		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
		return -EINVAL;
	}

	IPA_GSB_DBG_LOW("client hdl: %d\n", hdl);

	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
		IPA_GSB_ERR("iface is not connected\n");
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (ipa_gsb_ctx->iface[hdl]->is_resumed) {
		IPA_GSB_DBG("iface was already resumed\n");
		IPA_GSB_DBG_LOW("iface was already resumed\n");
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return 0;
	}

	mutex_lock(&ipa_gsb_ctx->lock);

	if (ipa_gsb_ctx->num_resumed_iface == 0) {
		ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl);
		if (ret) {
			IPA_GSB_ERR("fail to activate ipa pm\n");
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}

@@ -941,17 +1032,17 @@ int ipa_bridge_resume(u32 hdl)
			IPA_GSB_ERR(
				"fail to start con ep %d\n",
				ret);
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}
	}

	ipa_gsb_ctx->iface[hdl]->is_resumed = true;
	ipa_gsb_ctx->num_resumed_iface++;
	IPA_GSB_DBG("num resumed iface: %d\n",
	IPA_GSB_DBG_LOW("num resumed iface: %d\n",
		ipa_gsb_ctx->num_resumed_iface);

	mutex_unlock(&ipa_gsb_ctx->lock);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	return 0;
}
EXPORT_SYMBOL(ipa_bridge_resume);
@@ -965,20 +1056,32 @@ int ipa_bridge_suspend(u32 hdl)
		return -EFAULT;
	}

	IPA_GSB_DBG("client hdl: %d\n", hdl);
	if (hdl >= MAX_SUPPORTED_IFACE) {
		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
		return -EINVAL;
	}

	IPA_GSB_DBG_LOW("client hdl: %d\n", hdl);

	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (!ipa_gsb_ctx->iface[hdl]->is_connected) {
		IPA_GSB_ERR("iface is not connected\n");
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return -EFAULT;
	}

	if (!ipa_gsb_ctx->iface[hdl]->is_resumed) {
		IPA_GSB_DBG("iface was already suspended\n");
		IPA_GSB_DBG_LOW("iface was already suspended\n");
		mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
		return 0;
	}

	mutex_lock(&ipa_gsb_ctx->lock);

	if (ipa_gsb_ctx->num_resumed_iface == 1) {
		ret = ipa_stop_gsi_channel(
			ipa_gsb_ctx->cons_hdl);
@@ -986,7 +1089,7 @@ int ipa_bridge_suspend(u32 hdl)
			IPA_GSB_ERR(
				"fail to stop cons ep %d\n",
				ret);
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}

@@ -994,17 +1097,17 @@ int ipa_bridge_suspend(u32 hdl)
		if (ret) {
			IPA_GSB_ERR("fail to deactivate ipa pm\n");
			ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl);
			mutex_unlock(&ipa_gsb_ctx->lock);
			mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
			return ret;
		}
	}

	ipa_gsb_ctx->iface[hdl]->is_resumed = false;
	ipa_gsb_ctx->num_resumed_iface--;
	IPA_GSB_DBG("num resumed iface: %d\n",
	IPA_GSB_DBG_LOW("num resumed iface: %d\n",
		ipa_gsb_ctx->num_resumed_iface);

	mutex_unlock(&ipa_gsb_ctx->lock);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	return 0;
}
EXPORT_SYMBOL(ipa_bridge_suspend);
@@ -1013,16 +1116,26 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth)
{
	int ret;

	if (!ipa_gsb_ctx) {
		IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n");
		return -EFAULT;
	}

	if (hdl >= MAX_SUPPORTED_IFACE) {
		IPA_GSB_ERR("invalid hdl: %d\n", hdl);
		return -EINVAL;
	}

	IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth);

	mutex_lock(&ipa_gsb_ctx->lock);
	mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]);

	ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl,
		bandwidth);
	if (ret)
		IPA_GSB_ERR("fail to set perf profile\n");

	mutex_unlock(&ipa_gsb_ctx->lock);
	mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]);
	return ret;
}
EXPORT_SYMBOL(ipa_bridge_set_perf_profile);
@@ -1035,12 +1148,17 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb,
	struct stats iface_stats;
	int ret;

	IPA_GSB_DBG("client hdl: %d\n", hdl);
	IPA_GSB_DBG_LOW("client hdl: %d\n", hdl);

	iface_stats = ipa_gsb_ctx->iface[hdl]->iface_stats;
	if (!ipa_gsb_ctx->iface[hdl]) {
		IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl);
		return -EFAULT;
	}

	/* make sure skb has enough headroom */
	if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) {
		IPA_GSB_DBG("skb doesn't have enough headroom\n");
		IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n");
		skb2 = skb_copy_expand(skb, sizeof(struct ipa_gsb_mux_hdr),
			0, GFP_ATOMIC);
		if (!skb2) {
+9 −3
Original line number Diff line number Diff line
@@ -36,6 +36,9 @@
#define IPA_GENERIC_AGGR_TIME_LIMIT 500 /* 0.5msec */
#define IPA_GENERIC_AGGR_PKT_LIMIT 0

#define IPA_GSB_AGGR_BYTE_LIMIT 14
#define IPA_GSB_RX_BUFF_BASE_SZ 16384

#define IPA_GENERIC_RX_BUFF_BASE_SZ 8192
#define IPA_REAL_GENERIC_RX_BUFF_SZ(X) (SKB_DATA_ALIGN(\
		(X) + NET_SKB_PAD) +\
@@ -3049,11 +3052,14 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
			/* recycle skb for GSB use case */
			if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
				sys->free_rx_wrapper =
					ipa3_recycle_rx_wrapper;
					ipa3_free_rx_wrapper;
				sys->repl_hdlr =
					ipa3_replenish_rx_cache_recycle;
					ipa3_replenish_rx_cache;
				/* Overwrite buffer size & aggr limit for GSB */
				sys->rx_buff_sz = IPA_GENERIC_RX_BUFF_SZ(
					IPA_GENERIC_RX_BUFF_BASE_SZ);
					IPA_GSB_RX_BUFF_BASE_SZ);
				in->ipa_ep_cfg.aggr.aggr_byte_limit =
					IPA_GSB_AGGR_BYTE_LIMIT;
			} else {
				sys->free_rx_wrapper =
					ipa3_free_rx_wrapper;