diff --git a/driver/quectel_QMI_WWAN/Makefile b/driver/quectel_QMI_WWAN/Makefile index b27dfad..4238c1b 100644 --- a/driver/quectel_QMI_WWAN/Makefile +++ b/driver/quectel_QMI_WWAN/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qmi_wwan_q -PKG_VERSION:=3.0 -PKG_RELEASE:=2 +PKG_VERSION:=1.2.9 +PKG_RELEASE:=1 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk diff --git a/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c b/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c index 6a1dd08..74d8946 100644 --- a/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c +++ b/driver/quectel_QMI_WWAN/src/qmi_wwan_q.c @@ -1,13 +1,16 @@ /* - * Copyright (c) 2012 Bjørn Mork - * - * The probing code is heavily inspired by cdc_ether, which is: - * Copyright (C) 2003-2005 by David Brownell - * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. + Copyright (c) Bjørn Mork of author + + This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General + Public licenseas published byFree Software Foundation; either version 2theof the License,(at your option) + any later version.O1 + This program isdistributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the + implied warranty ofOr FITNESS FOR A PARTICULAR PURPOSE.MERCHANTABILITYSee theGNU General Public License + for more details. + You should have received a copy of the GNU General Public licensealong withthis program; if not, write to + the Free SoftwareFoundation, Inc.r51 Franklin Street, Fifth Floor,Boston,MA 02110-1301,USA. + + Based on version modification, the author is Quectel */ #include @@ -62,8 +65,10 @@ static struct rmnet_nss_cb __read_mostly *nss_cb = NULL; #if defined(CONFIG_PINCTRL_IPQ807x) || defined(CONFIG_PINCTRL_IPQ5018) #ifdef CONFIG_RMNET_DATA #define CONFIG_QCA_NSS_DRV -/* define at qsdk/qca/src/linux-4.4/net/rmnet_data/rmnet_data_main.c */ +/* define at qsdk/qca/src/linux-4.4/net/rmnet_data/rmnet_data_main.c */ //for spf11.x +/* define at qsdk/qca/src/datarmnet/core/rmnet_config.c */ //for spf12.x /* set at qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c */ +/* need add DEPENDS:= kmod-rmnet-core in feeds/makefile */ extern struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; #endif #endif @@ -91,7 +96,7 @@ extern struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; * These devices may alternatively/additionally be configured using AT * commands on a serial interface */ -#define VERSION_NUMBER "V1.2.2" +#define VERSION_NUMBER "V1.2.9" #define QUECTEL_WWAN_VERSION "Quectel_Linux&Android_QMI_WWAN_Driver_"VERSION_NUMBER static const char driver_name[] = "qmi_wwan_q"; @@ -115,6 +120,7 @@ static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; 1 - QMAP (Aggregation protocol) X - QMAP (Multiplexing and Aggregation protocol) */ +//#define CONFIG_CLEAR_HALT #define QUECTEL_WWAN_QMAP 4 //MAX is 7 #if defined(QUECTEL_WWAN_QMAP) @@ -216,7 +222,7 @@ struct qmap_priv { struct timespec64 agg_time; struct hrtimer agg_hrtimer; struct work_struct agg_wq; - + #ifdef QUECTEL_BRIDGE_MODE uint bridge_mode; uint bridge_ipv4; @@ -225,7 +231,7 @@ struct qmap_priv { unsigned char bridge_self_mac[ETH_ALEN]; #endif #endif - uint use_qca_nss; + uint use_qca_nss; }; struct qmap_hdr { @@ -319,10 +325,10 @@ static int bridge_arp_reply(struct net_device *net, struct sk_buff *skb, uint br reply->ip_summed = CHECKSUM_UNNECESSARY; reply->pkt_type = PACKET_HOST; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) - netif_rx_ni(reply); -#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 5,18,0 )) netif_rx(reply); +#else + netif_rx_ni(reply); #endif } return 1; @@ -357,14 +363,14 @@ static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_bu bridge_mac[0], bridge_mac[1], bridge_mac[2], bridge_mac[3], bridge_mac[4], bridge_mac[5]); } } - + #ifdef CONFIG_BRIDGE_LAN //bridge Lan IP 192.168.0.0 if (ehdr->h_proto == htons(ETH_P_IP) && (iph->daddr & 0xFFFF) == 0xA8C0) { struct sk_buff *reply = skb_copy(skb, GFP_ATOMIC); ehdr = eth_hdr(reply); - + memcpy(ehdr->h_source, default_modem_addr, ETH_ALEN); if(is_qmap_netdev(net)) { @@ -378,20 +384,16 @@ static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_bu sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; memcpy(ehdr->h_dest, pQmapDev->bridge_self_mac, ETH_ALEN); } - + //pr_info("%s br rx pkt addr: %02x:%02x:%02x:%02x:%02x:%02x -> %02x:%02x:%02x:%02x:%02x:%02x\n", netdev_name(net), // ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[5], // ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[5]); - + skb_reset_mac_header(reply); __skb_pull(reply, skb_network_offset(reply)); reply->ip_summed = CHECKSUM_UNNECESSARY; reply->pkt_type = PACKET_HOST; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) netif_rx_ni(reply); -#else - netif_rx(reply); -#endif return NULL; } #endif @@ -407,7 +409,7 @@ static void bridge_mode_rx_fixup(sQmiWwanQmap *pQmapDev, struct net_device *net, uint bridge_mode = 0; unsigned char *bridge_mac; - if (pQmapDev->qmap_mode > 1 || pQmapDev->use_rmnet_usb == 1) { + if (pQmapDev->qmap_mode > 1 || ((pQmapDev->use_rmnet_usb == 1) && !one_card_mode)) { struct qmap_priv *priv = netdev_priv(net); bridge_mode = priv->bridge_mode; bridge_mac = priv->bridge_mac; @@ -510,7 +512,7 @@ static ssize_t link_state_store(struct device *dev, struct device_attribute *att } } - if (usbnetdev->net->flags & IFF_UP) { + if (usbnetdev->net->flags & IFF_UP) { if (!pQmapDev->link_state) { netif_carrier_off(usbnetdev->net); } @@ -683,7 +685,7 @@ static void qmap_wake_queue(sQmiWwanQmap *pQmapDev) if (!pQmapDev || !pQmapDev->use_rmnet_usb) return; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; @@ -693,7 +695,7 @@ static void qmap_wake_queue(sQmiWwanQmap *pQmapDev) } } -static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id) { +static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id, int *hdr_data, int ip_offset) { struct qmap_hdr *qhdr; int pad = 0; @@ -701,44 +703,55 @@ static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id) { if (pad) { pad = 4 - pad; if (skb_tailroom(skb) < pad) { - printk("skb_tailroom small!\n"); + //printk("skb_tailroom small!\n"); pad = 0; } if (pad) __skb_put(skb, pad); } - - qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr)); + + if (hdr_data) { + qhdr = (struct qmap_hdr *)hdr_data; + qhdr->pkt_len = cpu_to_be16(skb->len - ip_offset); + } + else { + qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr)); + qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr)); + } qhdr->cd_rsvd_pad = pad; qhdr->mux_id = mux_id; - qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr)); return skb; } -static struct sk_buff * add_qhdr_v5(struct sk_buff *skb, u8 mux_id) { +static struct sk_buff * add_qhdr_v5(struct sk_buff *skb, u8 mux_id, int *hdr_data, int ip_offset) { struct rmnet_map_header *map_header; struct rmnet_map_v5_csum_header *ul_header; - u32 padding, map_datalen; + int pad = 0; - map_datalen = skb->len; - padding = map_datalen%4; - if (padding) { - padding = 4 - padding; - if (skb_tailroom(skb) < padding) { - printk("skb_tailroom small!\n"); - padding = 0; + pad = (skb->len - ip_offset) %4; + if (pad) { + pad = 4 - pad; + if (skb_tailroom(skb) < pad) { + //printk("skb_tailroom small!\n"); + pad = 0; } - if (padding) - __skb_put(skb, padding); + if (pad) + __skb_put(skb, pad); + } + + if (hdr_data) { + map_header = (struct rmnet_map_header *)hdr_data; + map_header->pkt_len = htons(skb->len - ip_offset); + } + else { + map_header = (struct rmnet_map_header *)skb_push(skb, (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); + map_header->pkt_len = htons(skb->len - (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); } - - map_header = (struct rmnet_map_header *)skb_push(skb, (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); map_header->cd_bit = 0; map_header->next_hdr = 1; - map_header->pad_len = padding; + map_header->pad_len = pad; map_header->mux_id = mux_id; - map_header->pkt_len = htons(map_datalen + padding); ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); memset(ul_header, 0, sizeof(*ul_header)); @@ -761,48 +774,38 @@ static void rmnet_vnd_update_rx_stats(struct net_device *net, struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); u64_stats_update_begin(&stats64->syncp); -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,0,0 )) stats64->rx_packets += rx_packets; stats64->rx_bytes += rx_bytes; #else - u64_stats_add(&stats64->rx_packets, rx_packets); - u64_stats_add(&stats64->rx_bytes, rx_bytes); + u64_stats_add(&stats64->rx_packets, rx_packets); + u64_stats_add(&stats64->rx_bytes, rx_bytes); #endif u64_stats_update_end(&stats64->syncp); #else -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) net->stats.rx_packets += rx_packets; net->stats.rx_bytes += rx_bytes; -#else - u64_stats_add(&net->stats.rx_packets, rx_packets); - u64_stats_add(&net->stats.rx_bytes, rx_bytes); -#endif #endif } static void rmnet_vnd_update_tx_stats(struct net_device *net, - unsigned tx_packets, unsigned tx_bytes) { + unsigned tx_packets, unsigned tx_bytes) { #if defined(MHI_NETDEV_STATUS64) struct qmap_priv *dev = netdev_priv(net); struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); u64_stats_update_begin(&stats64->syncp); -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,0,0 )) stats64->tx_packets += tx_packets; stats64->tx_bytes += tx_bytes; #else - u64_stats_add(&stats64->tx_packets, tx_packets); - u64_stats_add(&stats64->tx_bytes, tx_bytes); + u64_stats_add(&stats64->tx_packets, tx_packets); + u64_stats_add(&stats64->tx_bytes, tx_bytes); #endif u64_stats_update_end(&stats64->syncp); #else -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) net->stats.tx_packets += tx_packets; net->stats.tx_bytes += tx_bytes; -#else - u64_stats_add(&net->stats.tx_packets, tx_packets); - u64_stats_add(&net->tx_bytes, tx_bytes); -#endif #endif } @@ -822,6 +825,7 @@ static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, for_each_possible_cpu(cpu) { struct pcpu_sw_netstats *stats64; +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 6,1,0 )) u64 rx_packets, rx_bytes; u64 tx_packets, tx_bytes; @@ -829,25 +833,35 @@ static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, do { start = u64_stats_fetch_begin_irq(&stats64->syncp); -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) rx_packets = stats64->rx_packets; rx_bytes = stats64->rx_bytes; tx_packets = stats64->tx_packets; tx_bytes = stats64->tx_bytes; -#else - rx_packets = u64_stats_read(&stats64->rx_packets); - rx_bytes = u64_stats_read(&stats64->rx_bytes); - tx_packets = u64_stats_read(&stats64->tx_packets); - tx_bytes = u64_stats_read(&stats64->tx_bytes); -#endif } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); - stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; stats->tx_packets += tx_packets; stats->tx_bytes += tx_bytes; +#else + u64_stats_t rx_packets, rx_bytes; + u64_stats_t tx_packets, tx_bytes; + stats64 = per_cpu_ptr(dev->stats64, cpu); + + do { + start = u64_stats_fetch_begin_irq(&stats64->syncp); + rx_packets = stats64->rx_packets; + rx_bytes = stats64->rx_bytes; + tx_packets = stats64->tx_packets; + tx_bytes = stats64->tx_bytes; + } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); + + stats->rx_packets += u64_stats_read(&rx_packets); + stats->rx_bytes += u64_stats_read(&rx_bytes); + stats->tx_packets += u64_stats_read(&tx_packets); + stats->tx_bytes += u64_stats_read(&tx_bytes); +#endif } return stats; @@ -897,7 +911,7 @@ static void rmnet_usb_tx_skb_destructor(struct sk_buff *skb) { if (pQmapDev && pQmapDev->use_rmnet_usb) { int i; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; @@ -967,7 +981,7 @@ static void rmnet_usb_tx_agg_work(struct work_struct *work) ktime_get_ts64(&priv->agg_time); } spin_unlock_irqrestore(&priv->agg_lock, flags); - + if (skb) { int err; #if 0 @@ -998,7 +1012,7 @@ static long agg_bypass_time __read_mostly = 10000000L; module_param(agg_bypass_time, long, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(agg_bypass_time, "Skip agg when apart spaced more than this"); -static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv) { +static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv, int *hdr_data, int hdr_len, int ip_offset) { struct qmi_wwan_state *info = (void *)&priv->dev->data; sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; struct tx_agg_ctx *ctx = &pQmapDev->tx_ctx; @@ -1021,15 +1035,22 @@ static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv) { rmnet_vnd_update_tx_stats(pNet, 1, skb->len); if (ctx->ul_data_aggregation_max_datagrams == 1) { - skb->protocol = htons(ETH_P_MAP); - skb->dev = priv->real_dev; + agg_skb = alloc_skb(skb->len + hdr_len, GFP_ATOMIC); + if (agg_skb) { + memcpy(skb_put(agg_skb, hdr_len), hdr_data, hdr_len); + memcpy(skb_put(agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); + agg_skb->protocol = htons(ETH_P_MAP); + agg_skb->dev = priv->real_dev; #if 0 - if (!skb->destructor) - skb->destructor = rmnet_usb_tx_skb_destructor; + if (!agg_skb->destructor) + agg_skb->destructor = rmnet_usb_tx_skb_destructor; #endif - err = dev_queue_xmit(skb); - if (err != NET_XMIT_SUCCESS) + err = dev_queue_xmit(agg_skb); + if (err != NET_XMIT_SUCCESS) pNet->stats.tx_errors++; + } + dev_kfree_skb_any(skb); + skb = NULL; return NET_XMIT_SUCCESS; } @@ -1041,8 +1062,9 @@ new_packet: diff = timespec64_sub(now, priv->agg_time); if (priv->agg_skb) { - if ((priv->agg_skb->len + skb->len) < ctx->ul_data_aggregation_max_size) { - memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); + if ((priv->agg_skb->len + skb->len + hdr_len) < ctx->ul_data_aggregation_max_size) { + memcpy(skb_put(priv->agg_skb, hdr_len), hdr_data, hdr_len); + memcpy(skb_put(priv->agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); priv->agg_count++; if (diff.tv_sec > 0 || diff.tv_nsec > agg_time_limit) { @@ -1052,14 +1074,14 @@ new_packet: ready2send = 1; } else if (xmit_more == 0) { - struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; + struct rmnet_map_header *map_header = (struct rmnet_map_header *)hdr_data; size_t offset = sizeof(struct rmnet_map_header); if (map_header->next_hdr) offset += sizeof(struct rmnet_map_v5_csum_header); ready2send = rmnet_usb_tx_agg_skip(skb, offset); } - + dev_kfree_skb_any(skb); skb = NULL; } @@ -1078,7 +1100,7 @@ new_packet: ready2send = 1; } else if (xmit_more == 0) { - struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; + struct rmnet_map_header *map_header = (struct rmnet_map_header *)hdr_data; size_t offset = sizeof(struct rmnet_map_header); if (map_header->next_hdr) offset += sizeof(struct rmnet_map_v5_csum_header); @@ -1090,7 +1112,8 @@ new_packet: priv->agg_skb = alloc_skb(ctx->ul_data_aggregation_max_size, GFP_ATOMIC); if (priv->agg_skb) { skb_reset_network_header(priv->agg_skb); //protocol da1a is buggy, dev wwan0 - memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); + memcpy(skb_put(priv->agg_skb, hdr_len), hdr_data, hdr_len); + memcpy(skb_put(priv->agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); priv->agg_count++; dev_kfree_skb_any(skb); skb = NULL; @@ -1101,7 +1124,12 @@ new_packet: } if (ready2send) { - agg_skb = skb; + agg_skb = alloc_skb(skb->len + hdr_len, GFP_ATOMIC); + if (agg_skb) { + memcpy(skb_put(agg_skb, hdr_len), hdr_data, hdr_len); + memcpy(skb_put(agg_skb, skb->len - ip_offset), skb->data + ip_offset, skb->len - ip_offset); + } + dev_kfree_skb_any(skb); skb = NULL; } } @@ -1142,6 +1170,9 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, { int err; struct qmap_priv *priv = netdev_priv(pNet); + int qmap_hdr[2]; + int hdr_len = 0; + int ip_offset = 0; if (netif_queue_stopped(priv->real_dev)) { netif_stop_queue(pNet); @@ -1159,18 +1190,24 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, } #endif +#if 1 + ip_offset = ETH_HLEN; +#else if (skb_pull(skb, ETH_HLEN) == NULL) { dev_kfree_skb_any (skb); return NETDEV_TX_OK; } +#endif } //printk("%s 2 skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); if (priv->qmap_version == 5) { - add_qhdr(skb, priv->mux_id); + add_qhdr(skb, priv->mux_id, qmap_hdr, ip_offset); + hdr_len = 4; } else if (priv->qmap_version == 9) { - add_qhdr_v5(skb, priv->mux_id); + add_qhdr_v5(skb, priv->mux_id, qmap_hdr, ip_offset); + hdr_len = 8; } else { dev_kfree_skb_any (skb); @@ -1178,7 +1215,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, } //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); - err = rmnet_usb_tx_agg(skb, priv); + err = rmnet_usb_tx_agg(skb, priv, qmap_hdr, hdr_len, ip_offset); return err; } @@ -1246,7 +1283,7 @@ static rx_handler_result_t qca_nss_rx_handler(struct sk_buff **pskb) if (!skb) return RX_HANDLER_CONSUMED; - + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); if (skb->pkt_type == PACKET_LOOPBACK) @@ -1295,10 +1332,10 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) priv->dev = pDev->mpNetDev; priv->qmap_version = pDev->qmap_version; priv->mux_id = QUECTEL_QMAP_MUX_ID + offset_id; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) - memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) + __dev_addr_set(qmap_net, real_dev->dev_addr, ETH_ALEN); #else - eth_hw_addr_set (real_dev, qmap_net->dev_addr); + memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); #endif #ifdef QUECTEL_BRIDGE_MODE @@ -1314,7 +1351,9 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) if (nss_cb && use_qca_nss) { rmnet_usb_rawip_setup(qmap_net); } - +#ifdef CONFIG_PINCTRL_IPQ9574 + rmnet_usb_rawip_setup(qmap_net); +#endif priv->agg_skb = NULL; priv->agg_count = 0; hrtimer_init(&priv->agg_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); @@ -1350,7 +1389,7 @@ static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) netdev_info(qmap_net, "NSS context created\n"); rtnl_lock(); netdev_rx_handler_register(qmap_net, qca_nss_rx_handler, NULL); - rtnl_unlock(); + rtnl_unlock(); } } @@ -1379,7 +1418,7 @@ static void qmap_unregister_device(sQmiWwanQmap * pDev, u8 offset_id) { pDev->mpQmapNetDev[offset_id] = NULL; netif_carrier_off( qmap_net ); netif_stop_queue( qmap_net ); - + hrtimer_cancel(&priv->agg_hrtimer); cancel_work_sync(&priv->agg_wq); spin_lock_irqsave(&priv->agg_lock, flags); @@ -1421,6 +1460,8 @@ typedef struct { } BRMAC_SETTING; #endif +static int qma_setting_store(struct device *dev, QMAP_SETTING *qmap_settings, size_t size); + int qma_setting_store(struct device *dev, QMAP_SETTING *qmap_settings, size_t size) { struct net_device *netdev = to_net_dev(dev); struct usbnet * usbnetdev = netdev_priv( netdev ); @@ -1460,7 +1501,11 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #ifdef CONFIG_BRIDGE_LAN BRMAC_SETTING brmac_settings = {0}; #endif - +#ifdef CONFIG_CLEAR_HALT + uint clear_halt = 0; +#endif + + switch (cmd) { case 0x89F1: //SIOCDEVPRIVATE rc = copy_from_user(&link_state, ifr->ifr_ifru.ifru_data, sizeof(link_state)); @@ -1493,7 +1538,7 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) rc = copy_to_user(ifr->ifr_ifru.ifru_data, &pQmapDev->rmnet_info, sizeof(pQmapDev->rmnet_info)); } break; - + #ifdef CONFIG_BRIDGE_LAN case 0x89F4: //SIOCDEVPRIVATE rc = copy_from_user(&brmac_settings, ifr->ifr_ifru.ifru_data, sizeof(brmac_settings)); @@ -1515,6 +1560,16 @@ static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } break; #endif +#ifdef CONFIG_CLEAR_HALT + case 0x89F5: //SIOCDEVPRIVATE + rc = copy_from_user(&clear_halt, ifr->ifr_ifru.ifru_data, sizeof(clear_halt)); + if (rc == 0 && clear_halt == 1) { + usb_clear_halt(usbnetdev->udev,usbnetdev->in); + usb_clear_halt(usbnetdev->udev,usbnetdev->out); + pr_info("usb_clear_halt EPIN EPOUT\n"); + } + break; +#endif default: break; @@ -1657,9 +1712,9 @@ static struct sk_buff *qmap_qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff if (skb) { if(pQmapDev->qmap_version == 5) - add_qhdr(skb, QUECTEL_QMAP_MUX_ID); + add_qhdr(skb, QUECTEL_QMAP_MUX_ID, NULL, 0); else - add_qhdr_v5(skb, QUECTEL_QMAP_MUX_ID); + add_qhdr_v5(skb, QUECTEL_QMAP_MUX_ID, NULL, 0); } else { return NULL; @@ -1690,7 +1745,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, while (skb_in->len > sizeof(struct qmap_hdr)) { struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb_in->data; struct rmnet_map_v5_csum_header *ul_header = NULL; - size_t hdr_size = sizeof(struct rmnet_map_header); + size_t hdr_size = sizeof(struct rmnet_map_header); struct net_device *qmap_net; int pkt_len = ntohs(map_header->pkt_len); int skb_len; @@ -1702,7 +1757,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); hdr_size += sizeof(struct rmnet_map_v5_csum_header); } - + skb_len = pkt_len - (map_header->pad_len&0x3F); skb_len -= dl_minimum_padding; @@ -1717,7 +1772,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, dev_info(dev, "drop qmap unknow mux_id %x\n", map_header->mux_id); goto skip_pkt; } - + if (skb_len > qmap_net->mtu) { dev_info(dev, "drop skb_len=%x larger than mtu=%d\n", skb_len, qmap_net->mtu); goto error_pkt; @@ -1760,7 +1815,7 @@ static void qmap_packet_decode(sQmiWwanQmap *pQmapDev, dev_info(dev, "unknow skb->protocol %02x\n", skb_in->data[hdr_size]); goto error_pkt; } - + qmap_skb = netdev_alloc_skb(qmap_net, skb_len); if (qmap_skb) { skb_put(qmap_skb, skb_len); @@ -1815,7 +1870,7 @@ static int qmap_qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; struct sk_buff *qmap_skb; struct sk_buff_head skb_chain; - + if (pQmapDev->qmap_mode == 0) return qmi_wwan_rx_fixup(dev, skb_in); @@ -1862,7 +1917,7 @@ static void (*_usbnet_get_stats64)(struct net_device *net, struct rtnl_link_stat static void qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { if (_usbnet_get_stats64) ////c8b5d129ee293bcf972e7279ac996bb8a138505c return _usbnet_get_stats64(net, stats); - + netdev_stats_to_stats64(stats, &net->stats); } #else @@ -1871,7 +1926,7 @@ static struct rtnl_link_stats64 * (*_usbnet_get_stats64)(struct net_device *net, static struct rtnl_link_stats64 * qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { if (_usbnet_get_stats64) return _usbnet_get_stats64(net, stats); - + netdev_stats_to_stats64(stats, &net->stats); return stats; } @@ -1896,7 +1951,7 @@ static int qmi_wwan_open (struct net_device *net) { } static netdev_tx_t qmi_wwan_start_xmit (struct sk_buff *skb, - struct net_device *net) + struct net_device *net) { struct usbnet * usbnetdev = netdev_priv( net ); struct qmi_wwan_state *info = (void *)&usbnetdev->data; @@ -1907,7 +1962,7 @@ static netdev_tx_t qmi_wwan_start_xmit (struct sk_buff *skb, if (netif_queue_stopped(net) && pQmapDev && pQmapDev->use_rmnet_usb) { int i; - + for (i = 0; i < pQmapDev->qmap_mode; i++) { struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; if (qmap_net) { @@ -1949,7 +2004,7 @@ static void ql_net_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *i { /* Inherit standard device info */ usbnet_get_drvinfo(net, info); - /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ + /* strlcpy() is deprecated in kernel 6.8.0+, using strscpy instead */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(6,8,0)) strlcpy(info->driver, driver_name, sizeof(info->driver)); strlcpy(info->version, VERSION_NUMBER, sizeof(info->version)); @@ -2021,7 +2076,7 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev) atomic_set(&info->pmcount, 0); /* register subdriver */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION( 5,12,0 )) //cac6fb015f719104e60b1c68c15ca5b734f57b9c +#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 5,14,0 )) //cac6fb015f719104e60b1c68c15ca5b734f57b9c subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 4096, WWAN_PORT_QMI, &qmi_wwan_cdc_wdm_manage_power); #else @@ -2072,17 +2127,17 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) /* make MAC addr easily distinguishable from an IP header */ if (possibly_iphdr(dev->net->dev_addr)) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) + u8 temp_addr[ETH_ALEN]; + memcpy(temp_addr, dev->net->dev_addr, ETH_ALEN); + temp_addr[0] |= 0x02; /* set local assignment bit */ + temp_addr[0] &= 0xbf; /* clear "IP" bit */ + __dev_addr_set(dev->net, temp_addr, ETH_ALEN); +#else dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ -#else - u8 addr = dev->net->dev_addr[0]; - - addr |= 0x02; /* set local assignment bit */ - addr &= 0xbf; /* clear "IP" bit */ - dev_addr_mod(dev->net, 0, &addr, 1); #endif - } + } if (!_usbnet_get_stats64) _usbnet_get_stats64 = dev->net->netdev_ops->ndo_get_stats64; dev->net->netdev_ops = &qmi_wwan_netdev_ops; @@ -2115,6 +2170,9 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) NULL, 0, 100); } + usb_clear_halt(dev->udev,dev->in); + usb_clear_halt(dev->udev,dev->out); + //to advoid module report mtu 1460, but rx 1500 bytes IP packets, and cause the customer's system crash //next setting can make usbnet.c:usbnet_change_mtu() do not modify rx_urb_size according to hard mtu dev->rx_urb_size = ETH_DATA_LEN + ETH_HLEN + 6; @@ -2146,12 +2204,13 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) int qmap_version = (dev->driver_info->data>>8)&0xFF; int qmap_size = (dev->driver_info->data)&0xFF; int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct); - int lte_a = (idProduct == 0x0306 || idProduct == 0x030B || idProduct == 0x0512 || idProduct == 0x0620 || idProduct == 0x0800 || idProduct == 0x0801); + int lte_a = (idProduct == 0x0306 || idProduct == 0x030B || idProduct == 0x0512 || idProduct == 0x0620 || + idProduct == 0x0800 || idProduct == 0x0801 || idProduct == 0x0122 || idProduct == 0x0316); if (qmap_size > 4096 || dev->udev->speed >= USB_SPEED_SUPER) { //if meet this requirements, must be LTE-A or 5G lte_a = 1; } - + pQmapDev->qmap_mode = qmap_mode; if (lte_a && pQmapDev->qmap_mode == 0) { pQmapDev->qmap_mode = 1; //force use QMAP @@ -2168,17 +2227,19 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) if (pQmapDev->qmap_mode > 1) pQmapDev->use_rmnet_usb = 1; - else if (idProduct == 0x0800 || idProduct == 0x0801) + else if (idProduct == 0x0800 || idProduct == 0x0801 || idProduct == 0x0122) pQmapDev->use_rmnet_usb = 1; //benefit for ul data agg #ifdef QMI_NETDEV_ONE_CARD_MODE if(pQmapDev->use_rmnet_usb == 1 && pQmapDev->qmap_mode == 1) one_card_mode = 1; pQmapDev->rmnet_info.mux_id[0] = QUECTEL_QMAP_MUX_ID; -#endif +#endif pQmapDev->rmnet_info.size = sizeof(RMNET_INFO); pQmapDev->rmnet_info.rx_urb_size = pQmapDev->qmap_size; pQmapDev->rmnet_info.ep_type = 2; //DATA_EP_TYPE_HSUSB - pQmapDev->rmnet_info.iface_id = 4; + pQmapDev->rmnet_info.iface_id = 4;//Interface ID + if(idProduct == 0x0316) + pQmapDev->rmnet_info.iface_id = 3;// SDX35 Interface ID pQmapDev->rmnet_info.qmap_mode = pQmapDev->qmap_mode; pQmapDev->rmnet_info.qmap_version = pQmapDev->qmap_version; pQmapDev->rmnet_info.dl_minimum_padding = 0; @@ -2188,7 +2249,7 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) pQmapDev->tx_ctx.ul_data_aggregation_max_size = 1500; #endif - if (pQmapDev->use_rmnet_usb && !one_card_mode) { + if (pQmapDev->use_rmnet_usb && !one_card_mode) { pQmapDev->driver_info = rmnet_usb_info; pQmapDev->driver_info.data = dev->driver_info->data; dev->driver_info = &pQmapDev->driver_info; @@ -2356,7 +2417,7 @@ static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } - + return 0; } @@ -2417,7 +2478,7 @@ static const struct driver_info qmi_wwan_info = { }; #define qmi_wwan_raw_ip_info \ - .description = "WWAN/QMI device", \ + .description = "WWAN/QMI Raw IP device", \ .flags = FLAG_WWAN | FLAG_RX_ASSEMBLE | FLAG_NOARP | FLAG_SEND_ZLP, \ .bind = qmi_wwan_bind, \ .unbind = qmi_wwan_unbind, \ @@ -2465,6 +2526,7 @@ static const struct usb_device_id products[] = { { QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 (MDM9215) */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0125, 4, mdm9x07) }, /* Quectel EC20 (MDM9X07)/EC25/EG25 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0121, 4, mdm9x07) }, /* Quectel EC21 */ + { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x030E, 4, mdm9x07) }, /* Quectel EM05G */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0191, 4, mdm9x07) }, /* Quectel EG91 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0195, 4, mdm9x07) }, /* Quectel EG95 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0700, 3, mdm9x07) }, /* Quectel BG95 (at+qcfgext="usbnet","rmnet") */ @@ -2474,8 +2536,10 @@ static const struct usb_device_id products[] = { { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0296, 4, mdm9x07) }, /* Quectel BG96 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0435, 4, mdm9x07) }, /* Quectel AG35 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0620, 4, mdm9x40) }, /* Quectel EG20 */ + { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0316, 3, mdm9x40) }, /* Quectel RG255 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0800, 4, sdx55) }, /* Quectel RG500 */ { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0801, 4, sdx55) }, /* Quectel RG520 */ + { QMI_FIXED_RAWIP_INTF(0x2C7C, 0x0122, 4, sdx55) }, /* Quectel RG650 */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); @@ -2582,11 +2646,11 @@ static void qmap_qmi_wwan_disconnect(struct usb_interface *intf) } tasklet_kill(&pQmapDev->txq); - + usbnet_disconnect(intf); /* struct usbnet *dev had free by usbnet_disconnect()->free_netdev(). so we should access info. */ - //info->unused = 0; + //info->unused = 0; kfree(pQmapDev); } #endif