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

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

Merge "msm: ipa4: add VLAN mode to rndis_ipa and ecm_ipa"

parents 58934f90 2da9d45e
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -2727,6 +2727,26 @@ int ipa_start_gsi_channel(u32 clnt_hdl)
}
EXPORT_SYMBOL(ipa_start_gsi_channel);

/**
* ipa_is_vlan_mode - check if a LAN driver should load in VLAN mode
* @iface - type of vlan capable device
* @res - query result: true for vlan mode, false for non vlan mode
*
* API must be called after ipa_is_ready() returns true, otherwise it will fail
*
* Returns: 0 on success, negative on failure
*/
int ipa_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res)
{
	int ret;

	IPA_API_DISPATCH_RETURN(ipa_is_vlan_mode, iface, res);

	return ret;

}
EXPORT_SYMBOL(ipa_is_vlan_mode);

/**
 * ipa_get_version_string() - Get string representation of IPA version
 * @ver: IPA version
+1 −0
Original line number Diff line number Diff line
@@ -420,6 +420,7 @@ struct ipa_api_controller {

	int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
		struct ipa_smmu_out_params *out);
	int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
};

#ifdef CONFIG_IPA
+89 −34
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -123,6 +124,7 @@ enum ecm_ipa_operation {
 * @ipa_rm_resource_name_prod: IPA resource manager producer resource
 * @ipa_rm_resource_name_cons: IPA resource manager consumer resource
 * @pm_hdl: handle for IPA PM
 * @is_vlan_mode: does the driver need to work in VLAN mode?
 */
struct ecm_ipa_dev {
	struct net_device *net;
@@ -141,6 +143,7 @@ struct ecm_ipa_dev {
	enum ipa_rm_resource_name ipa_rm_resource_name_prod;
	enum ipa_rm_resource_name ipa_rm_resource_name_cons;
	u32 pm_hdl;
	bool is_vlan_mode;
};

static int ecm_ipa_open(struct net_device *net);
@@ -173,7 +176,8 @@ static ssize_t ecm_ipa_debugfs_atomic_read
	(struct file *file, char __user *ubuf, size_t count, loff_t *ppos);
static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
	bool is_vlan_mode);
static int ecm_ipa_set_device_ethernet_addr
	(u8 *dev_ethaddr, u8 device_ethaddr[]);
static enum ecm_ipa_state ecm_ipa_next_state
@@ -283,6 +287,12 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
	}
	ECM_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);

	if (ipa_is_vlan_mode(IPA_VLAN_IF_ECM, &ecm_ipa_ctx->is_vlan_mode)) {
		ECM_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
		goto fail_get_vlan_mode;
	}
	ECM_IPA_DEBUG("is vlan mode %d\n", ecm_ipa_ctx->is_vlan_mode);

	result = ecm_ipa_rules_cfg
		(ecm_ipa_ctx, params->host_ethaddr, params->device_ethaddr);
	if (result) {
@@ -319,8 +329,9 @@ int ecm_ipa_init(struct ecm_ipa_params *params)

fail_register_netdev:
	ecm_ipa_rules_destroy(ecm_ipa_ctx);
fail_set_device_ethernet:
fail_rules_cfg:
fail_get_vlan_mode:
fail_set_device_ethernet:
	ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
fail_netdev_priv:
	free_netdev(net);
@@ -450,7 +461,8 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, void *priv)
	}
	ECM_IPA_DEBUG("ecm_ipa 2 Tx and 2 Rx properties were registered\n");

	retval = ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
	retval = ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl,
		ecm_ipa_ctx->is_vlan_mode);
	if (retval) {
		ECM_IPA_ERROR("fail on ep cfg\n");
		goto fail;
@@ -606,6 +618,10 @@ static netdev_tx_t ecm_ipa_start_xmit
		goto out;
	}

	if (ecm_ipa_ctx->is_vlan_mode)
		if (unlikely(skb->protocol != ETH_P_8021Q))
			ECM_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");

	ret = ipa_tx_dp(ecm_ipa_ctx->ipa_to_usb_client, skb, NULL);
	if (ret) {
		ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
@@ -843,6 +859,41 @@ static void ecm_ipa_enable_data_path(struct ecm_ipa_dev *ecm_ipa_ctx)
	ECM_IPA_DEBUG("queue started\n");
}

