Loading drivers/platform/msm/ipa/ipa_api.c +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/platform/msm/ipa/ipa_api.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +89 −34 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +91 −24 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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; }; /** Loading @@ -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, Loading Loading @@ -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[]); Loading Loading @@ -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, Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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): Loading @@ -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} }; Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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)); Loading Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +29 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading
drivers/platform/msm/ipa/ipa_api.c +20 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/platform/msm/ipa/ipa_api.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +89 −34 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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; Loading @@ -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); Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading
drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +91 −24 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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; }; /** Loading @@ -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, Loading Loading @@ -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[]); Loading Loading @@ -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, Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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): Loading @@ -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} }; Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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)); Loading Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +29 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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