Loading drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +174 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ #include <asm/dma-iommu.h> #include <linux/iommu.h> #include <linux/micrel_phy.h> #include <linux/tcp.h> #include <linux/ip.h> #include <linux/ipv6.h> #include "stmmac.h" #include "stmmac_platform.h" #include "dwmac-qcom-ethqos.h" Loading @@ -36,6 +38,176 @@ void *ipc_emac_log_ctxt; static struct qmp_pkt pkt; static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0}; static inline unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) { return ((((u16)buf[QTAG_ETH_TYPE_OFFSET] << 8) | buf[QTAG_ETH_TYPE_OFFSET + 1]) == ETH_P_8021Q) ? (((u16)buf[QTAG_VLAN_ETH_TYPE_OFFSET] << 8) | buf[QTAG_VLAN_ETH_TYPE_OFFSET + 1]) : (((u16)buf[QTAG_ETH_TYPE_OFFSET] << 8) | buf[QTAG_ETH_TYPE_OFFSET + 1]); } static inline unsigned int dwmac_qcom_get_vlan_ucp(unsigned char *buf) { return (((u16)buf[QTAG_UCP_FIELD_OFFSET] << 8) | buf[QTAG_UCP_FIELD_OFFSET + 1]); } u16 dwmac_qcom_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type, priority; bool ipa_enabled = pethqos->ipa_enabled; /* Retrieve ETH type */ eth_type = dwmac_qcom_get_eth_type(skb->data); if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ priority = dwmac_qcom_get_vlan_ucp(skb->data); priority >>= VLAN_TAG_UCP_SHIFT; if (priority == CLASS_A_TRAFFIC_UCP) { txqueue_select = CLASS_A_TRAFFIC_TX_CHANNEL; } else if (priority == CLASS_B_TRAFFIC_UCP) { txqueue_select = CLASS_B_TRAFFIC_TX_CHANNEL; } else { if (ipa_enabled) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } } else { /* VLAN tagged IP packet or any other non vlan packets (PTP)*/ if (ipa_enabled) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } if (ipa_enabled && txqueue_select == IPA_DMA_TX_CH) { ETHQOSERR("TX Channel [%d] is not a valid for SW path\n", txqueue_select); WARN_ON(1); } ETHQOSDBG("tx_queue %d\n", txqueue_select); return txqueue_select; } void dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req) { struct dwmac_qcom_avb_algorithm l_avb_struct, *u_avb_struct = (struct dwmac_qcom_avb_algorithm *)req->ptr; struct dwmac_qcom_avb_algorithm_params *avb_params; ETHQOSDBG("\n"); if (copy_from_user(&l_avb_struct, (void __user *)u_avb_struct, sizeof(struct dwmac_qcom_avb_algorithm))) ETHQOSERR("Failed to fetch AVB Struct\n"); if (priv->speed == SPEED_1000) avb_params = &l_avb_struct.speed1000params; else avb_params = &l_avb_struct.speed100params; /* Application uses 1 for CLASS A traffic and * 2 for CLASS B traffic * Configure right channel accordingly */ if (l_avb_struct.qinx == 1) l_avb_struct.qinx = CLASS_A_TRAFFIC_TX_CHANNEL; else if (l_avb_struct.qinx == 2) l_avb_struct.qinx = CLASS_B_TRAFFIC_TX_CHANNEL; priv->plat->tx_queues_cfg[l_avb_struct.qinx].mode_to_use = MTL_QUEUE_AVB; priv->plat->tx_queues_cfg[l_avb_struct.qinx].send_slope = avb_params->send_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].idle_slope = avb_params->idle_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].high_credit = avb_params->hi_credit, priv->plat->tx_queues_cfg[l_avb_struct.qinx].low_credit = avb_params->low_credit, priv->hw->mac->config_cbs( priv->hw, priv->plat->tx_queues_cfg[l_avb_struct.qinx].send_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].idle_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].high_credit, priv->plat->tx_queues_cfg[l_avb_struct.qinx].low_credit, l_avb_struct.qinx); ETHQOSDBG("\n"); } unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb) { bool is_udp; unsigned int eth_type; eth_type = dwmac_qcom_get_eth_type(skb->data); #ifdef CONFIG_PTPSUPPORT_OBJ if (eth_type == ETH_P_1588) return PTP_INT_MOD; #endif if (eth_type == ETH_P_TSN) return AVB_INT_MOD; if (eth_type == ETH_P_IP || eth_type == ETH_P_IPV6) { #ifdef CONFIG_PTPSUPPORT_OBJ is_udp = (((eth_type == ETH_P_IP) && (ip_hdr(skb)->protocol == IPPROTO_UDP)) || ((eth_type == ETH_P_IPV6) && (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP))); if (is_udp && ((udp_hdr(skb)->dest == htons(PTP_UDP_EV_PORT)) || (udp_hdr(skb)->dest == htons(PTP_UDP_GEN_PORT)))) return PTP_INT_MOD; #endif return IP_PKT_INT_MOD; } return DEFAULT_INT_MOD; } int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct stmmac_priv *pdata = netdev_priv(dev); struct ifr_data_struct req; int ret = 0; if (copy_from_user(&req, ifr->ifr_ifru.ifru_data, sizeof(struct ifr_data_struct))) return -EFAULT; switch (req.cmd) { case ETHQOS_CONFIG_PPSOUT_CMD: ret = ppsout_config(pdata, &req); break; case ETHQOS_AVB_ALGORITHM: dwmac_qcom_program_avb_algorithm(pdata, &req); break; default: break; } return ret; } static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) { return readl(ethqos->rgmii_base + offset); Loading Loading @@ -1227,6 +1399,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->bsp_priv = ethqos; plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->tx_select_queue = dwmac_qcom_select_queue; plat_dat->has_gmac4 = 1; plat_dat->pmt = 1; plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); Loading drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +62 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ do {\ #define RGMII_IO_MACRO_CONFIG2 0x1C #define ETHQOS_CONFIG_PPSOUT_CMD 44 #define ETHQOS_AVB_ALGORITHM 27 #define MAC_PPS_CONTROL 0x00000b70 #define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1) #define PPS_MINIDX(x) ((x) * 8) Loading Loading @@ -435,4 +437,64 @@ int create_pps_interrupt_device_node(dev_t *pps_dev_t, char *pps_dev_node_name); void qcom_ethqos_request_phy_wol(struct plat_stmmacenet_data *plat); int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req); u16 dwmac_qcom_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback); #define QTAG_VLAN_ETH_TYPE_OFFSET 16 #define QTAG_UCP_FIELD_OFFSET 14 #define QTAG_ETH_TYPE_OFFSET 12 #define PTP_UDP_EV_PORT 0x013F #define PTP_UDP_GEN_PORT 0x0140 #define IPA_DMA_TX_CH 0 #define IPA_DMA_RX_CH 0 #define VLAN_TAG_UCP_SHIFT 13 #define CLASS_A_TRAFFIC_UCP 3 #define CLASS_A_TRAFFIC_TX_CHANNEL 3 #define CLASS_B_TRAFFIC_UCP 2 #define CLASS_B_TRAFFIC_TX_CHANNEL 2 #define NON_TAGGED_IP_TRAFFIC_TX_CHANNEL 1 #define ALL_OTHER_TRAFFIC_TX_CHANNEL 1 #define ALL_OTHER_TX_TRAFFIC_IPA_DISABLED 0 #define DEFAULT_INT_MOD 1 #define AVB_INT_MOD 8 #define IP_PKT_INT_MOD 32 #define PTP_INT_MOD 1 enum dwmac_qcom_queue_operating_mode { DWMAC_QCOM_QDISABLED = 0X0, DWMAC_QCOM_QAVB, DWMAC_QCOM_QDCB, DWMAC_QCOM_QGENERIC }; struct dwmac_qcom_avb_algorithm_params { unsigned int idle_slope; unsigned int send_slope; unsigned int hi_credit; unsigned int low_credit; }; struct dwmac_qcom_avb_algorithm { unsigned int qinx; unsigned int algorithm; unsigned int cc; struct dwmac_qcom_avb_algorithm_params speed100params; struct dwmac_qcom_avb_algorithm_params speed1000params; enum dwmac_qcom_queue_operating_mode op_mode; }; void dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req); unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb); #endif drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-pps.c +26 −43 Original line number Diff line number Diff line Loading @@ -115,7 +115,7 @@ static u32 pps_config_default_addend(void __iomem *ioaddr, priv->default_addend = 0xFFFFFFFF; } else { temp = (u64)((u64)ptp_clock << 32); priv->default_addend = div_u64(temp, 250000000); priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); } priv->hw->ptp->config_addend(ioaddr, priv->default_addend); Loading Loading @@ -200,17 +200,21 @@ static void ethqos_unregister_pps_isr(struct stmmac_priv *priv, int ch) int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req) { struct pps_cfg *eth_pps_cfg = (struct pps_cfg *)req->ptr; int interval, width; u32 sub_second_inc, value; void __iomem *ioaddr = priv->ioaddr; u32 val; struct pps_cfg eth_pps_cfg; if (copy_from_user(ð_pps_cfg, (void __user *)req->ptr, sizeof(struct pps_cfg))) return -EFAULT; if (!eth_pps_cfg->ppsout_start) { ppsout_stop(priv, eth_pps_cfg); if (eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_unregister_pps_isr(priv, eth_pps_cfg->ppsout_ch); if (!eth_pps_cfg.ppsout_start) { ppsout_stop(priv, ð_pps_cfg); if (eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_unregister_pps_isr(priv, eth_pps_cfg.ppsout_ch); return 0; } Loading @@ -222,40 +226,40 @@ int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req) val = readl_relaxed(ioaddr + MAC_PPS_CONTROL); sub_second_inc = pps_config_sub_second_increment (priv->ptpaddr, eth_pps_cfg->ptpclk_freq, (priv->ptpaddr, eth_pps_cfg.ptpclk_freq, priv->plat->has_gmac4); pps_config_default_addend(priv->ptpaddr, priv, eth_pps_cfg->ptpclk_freq); eth_pps_cfg.ptpclk_freq); val &= ~PPSX_MASK(eth_pps_cfg->ppsout_ch); val &= ~PPSX_MASK(eth_pps_cfg.ppsout_ch); val |= PPSCMDX(eth_pps_cfg->ppsout_ch, 0x2); val |= TRGTMODSELX(eth_pps_cfg->ppsout_ch, 0x2); val |= PPSCMDX(eth_pps_cfg.ppsout_ch, 0x2); val |= TRGTMODSELX(eth_pps_cfg.ppsout_ch, 0x2); val |= PPSEN0; if (eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_register_pps_isr(priv, eth_pps_cfg->ppsout_ch); if (eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_register_pps_isr(priv, eth_pps_cfg.ppsout_ch); writel_relaxed(0, ioaddr + MAC_PPSX_TARGET_TIME_SEC(eth_pps_cfg->ppsout_ch)); MAC_PPSX_TARGET_TIME_SEC(eth_pps_cfg.ppsout_ch)); writel_relaxed(0, ioaddr + MAC_PPSX_TARGET_TIME_NSEC(eth_pps_cfg->ppsout_ch)); MAC_PPSX_TARGET_TIME_NSEC(eth_pps_cfg.ppsout_ch)); interval = ((eth_pps_cfg->ptpclk_freq + eth_pps_cfg->ppsout_freq / 2) / eth_pps_cfg->ppsout_freq); interval = ((eth_pps_cfg.ptpclk_freq + eth_pps_cfg.ppsout_freq / 2) / eth_pps_cfg.ppsout_freq); width = ((interval * eth_pps_cfg->ppsout_duty) + 50) / 100 - 1; width = ((interval * eth_pps_cfg.ppsout_duty) + 50) / 100 - 1; if (width >= interval) width = interval - 1; if (width < 0) width = 0; writel_relaxed(interval, ioaddr + MAC_PPSX_INTERVAL(eth_pps_cfg->ppsout_ch)); MAC_PPSX_INTERVAL(eth_pps_cfg.ppsout_ch)); writel_relaxed(width, ioaddr + MAC_PPSX_WIDTH(eth_pps_cfg->ppsout_ch)); writel_relaxed(width, ioaddr + MAC_PPSX_WIDTH(eth_pps_cfg.ppsout_ch)); writel_relaxed(val, ioaddr + MAC_PPS_CONTROL); Loading Loading @@ -286,27 +290,6 @@ int ethqos_init_pps(struct stmmac_priv *priv) return 0; } int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct stmmac_priv *pdata = netdev_priv(dev); struct ifr_data_struct req; struct pps_cfg eth_pps_cfg; int ret = 0; if (copy_from_user(&req, ifr->ifr_ifru.ifru_data, sizeof(struct ifr_data_struct))) return -EFAULT; if (copy_from_user(ð_pps_cfg, req.ptr, sizeof(struct pps_cfg))) return -EFAULT; req.ptr = ð_pps_cfg; switch (req.cmd) { case ETHQOS_CONFIG_PPSOUT_CMD: ret = ppsout_config(pdata, &req); } return ret; } static ssize_t pps_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { Loading drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +17 −7 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, u32 ptp_clock, int gmac4) { u32 value = readl(ioaddr + PTP_TCR); unsigned long data; unsigned long ss_inc = 0, sns_inc = 0, ptpclock = 0; u32 reg_value; /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second Loading @@ -43,23 +43,33 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, * where ptp_clock is 50MHz if fine method is used to update system */ if (value & PTP_TCR_TSCFUPDT) data = (1000000000ULL / 50000000); ptpclock = (unsigned long)ptp_clock; else data = (1000000000ULL / ptp_clock); ptpclock = (unsigned long)ptp_clock; ss_inc = ((1 * 1000000000ULL) / ptpclock); sns_inc = 1000000000ULL - (ss_inc * ptpclock); //take remainder //sns_inc needs to be multiplied by 2^8, per spec. sns_inc = (sns_inc * 256) / ptpclock; /* 0.465ns accuracy */ if (!(value & PTP_TCR_TSCTRLSSR)) data = (data * 1000) / 465; ss_inc = (ss_inc * 1000) / 465; data &= PTP_SSIR_SSINC_MASK; ss_inc &= PTP_SSIR_SSINC_MASK; sns_inc &= PTP_SSIR_SNSINC_MASK; reg_value = ss_inc; reg_value = data; if (gmac4) reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT; reg_value |= (sns_inc << GMAC4_PTP_SSIR_SNSINC_SHIFT); writel(reg_value, ioaddr + PTP_SSIR); return data; return reg_value; } static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) Loading drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +31 −35 Original line number Diff line number Diff line Loading @@ -524,6 +524,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) u32 snap_type_sel = 0; u32 ts_master_en = 0; u32 ts_event_en = 0; u32 av_8021asm_en = 0; u32 value = 0; u32 sec_inc; Loading Loading @@ -632,6 +633,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_PTP_V2_SYNC: Loading @@ -644,6 +646,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: Loading @@ -657,6 +660,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_NTP_ALL: Loading Loading @@ -689,21 +693,20 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR | tstamp_all | ptp_v2 | ptp_over_ethernet | ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | ts_master_en | snap_type_sel); ts_master_en | snap_type_sel | av_8021asm_en); priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, value); /* program Sub Second Increment reg */ sec_inc = priv->hw->ptp->config_sub_second_increment( priv->ptpaddr, priv->plat->clk_ptp_rate, priv->ptpaddr, priv->plat->clk_ptp_req_rate, priv->plat->has_gmac4); temp = div_u64(1000000000ULL, sec_inc); /* calculate default added value: * formula is : * addend = (2^32)/freq_div_ratio; * where, freq_div_ratio = 1e9ns/sec_inc */ temp = (u64)(temp << 32); temp = (u64)((u64)priv->plat->clk_ptp_req_rate << 32); priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); priv->hw->ptp->config_addend(priv->ptpaddr, priv->default_addend); Loading Loading @@ -2569,7 +2572,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) else if (ret) netdev_warn(priv->dev, "PTP init failed\n"); else ret = clk_set_rate(priv->plat->clk_ptp_ref, 96000000); clk_set_rate( priv->plat->clk_ptp_ref, priv->plat->clk_ptp_rate); ret = ethqos_init_pps(priv); } Loading Loading @@ -3188,12 +3194,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; priv->tx_count_frames += nfrags + 1; /* According to the coalesce parameter the IC bit for the latest * segment is reset and the timer re-started to clean the tx status. * This approach takes care about the fragments: desc is the first * element in case of no SG. */ priv->tx_count_frames += nfrags + 1; if (likely(priv->tx_coal_frames > priv->tx_count_frames)) { mod_timer(&priv->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer)); Loading @@ -3203,6 +3210,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } if (!priv->hwts_tx_en) skb_tx_timestamp(skb); /* Ready to fill the first descriptor and set the OWN bit w/o any Loading Loading @@ -3857,6 +3865,21 @@ static int stmmac_set_mac_address(struct net_device *ndev, void *addr) return ret; } static u16 stmmac_tx_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { struct stmmac_priv *priv = netdev_priv(dev); if (likely(priv->plat->tx_select_queue)) return priv->plat->tx_select_queue( dev, skb, accel_priv, fallback); return fallback(dev, skb); } #ifdef CONFIG_DEBUG_FS static struct dentry *stmmac_fs_dir; Loading Loading @@ -4073,33 +4096,6 @@ static void stmmac_exit_fs(struct net_device *dev) debugfs_remove_recursive(priv->dbgfs_dir); } #endif /* CONFIG_DEBUG_FS */ static u16 ethqos_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { struct stmmac_priv *priv = netdev_priv(dev); u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type; /* Retrieve ETH type */ GET_ETH_TYPE(skb->data, eth_type); if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ /* To do for vlan-tsn */ } else { /* VLAN tagged IP packet or any other non vlan packets (PTP)*/ txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; if (priv->tx_queue[txqueue_select].skip_sw) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; } if (priv->tx_queue[txqueue_select].skip_sw) netdev_err(priv->dev, "TX Chan %d is not valid for SW path\n", txqueue_select); return txqueue_select; } static const struct net_device_ops stmmac_netdev_ops = { .ndo_open = stmmac_open, Loading @@ -4111,11 +4107,11 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_set_rx_mode = stmmac_set_rx_mode, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, .ndo_select_queue = ethqos_select_queue, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = stmmac_poll_controller, #endif .ndo_set_mac_address = stmmac_set_mac_address, .ndo_select_queue = stmmac_tx_select_queue, }; /** Loading Loading
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +174 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ #include <asm/dma-iommu.h> #include <linux/iommu.h> #include <linux/micrel_phy.h> #include <linux/tcp.h> #include <linux/ip.h> #include <linux/ipv6.h> #include "stmmac.h" #include "stmmac_platform.h" #include "dwmac-qcom-ethqos.h" Loading @@ -36,6 +38,176 @@ void *ipc_emac_log_ctxt; static struct qmp_pkt pkt; static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0}; static inline unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) { return ((((u16)buf[QTAG_ETH_TYPE_OFFSET] << 8) | buf[QTAG_ETH_TYPE_OFFSET + 1]) == ETH_P_8021Q) ? (((u16)buf[QTAG_VLAN_ETH_TYPE_OFFSET] << 8) | buf[QTAG_VLAN_ETH_TYPE_OFFSET + 1]) : (((u16)buf[QTAG_ETH_TYPE_OFFSET] << 8) | buf[QTAG_ETH_TYPE_OFFSET + 1]); } static inline unsigned int dwmac_qcom_get_vlan_ucp(unsigned char *buf) { return (((u16)buf[QTAG_UCP_FIELD_OFFSET] << 8) | buf[QTAG_UCP_FIELD_OFFSET + 1]); } u16 dwmac_qcom_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type, priority; bool ipa_enabled = pethqos->ipa_enabled; /* Retrieve ETH type */ eth_type = dwmac_qcom_get_eth_type(skb->data); if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ priority = dwmac_qcom_get_vlan_ucp(skb->data); priority >>= VLAN_TAG_UCP_SHIFT; if (priority == CLASS_A_TRAFFIC_UCP) { txqueue_select = CLASS_A_TRAFFIC_TX_CHANNEL; } else if (priority == CLASS_B_TRAFFIC_UCP) { txqueue_select = CLASS_B_TRAFFIC_TX_CHANNEL; } else { if (ipa_enabled) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } } else { /* VLAN tagged IP packet or any other non vlan packets (PTP)*/ if (ipa_enabled) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } if (ipa_enabled && txqueue_select == IPA_DMA_TX_CH) { ETHQOSERR("TX Channel [%d] is not a valid for SW path\n", txqueue_select); WARN_ON(1); } ETHQOSDBG("tx_queue %d\n", txqueue_select); return txqueue_select; } void dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req) { struct dwmac_qcom_avb_algorithm l_avb_struct, *u_avb_struct = (struct dwmac_qcom_avb_algorithm *)req->ptr; struct dwmac_qcom_avb_algorithm_params *avb_params; ETHQOSDBG("\n"); if (copy_from_user(&l_avb_struct, (void __user *)u_avb_struct, sizeof(struct dwmac_qcom_avb_algorithm))) ETHQOSERR("Failed to fetch AVB Struct\n"); if (priv->speed == SPEED_1000) avb_params = &l_avb_struct.speed1000params; else avb_params = &l_avb_struct.speed100params; /* Application uses 1 for CLASS A traffic and * 2 for CLASS B traffic * Configure right channel accordingly */ if (l_avb_struct.qinx == 1) l_avb_struct.qinx = CLASS_A_TRAFFIC_TX_CHANNEL; else if (l_avb_struct.qinx == 2) l_avb_struct.qinx = CLASS_B_TRAFFIC_TX_CHANNEL; priv->plat->tx_queues_cfg[l_avb_struct.qinx].mode_to_use = MTL_QUEUE_AVB; priv->plat->tx_queues_cfg[l_avb_struct.qinx].send_slope = avb_params->send_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].idle_slope = avb_params->idle_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].high_credit = avb_params->hi_credit, priv->plat->tx_queues_cfg[l_avb_struct.qinx].low_credit = avb_params->low_credit, priv->hw->mac->config_cbs( priv->hw, priv->plat->tx_queues_cfg[l_avb_struct.qinx].send_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].idle_slope, priv->plat->tx_queues_cfg[l_avb_struct.qinx].high_credit, priv->plat->tx_queues_cfg[l_avb_struct.qinx].low_credit, l_avb_struct.qinx); ETHQOSDBG("\n"); } unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb) { bool is_udp; unsigned int eth_type; eth_type = dwmac_qcom_get_eth_type(skb->data); #ifdef CONFIG_PTPSUPPORT_OBJ if (eth_type == ETH_P_1588) return PTP_INT_MOD; #endif if (eth_type == ETH_P_TSN) return AVB_INT_MOD; if (eth_type == ETH_P_IP || eth_type == ETH_P_IPV6) { #ifdef CONFIG_PTPSUPPORT_OBJ is_udp = (((eth_type == ETH_P_IP) && (ip_hdr(skb)->protocol == IPPROTO_UDP)) || ((eth_type == ETH_P_IPV6) && (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP))); if (is_udp && ((udp_hdr(skb)->dest == htons(PTP_UDP_EV_PORT)) || (udp_hdr(skb)->dest == htons(PTP_UDP_GEN_PORT)))) return PTP_INT_MOD; #endif return IP_PKT_INT_MOD; } return DEFAULT_INT_MOD; } int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct stmmac_priv *pdata = netdev_priv(dev); struct ifr_data_struct req; int ret = 0; if (copy_from_user(&req, ifr->ifr_ifru.ifru_data, sizeof(struct ifr_data_struct))) return -EFAULT; switch (req.cmd) { case ETHQOS_CONFIG_PPSOUT_CMD: ret = ppsout_config(pdata, &req); break; case ETHQOS_AVB_ALGORITHM: dwmac_qcom_program_avb_algorithm(pdata, &req); break; default: break; } return ret; } static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) { return readl(ethqos->rgmii_base + offset); Loading Loading @@ -1227,6 +1399,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->bsp_priv = ethqos; plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->tx_select_queue = dwmac_qcom_select_queue; plat_dat->has_gmac4 = 1; plat_dat->pmt = 1; plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); Loading
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +62 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ do {\ #define RGMII_IO_MACRO_CONFIG2 0x1C #define ETHQOS_CONFIG_PPSOUT_CMD 44 #define ETHQOS_AVB_ALGORITHM 27 #define MAC_PPS_CONTROL 0x00000b70 #define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1) #define PPS_MINIDX(x) ((x) * 8) Loading Loading @@ -435,4 +437,64 @@ int create_pps_interrupt_device_node(dev_t *pps_dev_t, char *pps_dev_node_name); void qcom_ethqos_request_phy_wol(struct plat_stmmacenet_data *plat); int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req); u16 dwmac_qcom_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback); #define QTAG_VLAN_ETH_TYPE_OFFSET 16 #define QTAG_UCP_FIELD_OFFSET 14 #define QTAG_ETH_TYPE_OFFSET 12 #define PTP_UDP_EV_PORT 0x013F #define PTP_UDP_GEN_PORT 0x0140 #define IPA_DMA_TX_CH 0 #define IPA_DMA_RX_CH 0 #define VLAN_TAG_UCP_SHIFT 13 #define CLASS_A_TRAFFIC_UCP 3 #define CLASS_A_TRAFFIC_TX_CHANNEL 3 #define CLASS_B_TRAFFIC_UCP 2 #define CLASS_B_TRAFFIC_TX_CHANNEL 2 #define NON_TAGGED_IP_TRAFFIC_TX_CHANNEL 1 #define ALL_OTHER_TRAFFIC_TX_CHANNEL 1 #define ALL_OTHER_TX_TRAFFIC_IPA_DISABLED 0 #define DEFAULT_INT_MOD 1 #define AVB_INT_MOD 8 #define IP_PKT_INT_MOD 32 #define PTP_INT_MOD 1 enum dwmac_qcom_queue_operating_mode { DWMAC_QCOM_QDISABLED = 0X0, DWMAC_QCOM_QAVB, DWMAC_QCOM_QDCB, DWMAC_QCOM_QGENERIC }; struct dwmac_qcom_avb_algorithm_params { unsigned int idle_slope; unsigned int send_slope; unsigned int hi_credit; unsigned int low_credit; }; struct dwmac_qcom_avb_algorithm { unsigned int qinx; unsigned int algorithm; unsigned int cc; struct dwmac_qcom_avb_algorithm_params speed100params; struct dwmac_qcom_avb_algorithm_params speed1000params; enum dwmac_qcom_queue_operating_mode op_mode; }; void dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req); unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb); #endif
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-pps.c +26 −43 Original line number Diff line number Diff line Loading @@ -115,7 +115,7 @@ static u32 pps_config_default_addend(void __iomem *ioaddr, priv->default_addend = 0xFFFFFFFF; } else { temp = (u64)((u64)ptp_clock << 32); priv->default_addend = div_u64(temp, 250000000); priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); } priv->hw->ptp->config_addend(ioaddr, priv->default_addend); Loading Loading @@ -200,17 +200,21 @@ static void ethqos_unregister_pps_isr(struct stmmac_priv *priv, int ch) int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req) { struct pps_cfg *eth_pps_cfg = (struct pps_cfg *)req->ptr; int interval, width; u32 sub_second_inc, value; void __iomem *ioaddr = priv->ioaddr; u32 val; struct pps_cfg eth_pps_cfg; if (copy_from_user(ð_pps_cfg, (void __user *)req->ptr, sizeof(struct pps_cfg))) return -EFAULT; if (!eth_pps_cfg->ppsout_start) { ppsout_stop(priv, eth_pps_cfg); if (eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_unregister_pps_isr(priv, eth_pps_cfg->ppsout_ch); if (!eth_pps_cfg.ppsout_start) { ppsout_stop(priv, ð_pps_cfg); if (eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_unregister_pps_isr(priv, eth_pps_cfg.ppsout_ch); return 0; } Loading @@ -222,40 +226,40 @@ int ppsout_config(struct stmmac_priv *priv, struct ifr_data_struct *req) val = readl_relaxed(ioaddr + MAC_PPS_CONTROL); sub_second_inc = pps_config_sub_second_increment (priv->ptpaddr, eth_pps_cfg->ptpclk_freq, (priv->ptpaddr, eth_pps_cfg.ptpclk_freq, priv->plat->has_gmac4); pps_config_default_addend(priv->ptpaddr, priv, eth_pps_cfg->ptpclk_freq); eth_pps_cfg.ptpclk_freq); val &= ~PPSX_MASK(eth_pps_cfg->ppsout_ch); val &= ~PPSX_MASK(eth_pps_cfg.ppsout_ch); val |= PPSCMDX(eth_pps_cfg->ppsout_ch, 0x2); val |= TRGTMODSELX(eth_pps_cfg->ppsout_ch, 0x2); val |= PPSCMDX(eth_pps_cfg.ppsout_ch, 0x2); val |= TRGTMODSELX(eth_pps_cfg.ppsout_ch, 0x2); val |= PPSEN0; if (eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg->ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_register_pps_isr(priv, eth_pps_cfg->ppsout_ch); if (eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_2 || eth_pps_cfg.ppsout_ch == DWC_ETH_QOS_PPS_CH_3) ethqos_register_pps_isr(priv, eth_pps_cfg.ppsout_ch); writel_relaxed(0, ioaddr + MAC_PPSX_TARGET_TIME_SEC(eth_pps_cfg->ppsout_ch)); MAC_PPSX_TARGET_TIME_SEC(eth_pps_cfg.ppsout_ch)); writel_relaxed(0, ioaddr + MAC_PPSX_TARGET_TIME_NSEC(eth_pps_cfg->ppsout_ch)); MAC_PPSX_TARGET_TIME_NSEC(eth_pps_cfg.ppsout_ch)); interval = ((eth_pps_cfg->ptpclk_freq + eth_pps_cfg->ppsout_freq / 2) / eth_pps_cfg->ppsout_freq); interval = ((eth_pps_cfg.ptpclk_freq + eth_pps_cfg.ppsout_freq / 2) / eth_pps_cfg.ppsout_freq); width = ((interval * eth_pps_cfg->ppsout_duty) + 50) / 100 - 1; width = ((interval * eth_pps_cfg.ppsout_duty) + 50) / 100 - 1; if (width >= interval) width = interval - 1; if (width < 0) width = 0; writel_relaxed(interval, ioaddr + MAC_PPSX_INTERVAL(eth_pps_cfg->ppsout_ch)); MAC_PPSX_INTERVAL(eth_pps_cfg.ppsout_ch)); writel_relaxed(width, ioaddr + MAC_PPSX_WIDTH(eth_pps_cfg->ppsout_ch)); writel_relaxed(width, ioaddr + MAC_PPSX_WIDTH(eth_pps_cfg.ppsout_ch)); writel_relaxed(val, ioaddr + MAC_PPS_CONTROL); Loading Loading @@ -286,27 +290,6 @@ int ethqos_init_pps(struct stmmac_priv *priv) return 0; } int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct stmmac_priv *pdata = netdev_priv(dev); struct ifr_data_struct req; struct pps_cfg eth_pps_cfg; int ret = 0; if (copy_from_user(&req, ifr->ifr_ifru.ifru_data, sizeof(struct ifr_data_struct))) return -EFAULT; if (copy_from_user(ð_pps_cfg, req.ptr, sizeof(struct pps_cfg))) return -EFAULT; req.ptr = ð_pps_cfg; switch (req.cmd) { case ETHQOS_CONFIG_PPSOUT_CMD: ret = ppsout_config(pdata, &req); } return ret; } static ssize_t pps_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { Loading
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +17 −7 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, u32 ptp_clock, int gmac4) { u32 value = readl(ioaddr + PTP_TCR); unsigned long data; unsigned long ss_inc = 0, sns_inc = 0, ptpclock = 0; u32 reg_value; /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second Loading @@ -43,23 +43,33 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, * where ptp_clock is 50MHz if fine method is used to update system */ if (value & PTP_TCR_TSCFUPDT) data = (1000000000ULL / 50000000); ptpclock = (unsigned long)ptp_clock; else data = (1000000000ULL / ptp_clock); ptpclock = (unsigned long)ptp_clock; ss_inc = ((1 * 1000000000ULL) / ptpclock); sns_inc = 1000000000ULL - (ss_inc * ptpclock); //take remainder //sns_inc needs to be multiplied by 2^8, per spec. sns_inc = (sns_inc * 256) / ptpclock; /* 0.465ns accuracy */ if (!(value & PTP_TCR_TSCTRLSSR)) data = (data * 1000) / 465; ss_inc = (ss_inc * 1000) / 465; data &= PTP_SSIR_SSINC_MASK; ss_inc &= PTP_SSIR_SSINC_MASK; sns_inc &= PTP_SSIR_SNSINC_MASK; reg_value = ss_inc; reg_value = data; if (gmac4) reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT; reg_value |= (sns_inc << GMAC4_PTP_SSIR_SNSINC_SHIFT); writel(reg_value, ioaddr + PTP_SSIR); return data; return reg_value; } static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) Loading
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +31 −35 Original line number Diff line number Diff line Loading @@ -524,6 +524,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) u32 snap_type_sel = 0; u32 ts_master_en = 0; u32 ts_event_en = 0; u32 av_8021asm_en = 0; u32 value = 0; u32 sec_inc; Loading Loading @@ -632,6 +633,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_PTP_V2_SYNC: Loading @@ -644,6 +646,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: Loading @@ -657,6 +660,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; ptp_over_ethernet = PTP_TCR_TSIPENA; av_8021asm_en = PTP_TCR_AV8021ASMEN; break; case HWTSTAMP_FILTER_NTP_ALL: Loading Loading @@ -689,21 +693,20 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR | tstamp_all | ptp_v2 | ptp_over_ethernet | ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | ts_master_en | snap_type_sel); ts_master_en | snap_type_sel | av_8021asm_en); priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, value); /* program Sub Second Increment reg */ sec_inc = priv->hw->ptp->config_sub_second_increment( priv->ptpaddr, priv->plat->clk_ptp_rate, priv->ptpaddr, priv->plat->clk_ptp_req_rate, priv->plat->has_gmac4); temp = div_u64(1000000000ULL, sec_inc); /* calculate default added value: * formula is : * addend = (2^32)/freq_div_ratio; * where, freq_div_ratio = 1e9ns/sec_inc */ temp = (u64)(temp << 32); temp = (u64)((u64)priv->plat->clk_ptp_req_rate << 32); priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); priv->hw->ptp->config_addend(priv->ptpaddr, priv->default_addend); Loading Loading @@ -2569,7 +2572,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) else if (ret) netdev_warn(priv->dev, "PTP init failed\n"); else ret = clk_set_rate(priv->plat->clk_ptp_ref, 96000000); clk_set_rate( priv->plat->clk_ptp_ref, priv->plat->clk_ptp_rate); ret = ethqos_init_pps(priv); } Loading Loading @@ -3188,12 +3194,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; priv->tx_count_frames += nfrags + 1; /* According to the coalesce parameter the IC bit for the latest * segment is reset and the timer re-started to clean the tx status. * This approach takes care about the fragments: desc is the first * element in case of no SG. */ priv->tx_count_frames += nfrags + 1; if (likely(priv->tx_coal_frames > priv->tx_count_frames)) { mod_timer(&priv->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer)); Loading @@ -3203,6 +3210,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) priv->xstats.tx_set_ic_bit++; } if (!priv->hwts_tx_en) skb_tx_timestamp(skb); /* Ready to fill the first descriptor and set the OWN bit w/o any Loading Loading @@ -3857,6 +3865,21 @@ static int stmmac_set_mac_address(struct net_device *ndev, void *addr) return ret; } static u16 stmmac_tx_select_queue( struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { struct stmmac_priv *priv = netdev_priv(dev); if (likely(priv->plat->tx_select_queue)) return priv->plat->tx_select_queue( dev, skb, accel_priv, fallback); return fallback(dev, skb); } #ifdef CONFIG_DEBUG_FS static struct dentry *stmmac_fs_dir; Loading Loading @@ -4073,33 +4096,6 @@ static void stmmac_exit_fs(struct net_device *dev) debugfs_remove_recursive(priv->dbgfs_dir); } #endif /* CONFIG_DEBUG_FS */ static u16 ethqos_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { struct stmmac_priv *priv = netdev_priv(dev); u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type; /* Retrieve ETH type */ GET_ETH_TYPE(skb->data, eth_type); if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ /* To do for vlan-tsn */ } else { /* VLAN tagged IP packet or any other non vlan packets (PTP)*/ txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; if (priv->tx_queue[txqueue_select].skip_sw) txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; } if (priv->tx_queue[txqueue_select].skip_sw) netdev_err(priv->dev, "TX Chan %d is not valid for SW path\n", txqueue_select); return txqueue_select; } static const struct net_device_ops stmmac_netdev_ops = { .ndo_open = stmmac_open, Loading @@ -4111,11 +4107,11 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_set_rx_mode = stmmac_set_rx_mode, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, .ndo_select_queue = ethqos_select_queue, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = stmmac_poll_controller, #endif .ndo_set_mac_address = stmmac_set_mac_address, .ndo_select_queue = stmmac_tx_select_queue, }; /** Loading