static void ecm_ipa_prepare_header_insertion(
	int eth_type,
	const char *hdr_name, struct ipa_hdr_add *add_hdr,
	const void *dst_mac, const void *src_mac, bool is_vlan_mode)
{
	struct ethhdr *eth_hdr;
	struct vlan_ethhdr *eth_vlan_hdr;

	ECM_IPA_LOG_ENTRY();

	add_hdr->is_partial = 0;
	strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);
	add_hdr->is_eth2_ofst_valid = true;
	add_hdr->eth2_ofst = 0;

	if (is_vlan_mode) {
		eth_vlan_hdr = (struct vlan_ethhdr *)add_hdr->hdr;
		memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
		memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
		eth_vlan_hdr->h_vlan_encapsulated_proto =
			htons(eth_type);
		eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
		add_hdr->hdr_len = VLAN_ETH_HLEN;
		add_hdr->type = IPA_HDR_L2_802_1Q;
	} else {
		eth_hdr = (struct ethhdr *)add_hdr->hdr;
		memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
		memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
		eth_hdr->h_proto = htons(eth_type);
		add_hdr->hdr_len = ETH_HLEN;
		add_hdr->type = IPA_HDR_L2_ETHERNET_II;
	}
	ECM_IPA_LOG_EXIT();
}

/**
 * ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
 *				Headers will be committed to HW
@@ -859,8 +910,6 @@ static int ecm_ipa_rules_cfg
	struct ipa_ioc_add_hdr *hdrs;
	struct ipa_hdr_add *ipv4_hdr;
	struct ipa_hdr_add *ipv6_hdr;
	struct ethhdr *eth_ipv4;
	struct ethhdr *eth_ipv6;
	int result = 0;

	ECM_IPA_LOG_ENTRY();
@@ -871,28 +920,17 @@ static int ecm_ipa_rules_cfg
		result = -ENOMEM;
		goto out;
	}

	ipv4_hdr = &hdrs->hdr[0];
	eth_ipv4 = (struct ethhdr *)ipv4_hdr->hdr;
	ecm_ipa_prepare_header_insertion(
		ETH_P_IP, ECM_IPA_IPV4_HDR_NAME,
		ipv4_hdr, dst_mac, src_mac, ecm_ipa_ctx->is_vlan_mode);

	ipv6_hdr = &hdrs->hdr[1];
	eth_ipv6 = (struct ethhdr *)ipv6_hdr->hdr;
	strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
	memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
	memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
	eth_ipv4->h_proto = htons(ETH_P_IP);
	ipv4_hdr->hdr_len = ETH_HLEN;
	ipv4_hdr->is_partial = 0;
	ipv4_hdr->is_eth2_ofst_valid = true;
	ipv4_hdr->eth2_ofst = 0;
	ipv4_hdr->type = IPA_HDR_L2_ETHERNET_II;
	strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
	memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
	memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
	eth_ipv6->h_proto = htons(ETH_P_IPV6);
	ipv6_hdr->hdr_len = ETH_HLEN;
	ipv6_hdr->is_partial = 0;
	ipv6_hdr->is_eth2_ofst_valid = true;
	ipv6_hdr->eth2_ofst = 0;
	ipv6_hdr->type = IPA_HDR_L2_ETHERNET_II;
	ecm_ipa_prepare_header_insertion(
		ETH_P_IPV6, ECM_IPA_IPV6_HDR_NAME,
		ipv6_hdr, dst_mac, src_mac, ecm_ipa_ctx->is_vlan_mode);

	hdrs->commit = 1;
	hdrs->num_hdrs = 2;
	result = ipa_add_hdr(hdrs);
@@ -972,10 +1010,14 @@ static int ecm_ipa_register_properties(struct ecm_ipa_dev *ecm_ipa_ctx)
	struct ipa_rx_intf rx_properties = {0};
	struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
	struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
	enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	int result = 0;

	ECM_IPA_LOG_ENTRY();

	if (ecm_ipa_ctx->is_vlan_mode)
		hdr_l2_type = IPA_HDR_L2_802_1Q;

	tx_properties.prop = properties;
	ipv4_property = &tx_properties.prop[0];
	ipv4_property->ip = IPA_IP_v4;
@@ -983,11 +1025,11 @@ static int ecm_ipa_register_properties(struct ecm_ipa_dev *ecm_ipa_ctx)
	strlcpy
		(ipv4_property->hdr_name, ECM_IPA_IPV4_HDR_NAME,
		IPA_RESOURCE_NAME_MAX);
	ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	ipv4_property->hdr_l2_type = hdr_l2_type;
	ipv6_property = &tx_properties.prop[1];
	ipv6_property->ip = IPA_IP_v6;
	ipv6_property->dst_pipe = ecm_ipa_ctx->ipa_to_usb_client;
	ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	ipv6_property->hdr_l2_type = hdr_l2_type;
	strlcpy
		(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
		IPA_RESOURCE_NAME_MAX);
@@ -998,12 +1040,12 @@ static int ecm_ipa_register_properties(struct ecm_ipa_dev *ecm_ipa_ctx)
	rx_ipv4_property->ip = IPA_IP_v4;
	rx_ipv4_property->attrib.attrib_mask = 0;
	rx_ipv4_property->src_pipe = ecm_ipa_ctx->usb_to_ipa_client;
	rx_ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	rx_ipv4_property->hdr_l2_type = hdr_l2_type;
	rx_ipv6_property = &rx_properties.prop[1];
	rx_ipv6_property->ip = IPA_IP_v6;
	rx_ipv6_property->attrib.attrib_mask = 0;
	rx_ipv6_property->src_pipe = ecm_ipa_ctx->usb_to_ipa_client;
	rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	rx_ipv6_property->hdr_l2_type = hdr_l2_type;
	rx_properties.num_props = 2;

	result = ipa_register_intf("ecm0", &tx_properties, &rx_properties);
@@ -1336,6 +1378,13 @@ static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
		goto fail_file;
	}

	file = debugfs_create_bool("is_vlan_mode", flags_read_only,
		ecm_ipa_ctx->directory, &ecm_ipa_ctx->is_vlan_mode);
	if (!file) {
		ECM_IPA_ERROR("could not create is_vlan_mode file\n");
		goto fail_file;
	}

	ECM_IPA_DEBUG("debugfs entries were created\n");
	ECM_IPA_LOG_EXIT();

@@ -1362,8 +1411,9 @@ static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx) {}
/**
 * ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
 *
 *usb_to_ipa_hdl: handle received from ipa_connect
 *ipa_to_usb_hdl: handle received from ipa_connect
 * @usb_to_ipa_hdl: handle received from ipa_connect
 * @ipa_to_usb_hdl: handle received from ipa_connect
 * @is_vlan_mode - should driver work in vlan mode?
 *
 * USB to IPA pipe:
 *  - No de-aggregation
@@ -1374,16 +1424,21 @@ static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx) {}
 *  - No aggregation
 *  - Add Ethernet header
 */
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
	bool is_vlan_mode)
{
	int result = 0;
	struct ipa_ep_cfg usb_to_ipa_ep_cfg;
	struct ipa_ep_cfg ipa_to_usb_ep_cfg;
	uint8_t hdr_add = 0;


	ECM_IPA_LOG_ENTRY();
	if (is_vlan_mode)
		hdr_add = VLAN_HLEN;
	memset(&usb_to_ipa_ep_cfg, 0, sizeof(struct ipa_ep_cfg));
	usb_to_ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
	usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
	usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN + hdr_add;
	usb_to_ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT;
	usb_to_ipa_ep_cfg.route.rt_tbl_hdl = 0;
	usb_to_ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
@@ -1395,7 +1450,7 @@ static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
	}
	memset(&ipa_to_usb_ep_cfg, 0, sizeof(struct ipa_ep_cfg));
	ipa_to_usb_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
	ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN;
	ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN + hdr_add;
	ipa_to_usb_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
	result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
	if (result) {
+91 −24
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/debugfs.h>
#include <linux/in.h>
#include <linux/stddef.h>
@@ -162,6 +163,7 @@ enum rndis_ipa_operation {
 * @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
 * @state_lock: used to protect the state variable.
 * @pm_hdl: handle for IPA PM framework
 * @is_vlan_mode: should driver work in vlan mode?
 */
struct rndis_ipa_dev {
	struct net_device *net;
@@ -191,6 +193,7 @@ struct rndis_ipa_dev {
	struct delayed_work xmit_error_delayed_work;
	spinlock_t state_lock; /* Spinlock for the state variable.*/
	u32 pm_hdl;
	bool is_vlan_mode;
};

/**
@@ -217,19 +220,20 @@ static void rndis_ipa_tx_complete_notify
static void rndis_ipa_tx_timeout(struct net_device *net);
static int rndis_ipa_stop(struct net_device *net);
static void rndis_ipa_enable_data_path(struct rndis_ipa_dev *rndis_ipa_ctx);
static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb);
static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
	struct rndis_ipa_dev *rndis_ipa_ctx);
static void rndis_ipa_xmit_error(struct sk_buff *skb);
static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work);
static void rndis_ipa_prepare_header_insertion
	(int eth_type,
	const char *hdr_name, struct ipa_hdr_add *add_hdr,
	const void *dst_mac, const void *src_mac);
	const void *dst_mac, const void *src_mac, bool is_vlan_mode);
static int rndis_ipa_hdrs_cfg
	(struct rndis_ipa_dev *rndis_ipa_ctx,
	const void *dst_mac, const void *src_mac);
static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net);
static int rndis_ipa_register_properties(char *netdev_name);
static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode);
static int rndis_ipa_deregister_properties(char *netdev_name);
static void rndis_ipa_rm_notify
	(void *user_data, enum ipa_rm_event event,
@@ -262,7 +266,8 @@ static int rndis_ipa_ep_registers_cfg
	(u32 usb_to_ipa_hdl,
	u32 ipa_to_usb_hdl, u32 max_xfer_size_bytes_to_dev,
	u32 max_xfer_size_bytes_to_host, u32 mtu,
	bool deaggr_enable);
	bool deaggr_enable,
	bool is_vlan_mode);
static int rndis_ipa_set_device_ethernet_addr
	(u8 *dev_ethaddr,
	u8 device_ethaddr[]);
@@ -566,6 +571,14 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
	}
	RNDIS_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);

	if (ipa_is_vlan_mode(IPA_VLAN_IF_RNDIS,
		&rndis_ipa_ctx->is_vlan_mode)) {
		RNDIS_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
		goto fail_get_vlan_mode;
	}

	RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);

	result = rndis_ipa_hdrs_cfg
			(rndis_ipa_ctx,
			params->host_ethaddr,
@@ -576,7 +589,8 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
	}
	RNDIS_IPA_DEBUG("IPA header-insertion configed for Ethernet+RNDIS\n");

	result = rndis_ipa_register_properties(net->name);
	result = rndis_ipa_register_properties(net->name,
		rndis_ipa_ctx->is_vlan_mode);
	if (result) {
		RNDIS_IPA_ERROR("fail on properties set\n");
		goto fail_register_tx;
@@ -612,8 +626,9 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
	rndis_ipa_deregister_properties(net->name);
fail_register_tx:
	rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
fail_set_device_ethernet:
fail_hdrs_cfg:
fail_get_vlan_mode:
fail_set_device_ethernet:
	rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
fail_netdev_priv:
	free_netdev(net);
@@ -728,7 +743,8 @@ int rndis_ipa_pipe_connect_notify(
		max_xfer_size_bytes_to_dev,
		max_xfer_size_bytes_to_host,
		rndis_ipa_ctx->net->mtu,
		rndis_ipa_ctx->deaggregation_enable);
		rndis_ipa_ctx->deaggregation_enable,
		rndis_ipa_ctx->is_vlan_mode);
	if (result) {
		RNDIS_IPA_ERROR("fail on ep cfg\n");
		goto fail;
@@ -910,7 +926,7 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
		goto out;
	}

	skb = rndis_encapsulate_skb(skb);
	skb = rndis_encapsulate_skb(skb, rndis_ipa_ctx);
	trace_rndis_tx_dp(skb->protocol);
	ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
	if (ret) {
@@ -1456,6 +1472,7 @@ static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work)
 *  for IPA->USB pipe
 * src_mac: device MAC (Ethernet) address to be added to packets
 *  for IPA->USB pipe
 * is_vlan_mode: should driver work in vlan mode?
 *
 * This function shall build the header-insertion block request for a
 * single Ethernet+RNDIS header)
@@ -1468,24 +1485,38 @@ static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work)
static void rndis_ipa_prepare_header_insertion(
	int eth_type,
	const char *hdr_name, struct ipa_hdr_add *add_hdr,
	const void *dst_mac, const void *src_mac)
	const void *dst_mac, const void *src_mac, bool is_vlan_mode)
{
	struct ethhdr *eth_hdr;
	struct vlan_ethhdr *eth_vlan_hdr;

	add_hdr->hdr_len = sizeof(rndis_template_hdr);
	add_hdr->is_partial = false;
	strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);

	memcpy(add_hdr->hdr, &rndis_template_hdr, sizeof(rndis_template_hdr));
	eth_hdr = (struct ethhdr *)(add_hdr->hdr + sizeof(rndis_template_hdr));
	add_hdr->is_eth2_ofst_valid = true;
	add_hdr->eth2_ofst = sizeof(rndis_template_hdr);

	if (is_vlan_mode) {
		eth_vlan_hdr = (struct vlan_ethhdr *)(add_hdr->hdr +
			sizeof(rndis_template_hdr));
		memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
		memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
		eth_vlan_hdr->h_vlan_encapsulated_proto = htons(eth_type);
		eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
		add_hdr->hdr_len += VLAN_ETH_HLEN;
		add_hdr->type = IPA_HDR_L2_802_1Q;
	} else {
		eth_hdr = (struct ethhdr *)(add_hdr->hdr +
			sizeof(rndis_template_hdr));
		memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
		memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
		eth_hdr->h_proto = htons(eth_type);
		add_hdr->hdr_len += ETH_HLEN;
	add_hdr->is_eth2_ofst_valid = true;
	add_hdr->eth2_ofst = sizeof(rndis_template_hdr);
		add_hdr->type = IPA_HDR_L2_ETHERNET_II;
	}
}

/**
 * rndis_ipa_hdrs_cfg() - configure header insertion block in IPA core
@@ -1526,10 +1557,10 @@ static int rndis_ipa_hdrs_cfg(
	ipv6_hdr = &hdrs->hdr[1];
	rndis_ipa_prepare_header_insertion
		(ETH_P_IP, IPV4_HDR_NAME,
		ipv4_hdr, dst_mac, src_mac);
		ipv4_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
	rndis_ipa_prepare_header_insertion
		(ETH_P_IPV6, IPV6_HDR_NAME,
		ipv6_hdr, dst_mac, src_mac);
		ipv6_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);

	hdrs->commit = 1;
	hdrs->num_hdrs = 2;
@@ -1610,6 +1641,7 @@ static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net)
 * rndis_ipa_register_properties() - set Tx/Rx properties needed
 *  by IPA configuration manager
 * @netdev_name: a string with the name of the network interface device
 * @is_vlan_mode: should driver work in vlan mode?
 *
 * Register Tx/Rx properties to allow user space configuration (IPA
 * Configuration Manager):
@@ -1628,7 +1660,7 @@ static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net)
 *   This rules shall be added based on the attribute mask supplied at
 *   this function, that is, always hit rule.
 */
static int rndis_ipa_register_properties(char *netdev_name)
static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode)
{
	struct ipa_tx_intf tx_properties = {0};
	struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
@@ -1638,10 +1670,14 @@ static int rndis_ipa_register_properties(char *netdev_name)
	struct ipa_rx_intf rx_properties = {0};
	struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
	struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
	enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	int result = 0;

	RNDIS_IPA_LOG_ENTRY();

	if (is_vlan_mode)
		hdr_l2_type = IPA_HDR_L2_802_1Q;

	tx_properties.prop = properties;
	ipv4_property = &tx_properties.prop[0];
	ipv4_property->ip = IPA_IP_v4;
@@ -1649,14 +1685,14 @@ static int rndis_ipa_register_properties(char *netdev_name)
	strlcpy
		(ipv4_property->hdr_name, IPV4_HDR_NAME,
		IPA_RESOURCE_NAME_MAX);
	ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	ipv4_property->hdr_l2_type = hdr_l2_type;
	ipv6_property = &tx_properties.prop[1];
	ipv6_property->ip = IPA_IP_v6;
	ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
	strlcpy
		(ipv6_property->hdr_name, IPV6_HDR_NAME,
		IPA_RESOURCE_NAME_MAX);
	ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	ipv6_property->hdr_l2_type = hdr_l2_type;
	tx_properties.num_props = 2;

	rx_properties.prop = rx_ioc_properties;
@@ -1664,12 +1700,12 @@ static int rndis_ipa_register_properties(char *netdev_name)
	rx_ipv4_property->ip = IPA_IP_v4;
	rx_ipv4_property->attrib.attrib_mask = 0;
	rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
	rx_ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	rx_ipv4_property->hdr_l2_type = hdr_l2_type;
	rx_ipv6_property = &rx_properties.prop[1];
	rx_ipv6_property->ip = IPA_IP_v6;
	rx_ipv6_property->attrib.attrib_mask = 0;
	rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
	rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
	rx_ipv6_property->hdr_l2_type = hdr_l2_type;
	rx_properties.num_props = 2;

	result = ipa_register_intf("rndis0", &tx_properties, &rx_properties);
@@ -1948,12 +1984,14 @@ static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
 * rndis_encapsulate_skb() - encapsulate the given Ethernet skb with
 *  an RNDIS header
 * @skb: packet to be encapsulated with the RNDIS header
 * @rndis_ipa_ctx: main driver context
 *
 * Shall use a template header for RNDIS and update it with the given
 * skb values.
 * Ethernet is expected to be already encapsulate the packet.
 */
static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb)
static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
	struct rndis_ipa_dev *rndis_ipa_ctx)
{
	struct rndis_pkt_hdr *rndis_hdr;
	int payload_byte_len = skb->len;
@@ -1971,6 +2009,10 @@ static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb)
		skb = new_skb;
	}

	if (rndis_ipa_ctx->is_vlan_mode)
		if (unlikely(skb->protocol != ETH_P_8021Q))
			RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");

	/* make room at the head of the SKB to put the RNDIS header */
	rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
					sizeof(rndis_template_hdr));
@@ -2046,6 +2088,8 @@ static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
 * @max_xfer_size_bytes_to_host: the maximum size, in bytes, that the host
 *  expects to receive from the device. supplied on REMOTE_NDIS_INITIALIZE_MSG.
 * @mtu: the netdev MTU size, in bytes
 * @deaggr_enable: should deaggregation be enabled?
 * @is_vlan_mode: should driver work in vlan mode?
 *
 * USB to IPA pipe:
 *  - de-aggregation
@@ -2064,7 +2108,8 @@ static int rndis_ipa_ep_registers_cfg(
	u32 max_xfer_size_bytes_to_dev,
	u32 max_xfer_size_bytes_to_host,
	u32 mtu,
	bool deaggr_enable)
	bool deaggr_enable,
	bool is_vlan_mode)
{
	int result;
	struct ipa_ep_cfg *usb_to_ipa_ep_cfg;
@@ -2077,6 +2122,20 @@ static int rndis_ipa_ep_registers_cfg(
		RNDIS_IPA_DEBUG("deaggregation disabled\n");
	}

	if (is_vlan_mode) {
		usb_to_ipa_ep_cfg->hdr.hdr_len =
			VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
		ipa_to_usb_ep_cfg.hdr.hdr_len =
			VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
		ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = VLAN_ETH_HLEN;
	} else {
		usb_to_ipa_ep_cfg->hdr.hdr_len =
			ETH_HLEN + sizeof(struct rndis_pkt_hdr);
		ipa_to_usb_ep_cfg.hdr.hdr_len =
			ETH_HLEN + sizeof(struct rndis_pkt_hdr);
		ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = ETH_HLEN;
	}

	usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_xfer_size_bytes_to_dev;
	result = ipa_cfg_ep(usb_to_ipa_hdl, usb_to_ipa_ep_cfg);
	if (result) {
@@ -2452,6 +2511,14 @@ static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
		goto fail_file;
	}

	file = debugfs_create_bool("is_vlan_mode", flags_read_only,
		rndis_ipa_ctx->directory,
		&rndis_ipa_ctx->is_vlan_mode);
	if (!file) {
		RNDIS_IPA_ERROR("fail to create is_vlan_mode file\n");
		goto fail_file;
	}

	RNDIS_IPA_DEBUG("debugfs entries were created\n");
	RNDIS_IPA_LOG_EXIT();

+29 −4
Original line number Diff line number Diff line
@@ -4638,7 +4638,7 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
{
	unsigned long missing;

	char dbg_buff[16] = { 0 };
	char dbg_buff[32] = { 0 };

	if (sizeof(dbg_buff) < count + 1)
		return -EFAULT;
@@ -4653,19 +4653,44 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
	if (count > 0)
		dbg_buff[count - 1] = '\0';

	IPADBG("user input string %s\n", dbg_buff);

	/* Prevent consequent calls from trying to load the FW again. */
	if (ipa3_is_ready())
		return count;

	/* Check MHI configuration on MDM devices */
	if (!ipa3_is_msm_device()) {

		if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
			if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
				ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
				true;
			if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
				ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
				true;
			if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
				ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
				true;

			/*
			 * when vlan mode is passed to our dev we expect
			 * another write
			 */
			return count;
		}

		if (!strcasecmp(dbg_buff, "MHI")) {
			ipa3_ctx->ipa_config_is_mhi = true;
			pr_info(
				"IPA is loading with MHI configuration\n");
		} else {
		} else if (!strcmp(dbg_buff, "1\n")) {
			pr_info(
				"IPA is loading with non MHI configuration\n");
		} else {
			IPAERR("got invalid string %s not loading FW\n",
				dbg_buff);
			return count;
		}
	}

Loading