Loading drivers/net/ethernet/stmicro/stmmac/common.h +12 −0 Original line number Diff line number Diff line Loading @@ -472,16 +472,25 @@ struct stmmac_dma_ops { void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan); void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan); void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan); void (*enable_rx_fep)(void __iomem *ioaddr, bool en, u32 chan); }; struct mac_device_info; struct vlan_filter_info { u16 vlan_id; u32 vlan_offset; u32 rx_queue; }; /* Helpers to program the MAC core */ struct stmmac_ops { /* MAC core initialization */ void (*core_init)(struct mac_device_info *hw, struct net_device *dev); /* Enable the MAC RX/TX */ void (*set_mac)(void __iomem *ioaddr, bool enable); /* Enable the VLAN MAC configuration for DMA Queue*/ void (*set_vlan)(struct vlan_filter_info *vlan, void __iomem *ioaddr); /* Enable and verify that the IPC module is supported */ int (*rx_ipc)(struct mac_device_info *hw); /* Enable RX Queues */ Loading Loading @@ -623,6 +632,9 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, unsigned int high, unsigned int low); void stmmac_set_mac(void __iomem *ioaddr, bool enable); void stmmac_set_vlan_filter_rx_queue(struct vlan_filter_info *vlan, void __iomem *ioaddr); void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned int high, unsigned int low); void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, Loading drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +265 −8 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/rtnetlink.h> #include <linux/if_vlan.h> #include "stmmac.h" #include "stmmac_platform.h" #include "dwmac-qcom-ethqos.h" Loading Loading @@ -60,6 +62,7 @@ struct qcom_ethqos *pethqos; struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx = {0}; static unsigned char dev_addr[ETH_ALEN] = { 0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7}; static unsigned char config_dev_addr[ETH_ALEN] = {0}; void *ipc_stmmac_log_ctxt; void *ipc_stmmac_log_ctxt_low; Loading Loading @@ -110,13 +113,28 @@ u16 dwmac_qcom_select_queue( select_queue_fallback_t fallback) { u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type, priority; unsigned int eth_type, priority, vlan_id; bool ipa_enabled = pethqos->ipa_enabled; /* Retrieve ETH type */ eth_type = dwmac_qcom_get_eth_type(skb->data); if (eth_type == ETH_P_TSN) { if (pethqos->cv2x_mode == CV2X_MODE_AP) { if (skb_vlan_tag_present(skb)) { vlan_id = skb_vlan_tag_get_id(skb); if (vlan_id == pethqos->cv2x_vlan.vlan_id) txqueue_select = CV2X_TAG_TX_CHANNEL; else if (vlan_id == pethqos->qoe_vlan.vlan_id) txqueue_select = QMI_TAG_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } else { txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } } else if (pethqos->cv2x_mode == CV2X_MODE_MDM) { txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; } else if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ priority = dwmac_qcom_get_vlan_ucp(skb->data); Loading @@ -140,11 +158,6 @@ u16 dwmac_qcom_select_queue( 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; } Loading Loading @@ -2341,6 +2354,227 @@ bool qcom_ethqos_ipa_enabled(void) return false; } static ssize_t ethqos_read_dev_emac(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { unsigned int len = 0; char *temp_buf; ssize_t ret_cnt = 0; ret_cnt = simple_read_from_buffer(buf, count, f_pos, temp_buf, len); return ret_cnt; } static ssize_t ethqos_write_dev_emac(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { unsigned char in_buf[300] = {0}; unsigned long ret; struct qcom_ethqos *ethqos = pethqos; struct stmmac_priv *priv = qcom_ethqos_get_priv(pethqos); struct vlan_filter_info vlan_filter_info; char mac_str[30] = {0}; char vlan_str[30] = {0}; char *prefix = NULL; u32 err; unsigned int number; if (sizeof(in_buf) < count) { ETHQOSERR("emac string is too long - count=%u\n", count); return -EFAULT; } memset(in_buf, 0, sizeof(in_buf)); ret = copy_from_user(in_buf, user_buf, count); if (ret) return -EFAULT; strlcpy(vlan_str, in_buf, sizeof(vlan_str)); ETHQOSINFO("emac string is %s\n", vlan_str); if (strnstr(vlan_str, "QOE", sizeof(vlan_str))) { ethqos->qoe_vlan.available = true; vlan_filter_info.vlan_id = ethqos->qoe_vlan.vlan_id; vlan_filter_info.rx_queue = ethqos->qoe_vlan.rx_queue; vlan_filter_info.vlan_offset = ethqos->qoe_vlan.vlan_offset; priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr); } if (strnstr(vlan_str, "qvlanid=", sizeof(vlan_str))) { prefix = strnchr(vlan_str, strlen(vlan_str), '='); ETHQOSINFO("vlanid data written is %s\n", prefix + 1); if (prefix) { err = kstrtouint(prefix + 1, 0, &number); if (!err) ethqos->qoe_vlan.vlan_id = number; } } if (strnstr(vlan_str, "Cv2X", strlen(vlan_str))) { ETHQOSDBG("Cv2X supported mode is %u\n", ethqos->cv2x_mode); ethqos->cv2x_vlan.available = true; vlan_filter_info.vlan_id = ethqos->cv2x_vlan.vlan_id; vlan_filter_info.rx_queue = ethqos->cv2x_vlan.rx_queue; vlan_filter_info.vlan_offset = ethqos->cv2x_vlan.vlan_offset; priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr); } if (strnstr(vlan_str, "cvlanid=", strlen(vlan_str))) { prefix = strnchr(vlan_str, strlen(vlan_str), '='); ETHQOSDBG("Cv2X vlanid data written is %s\n", prefix + 1); if (prefix) { err = kstrtouint(prefix + 1, 0, &number); if (!err) ethqos->cv2x_vlan.vlan_id = number; } } if (strnstr(in_buf, "cmac_id=", strlen(in_buf))) { prefix = strnchr(in_buf, strlen(in_buf), '='); if (prefix) { memcpy(mac_str, (char *)prefix + 1, 30); if (!mac_pton(mac_str, config_dev_addr)) { ETHQOSERR("Invalid mac addr in /dev/emac\n"); return count; } if (!is_valid_ether_addr(config_dev_addr)) { ETHQOSERR("Invalid/Multcast mac addr found\n"); return count; } ether_addr_copy(dev_addr, config_dev_addr); memcpy(ethqos->cv2x_dev_addr, dev_addr, ETH_ALEN); } } return count; } static void ethqos_get_qoe_dt(struct qcom_ethqos *ethqos, struct device_node *np) { int res; res = of_property_read_u32(np, "qcom,qoe_mode", ðqos->qoe_mode); if (res) { ETHQOSDBG("qoe_mode not in dtsi\n"); ethqos->qoe_mode = 0; } if (ethqos->qoe_mode) { res = of_property_read_u32(np, "qcom,qoe-queue", ðqos->qoe_vlan.rx_queue); if (res) { ETHQOSERR("qoe-queue not in dtsi for qoe_mode %u\n", ethqos->qoe_mode); ethqos->qoe_vlan.rx_queue = QMI_TAG_TX_CHANNEL; } res = of_property_read_u32(np, "qcom,qoe-vlan-offset", ðqos->qoe_vlan.vlan_offset); if (res) { ETHQOSERR("qoe-vlan-offset not in dtsi\n"); ethqos->qoe_vlan.vlan_offset = 0; } } } static const struct file_operations emac_fops = { .owner = THIS_MODULE, .read = ethqos_read_dev_emac, .write = ethqos_write_dev_emac, }; static int ethqos_create_emac_device_node(dev_t *emac_dev_t, struct cdev **emac_cdev, struct class **emac_class, char *emac_dev_node_name) { int ret; ret = alloc_chrdev_region(emac_dev_t, 0, 1, emac_dev_node_name); if (ret) { ETHQOSERR("alloc_chrdev_region error for node %s\n", emac_dev_node_name); goto alloc_chrdev1_region_fail; } *emac_cdev = cdev_alloc(); if (!*emac_cdev) { ret = -ENOMEM; ETHQOSERR("failed to alloc cdev\n"); goto fail_alloc_cdev; } cdev_init(*emac_cdev, &emac_fops); ret = cdev_add(*emac_cdev, *emac_dev_t, 1); if (ret < 0) { ETHQOSERR(":cdev_add err=%d\n", -ret); goto cdev1_add_fail; } *emac_class = class_create(THIS_MODULE, emac_dev_node_name); if (!*emac_class) { ret = -ENODEV; ETHQOSERR("failed to create class\n"); goto fail_create_class; } if (!device_create(*emac_class, NULL, *emac_dev_t, NULL, emac_dev_node_name)) { ret = -EINVAL; ETHQOSERR("failed to create device_create\n"); goto fail_create_device; } return 0; fail_create_device: class_destroy(*emac_class); fail_create_class: cdev_del(*emac_cdev); cdev1_add_fail: fail_alloc_cdev: unregister_chrdev_region(*emac_dev_t, 1); alloc_chrdev1_region_fail: return ret; } static void ethqos_get_cv2x_dt(struct qcom_ethqos *ethqos, struct device_node *np) { int res; res = of_property_read_u32(np, "qcom,cv2x_mode", ðqos->cv2x_mode); if (res) { ETHQOSDBG("cv2x_mode not in dtsi\n"); ethqos->cv2x_mode = CV2X_MODE_DISABLE; } if (ethqos->cv2x_mode != CV2X_MODE_DISABLE) { res = of_property_read_u32(np, "qcom,cv2x-queue", ðqos->cv2x_vlan.rx_queue); if (res) { ETHQOSERR("cv2x-queue not in dtsi for cv2x_mode %u\n", ethqos->cv2x_mode); ethqos->cv2x_vlan.rx_queue = CV2X_TAG_TX_CHANNEL; } res = of_property_read_u32(np, "qcom,cv2x-vlan-offset", ðqos->cv2x_vlan.vlan_offset); if (res) { ETHQOSERR("cv2x-vlan-offset not in dtsi\n"); ethqos->cv2x_vlan.vlan_offset = 1; } } } static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; Loading @@ -2351,7 +2585,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) struct resource *res; struct net_device *ndev; struct stmmac_priv *priv; int ret; int ret, i; if (of_device_is_compatible(pdev->dev.of_node, "qcom,emac-smmu-embedded")) Loading Loading @@ -2382,12 +2616,24 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos_init_reqgulators(ethqos); ethqos_init_gpio(ethqos); ethqos_get_qoe_dt(ethqos, np); ethqos_get_cv2x_dt(ethqos, np); plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed\n"); return PTR_ERR(plat_dat); } if (ethqos->cv2x_mode == CV2X_MODE_MDM || ethqos->cv2x_mode == CV2X_MODE_AP) { for (i = 0; i < plat_dat->rx_queues_to_use; i++) { if (plat_dat->rx_queues_cfg[i].pkt_route == PACKET_AVCPQ) plat_dat->rx_queues_cfg[i].pkt_route = 0; } } if (plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_WFQ || plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_DWRR) { ETHQOSERR("WFO and DWRR TX Algorithm is not supported\n"); Loading Loading @@ -2566,6 +2812,17 @@ static int qcom_ethqos_probe(struct platform_device *pdev) /*Set early eth parameters*/ ethqos_set_early_eth_param(priv, ethqos); } if (ethqos->cv2x_mode) for (i = 0; i < plat_dat->rx_queues_to_use; i++) priv->rx_queue[i].en_fep = true; if (ethqos->qoe_mode || ethqos->cv2x_mode) { ethqos_create_emac_device_node(ðqos->emac_dev_t, ðqos->emac_cdev, ðqos->emac_class, "emac"); } #ifdef CONFIG_ETH_IPA_OFFLOAD ethqos->ipa_enabled = true; priv->rx_queue[IPA_DMA_RX_CH].skip_sw = true; Loading drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +27 −0 Original line number Diff line number Diff line Loading @@ -398,6 +398,19 @@ enum current_phy_state { RGMII_IO_MACRO_CONFIG_RGWR(v);\ } while (0) enum CV2X_MODE { CV2X_MODE_DISABLE = 0x0, CV2X_MODE_MDM, CV2X_MODE_AP }; struct ethqos_vlan_info { u16 vlan_id; u32 vlan_offset; u32 rx_queue; bool available; }; struct ethqos_emac_por { unsigned int offset; unsigned int value; Loading Loading @@ -454,6 +467,10 @@ struct qcom_ethqos { struct cdev *avb_class_b_cdev; struct class *avb_class_b_class; dev_t emac_dev_t; struct cdev *emac_cdev; struct class *emac_class; unsigned long avb_class_a_intr_cnt; unsigned long avb_class_b_intr_cnt; struct dentry *debugfs_dir; Loading Loading @@ -503,6 +520,13 @@ struct qcom_ethqos { /* IO Macro parameters */ struct ethqos_io_macro io_macro; /* QMI over ethernet parameter */ u32 qoe_mode; struct ethqos_vlan_info qoe_vlan; u32 cv2x_mode; struct ethqos_vlan_info cv2x_vlan; unsigned char cv2x_dev_addr[ETH_ALEN]; }; struct pps_cfg { Loading Loading @@ -577,6 +601,9 @@ u16 dwmac_qcom_select_queue( #define IPA_DMA_TX_CH 0 #define IPA_DMA_RX_CH 0 #define CV2X_TAG_TX_CHANNEL 3 #define QMI_TAG_TX_CHANNEL 2 #define VLAN_TAG_UCP_SHIFT 13 #define CLASS_A_TRAFFIC_UCP 3 #define CLASS_A_TRAFFIC_TX_CHANNEL 3 Loading drivers/net/ethernet/stmicro/stmmac/dwmac4.h +18 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #define GMAC_PACKET_FILTER 0x00000008 #define GMAC_HASH_TAB_0_31 0x00000010 #define GMAC_HASH_TAB_32_63 0x00000014 #define GMAC_VLAN_CTRL_TAG 0x00000050 #define GMAC_VLAN_DATA_TAG 0x00000054 #define GMAC_RX_FLOW_CTRL 0x00000090 #define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) #define GMAC_TXQ_PRTY_MAP0 0x98 Loading @@ -43,6 +45,20 @@ #define GMAC_MDIO_DATA 0x00000204 #define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) #define GMAC_ADDR_LOW(reg) (0x304 + reg * 8) #define GMAC_MTL_RX_QMAP 0x00000c30 /*MAC VLAN CTRL Bit*/ #define GMAC_VLANTR_OB_MASK (0x1) #define GMAC_VLANTR_CT_MASKBIT BIT(1) #define GMAC_VLANTR_OFFSET_SHIFT 2 #define GMAC_VLANTR_VLAN_EN BIT(16) #define GMAC_VLANTR_VLAN_CMP BIT(17) #define GMAC_VLANTR_VLAN_CMP_DISABLE BIT(18) #define GMAC_VLANTR_DMA_CHAN_EN BIT(24) #define GMAC_VLANTR_DMA_CHAN_NUM 25 /*MTL Rx Queue Bit*/ #define GMAC_MTL_RXQ_DMACH BIT(4) /* RX Queues Routing */ #define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0) Loading Loading @@ -259,6 +275,8 @@ enum power_event { #define MTL_OP_MODE_RFA_SHIFT 8 #define MTL_OP_MODE_EHFC BIT(7) #define MTL_OP_MODE_FEP BIT(4) #define MTL_OP_MODE_FUP BIT(3) #define MTL_OP_MODE_RTC_MASK 0x18 #define MTL_OP_MODE_RTC_SHIFT 3 Loading drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +2 −0 Original line number Diff line number Diff line Loading @@ -699,6 +699,7 @@ static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x, static const struct stmmac_ops dwmac4_ops = { .core_init = dwmac4_core_init, .set_mac = stmmac_set_mac, .set_vlan = stmmac_set_vlan_filter_rx_queue, .rx_ipc = dwmac4_rx_ipc_enable, .rx_queue_enable = dwmac4_rx_queue_enable, .rx_queue_prio = dwmac4_rx_queue_priority, Loading Loading @@ -730,6 +731,7 @@ static const struct stmmac_ops dwmac4_ops = { static const struct stmmac_ops dwmac410_ops = { .core_init = dwmac4_core_init, .set_mac = stmmac_dwmac4_set_mac, .set_vlan = stmmac_set_vlan_filter_rx_queue, .rx_ipc = dwmac4_rx_ipc_enable, .rx_queue_enable = dwmac4_rx_queue_enable, .rx_queue_prio = dwmac4_rx_queue_priority, Loading Loading
drivers/net/ethernet/stmicro/stmmac/common.h +12 −0 Original line number Diff line number Diff line Loading @@ -472,16 +472,25 @@ struct stmmac_dma_ops { void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan); void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan); void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan); void (*enable_rx_fep)(void __iomem *ioaddr, bool en, u32 chan); }; struct mac_device_info; struct vlan_filter_info { u16 vlan_id; u32 vlan_offset; u32 rx_queue; }; /* Helpers to program the MAC core */ struct stmmac_ops { /* MAC core initialization */ void (*core_init)(struct mac_device_info *hw, struct net_device *dev); /* Enable the MAC RX/TX */ void (*set_mac)(void __iomem *ioaddr, bool enable); /* Enable the VLAN MAC configuration for DMA Queue*/ void (*set_vlan)(struct vlan_filter_info *vlan, void __iomem *ioaddr); /* Enable and verify that the IPC module is supported */ int (*rx_ipc)(struct mac_device_info *hw); /* Enable RX Queues */ Loading Loading @@ -623,6 +632,9 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, unsigned int high, unsigned int low); void stmmac_set_mac(void __iomem *ioaddr, bool enable); void stmmac_set_vlan_filter_rx_queue(struct vlan_filter_info *vlan, void __iomem *ioaddr); void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned int high, unsigned int low); void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, Loading
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +265 −8 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/rtnetlink.h> #include <linux/if_vlan.h> #include "stmmac.h" #include "stmmac_platform.h" #include "dwmac-qcom-ethqos.h" Loading Loading @@ -60,6 +62,7 @@ struct qcom_ethqos *pethqos; struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx = {0}; static unsigned char dev_addr[ETH_ALEN] = { 0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7}; static unsigned char config_dev_addr[ETH_ALEN] = {0}; void *ipc_stmmac_log_ctxt; void *ipc_stmmac_log_ctxt_low; Loading Loading @@ -110,13 +113,28 @@ u16 dwmac_qcom_select_queue( select_queue_fallback_t fallback) { u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; unsigned int eth_type, priority; unsigned int eth_type, priority, vlan_id; bool ipa_enabled = pethqos->ipa_enabled; /* Retrieve ETH type */ eth_type = dwmac_qcom_get_eth_type(skb->data); if (eth_type == ETH_P_TSN) { if (pethqos->cv2x_mode == CV2X_MODE_AP) { if (skb_vlan_tag_present(skb)) { vlan_id = skb_vlan_tag_get_id(skb); if (vlan_id == pethqos->cv2x_vlan.vlan_id) txqueue_select = CV2X_TAG_TX_CHANNEL; else if (vlan_id == pethqos->qoe_vlan.vlan_id) txqueue_select = QMI_TAG_TX_CHANNEL; else txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } else { txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED; } } else if (pethqos->cv2x_mode == CV2X_MODE_MDM) { txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL; } else if (eth_type == ETH_P_TSN) { /* Read VLAN priority field from skb->data */ priority = dwmac_qcom_get_vlan_ucp(skb->data); Loading @@ -140,11 +158,6 @@ u16 dwmac_qcom_select_queue( 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; } Loading Loading @@ -2341,6 +2354,227 @@ bool qcom_ethqos_ipa_enabled(void) return false; } static ssize_t ethqos_read_dev_emac(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { unsigned int len = 0; char *temp_buf; ssize_t ret_cnt = 0; ret_cnt = simple_read_from_buffer(buf, count, f_pos, temp_buf, len); return ret_cnt; } static ssize_t ethqos_write_dev_emac(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { unsigned char in_buf[300] = {0}; unsigned long ret; struct qcom_ethqos *ethqos = pethqos; struct stmmac_priv *priv = qcom_ethqos_get_priv(pethqos); struct vlan_filter_info vlan_filter_info; char mac_str[30] = {0}; char vlan_str[30] = {0}; char *prefix = NULL; u32 err; unsigned int number; if (sizeof(in_buf) < count) { ETHQOSERR("emac string is too long - count=%u\n", count); return -EFAULT; } memset(in_buf, 0, sizeof(in_buf)); ret = copy_from_user(in_buf, user_buf, count); if (ret) return -EFAULT; strlcpy(vlan_str, in_buf, sizeof(vlan_str)); ETHQOSINFO("emac string is %s\n", vlan_str); if (strnstr(vlan_str, "QOE", sizeof(vlan_str))) { ethqos->qoe_vlan.available = true; vlan_filter_info.vlan_id = ethqos->qoe_vlan.vlan_id; vlan_filter_info.rx_queue = ethqos->qoe_vlan.rx_queue; vlan_filter_info.vlan_offset = ethqos->qoe_vlan.vlan_offset; priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr); } if (strnstr(vlan_str, "qvlanid=", sizeof(vlan_str))) { prefix = strnchr(vlan_str, strlen(vlan_str), '='); ETHQOSINFO("vlanid data written is %s\n", prefix + 1); if (prefix) { err = kstrtouint(prefix + 1, 0, &number); if (!err) ethqos->qoe_vlan.vlan_id = number; } } if (strnstr(vlan_str, "Cv2X", strlen(vlan_str))) { ETHQOSDBG("Cv2X supported mode is %u\n", ethqos->cv2x_mode); ethqos->cv2x_vlan.available = true; vlan_filter_info.vlan_id = ethqos->cv2x_vlan.vlan_id; vlan_filter_info.rx_queue = ethqos->cv2x_vlan.rx_queue; vlan_filter_info.vlan_offset = ethqos->cv2x_vlan.vlan_offset; priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr); } if (strnstr(vlan_str, "cvlanid=", strlen(vlan_str))) { prefix = strnchr(vlan_str, strlen(vlan_str), '='); ETHQOSDBG("Cv2X vlanid data written is %s\n", prefix + 1); if (prefix) { err = kstrtouint(prefix + 1, 0, &number); if (!err) ethqos->cv2x_vlan.vlan_id = number; } } if (strnstr(in_buf, "cmac_id=", strlen(in_buf))) { prefix = strnchr(in_buf, strlen(in_buf), '='); if (prefix) { memcpy(mac_str, (char *)prefix + 1, 30); if (!mac_pton(mac_str, config_dev_addr)) { ETHQOSERR("Invalid mac addr in /dev/emac\n"); return count; } if (!is_valid_ether_addr(config_dev_addr)) { ETHQOSERR("Invalid/Multcast mac addr found\n"); return count; } ether_addr_copy(dev_addr, config_dev_addr); memcpy(ethqos->cv2x_dev_addr, dev_addr, ETH_ALEN); } } return count; } static void ethqos_get_qoe_dt(struct qcom_ethqos *ethqos, struct device_node *np) { int res; res = of_property_read_u32(np, "qcom,qoe_mode", ðqos->qoe_mode); if (res) { ETHQOSDBG("qoe_mode not in dtsi\n"); ethqos->qoe_mode = 0; } if (ethqos->qoe_mode) { res = of_property_read_u32(np, "qcom,qoe-queue", ðqos->qoe_vlan.rx_queue); if (res) { ETHQOSERR("qoe-queue not in dtsi for qoe_mode %u\n", ethqos->qoe_mode); ethqos->qoe_vlan.rx_queue = QMI_TAG_TX_CHANNEL; } res = of_property_read_u32(np, "qcom,qoe-vlan-offset", ðqos->qoe_vlan.vlan_offset); if (res) { ETHQOSERR("qoe-vlan-offset not in dtsi\n"); ethqos->qoe_vlan.vlan_offset = 0; } } } static const struct file_operations emac_fops = { .owner = THIS_MODULE, .read = ethqos_read_dev_emac, .write = ethqos_write_dev_emac, }; static int ethqos_create_emac_device_node(dev_t *emac_dev_t, struct cdev **emac_cdev, struct class **emac_class, char *emac_dev_node_name) { int ret; ret = alloc_chrdev_region(emac_dev_t, 0, 1, emac_dev_node_name); if (ret) { ETHQOSERR("alloc_chrdev_region error for node %s\n", emac_dev_node_name); goto alloc_chrdev1_region_fail; } *emac_cdev = cdev_alloc(); if (!*emac_cdev) { ret = -ENOMEM; ETHQOSERR("failed to alloc cdev\n"); goto fail_alloc_cdev; } cdev_init(*emac_cdev, &emac_fops); ret = cdev_add(*emac_cdev, *emac_dev_t, 1); if (ret < 0) { ETHQOSERR(":cdev_add err=%d\n", -ret); goto cdev1_add_fail; } *emac_class = class_create(THIS_MODULE, emac_dev_node_name); if (!*emac_class) { ret = -ENODEV; ETHQOSERR("failed to create class\n"); goto fail_create_class; } if (!device_create(*emac_class, NULL, *emac_dev_t, NULL, emac_dev_node_name)) { ret = -EINVAL; ETHQOSERR("failed to create device_create\n"); goto fail_create_device; } return 0; fail_create_device: class_destroy(*emac_class); fail_create_class: cdev_del(*emac_cdev); cdev1_add_fail: fail_alloc_cdev: unregister_chrdev_region(*emac_dev_t, 1); alloc_chrdev1_region_fail: return ret; } static void ethqos_get_cv2x_dt(struct qcom_ethqos *ethqos, struct device_node *np) { int res; res = of_property_read_u32(np, "qcom,cv2x_mode", ðqos->cv2x_mode); if (res) { ETHQOSDBG("cv2x_mode not in dtsi\n"); ethqos->cv2x_mode = CV2X_MODE_DISABLE; } if (ethqos->cv2x_mode != CV2X_MODE_DISABLE) { res = of_property_read_u32(np, "qcom,cv2x-queue", ðqos->cv2x_vlan.rx_queue); if (res) { ETHQOSERR("cv2x-queue not in dtsi for cv2x_mode %u\n", ethqos->cv2x_mode); ethqos->cv2x_vlan.rx_queue = CV2X_TAG_TX_CHANNEL; } res = of_property_read_u32(np, "qcom,cv2x-vlan-offset", ðqos->cv2x_vlan.vlan_offset); if (res) { ETHQOSERR("cv2x-vlan-offset not in dtsi\n"); ethqos->cv2x_vlan.vlan_offset = 1; } } } static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; Loading @@ -2351,7 +2585,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) struct resource *res; struct net_device *ndev; struct stmmac_priv *priv; int ret; int ret, i; if (of_device_is_compatible(pdev->dev.of_node, "qcom,emac-smmu-embedded")) Loading Loading @@ -2382,12 +2616,24 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos_init_reqgulators(ethqos); ethqos_init_gpio(ethqos); ethqos_get_qoe_dt(ethqos, np); ethqos_get_cv2x_dt(ethqos, np); plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed\n"); return PTR_ERR(plat_dat); } if (ethqos->cv2x_mode == CV2X_MODE_MDM || ethqos->cv2x_mode == CV2X_MODE_AP) { for (i = 0; i < plat_dat->rx_queues_to_use; i++) { if (plat_dat->rx_queues_cfg[i].pkt_route == PACKET_AVCPQ) plat_dat->rx_queues_cfg[i].pkt_route = 0; } } if (plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_WFQ || plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_DWRR) { ETHQOSERR("WFO and DWRR TX Algorithm is not supported\n"); Loading Loading @@ -2566,6 +2812,17 @@ static int qcom_ethqos_probe(struct platform_device *pdev) /*Set early eth parameters*/ ethqos_set_early_eth_param(priv, ethqos); } if (ethqos->cv2x_mode) for (i = 0; i < plat_dat->rx_queues_to_use; i++) priv->rx_queue[i].en_fep = true; if (ethqos->qoe_mode || ethqos->cv2x_mode) { ethqos_create_emac_device_node(ðqos->emac_dev_t, ðqos->emac_cdev, ðqos->emac_class, "emac"); } #ifdef CONFIG_ETH_IPA_OFFLOAD ethqos->ipa_enabled = true; priv->rx_queue[IPA_DMA_RX_CH].skip_sw = true; Loading
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +27 −0 Original line number Diff line number Diff line Loading @@ -398,6 +398,19 @@ enum current_phy_state { RGMII_IO_MACRO_CONFIG_RGWR(v);\ } while (0) enum CV2X_MODE { CV2X_MODE_DISABLE = 0x0, CV2X_MODE_MDM, CV2X_MODE_AP }; struct ethqos_vlan_info { u16 vlan_id; u32 vlan_offset; u32 rx_queue; bool available; }; struct ethqos_emac_por { unsigned int offset; unsigned int value; Loading Loading @@ -454,6 +467,10 @@ struct qcom_ethqos { struct cdev *avb_class_b_cdev; struct class *avb_class_b_class; dev_t emac_dev_t; struct cdev *emac_cdev; struct class *emac_class; unsigned long avb_class_a_intr_cnt; unsigned long avb_class_b_intr_cnt; struct dentry *debugfs_dir; Loading Loading @@ -503,6 +520,13 @@ struct qcom_ethqos { /* IO Macro parameters */ struct ethqos_io_macro io_macro; /* QMI over ethernet parameter */ u32 qoe_mode; struct ethqos_vlan_info qoe_vlan; u32 cv2x_mode; struct ethqos_vlan_info cv2x_vlan; unsigned char cv2x_dev_addr[ETH_ALEN]; }; struct pps_cfg { Loading Loading @@ -577,6 +601,9 @@ u16 dwmac_qcom_select_queue( #define IPA_DMA_TX_CH 0 #define IPA_DMA_RX_CH 0 #define CV2X_TAG_TX_CHANNEL 3 #define QMI_TAG_TX_CHANNEL 2 #define VLAN_TAG_UCP_SHIFT 13 #define CLASS_A_TRAFFIC_UCP 3 #define CLASS_A_TRAFFIC_TX_CHANNEL 3 Loading
drivers/net/ethernet/stmicro/stmmac/dwmac4.h +18 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #define GMAC_PACKET_FILTER 0x00000008 #define GMAC_HASH_TAB_0_31 0x00000010 #define GMAC_HASH_TAB_32_63 0x00000014 #define GMAC_VLAN_CTRL_TAG 0x00000050 #define GMAC_VLAN_DATA_TAG 0x00000054 #define GMAC_RX_FLOW_CTRL 0x00000090 #define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) #define GMAC_TXQ_PRTY_MAP0 0x98 Loading @@ -43,6 +45,20 @@ #define GMAC_MDIO_DATA 0x00000204 #define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) #define GMAC_ADDR_LOW(reg) (0x304 + reg * 8) #define GMAC_MTL_RX_QMAP 0x00000c30 /*MAC VLAN CTRL Bit*/ #define GMAC_VLANTR_OB_MASK (0x1) #define GMAC_VLANTR_CT_MASKBIT BIT(1) #define GMAC_VLANTR_OFFSET_SHIFT 2 #define GMAC_VLANTR_VLAN_EN BIT(16) #define GMAC_VLANTR_VLAN_CMP BIT(17) #define GMAC_VLANTR_VLAN_CMP_DISABLE BIT(18) #define GMAC_VLANTR_DMA_CHAN_EN BIT(24) #define GMAC_VLANTR_DMA_CHAN_NUM 25 /*MTL Rx Queue Bit*/ #define GMAC_MTL_RXQ_DMACH BIT(4) /* RX Queues Routing */ #define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0) Loading Loading @@ -259,6 +275,8 @@ enum power_event { #define MTL_OP_MODE_RFA_SHIFT 8 #define MTL_OP_MODE_EHFC BIT(7) #define MTL_OP_MODE_FEP BIT(4) #define MTL_OP_MODE_FUP BIT(3) #define MTL_OP_MODE_RTC_MASK 0x18 #define MTL_OP_MODE_RTC_SHIFT 3 Loading
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +2 −0 Original line number Diff line number Diff line Loading @@ -699,6 +699,7 @@ static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x, static const struct stmmac_ops dwmac4_ops = { .core_init = dwmac4_core_init, .set_mac = stmmac_set_mac, .set_vlan = stmmac_set_vlan_filter_rx_queue, .rx_ipc = dwmac4_rx_ipc_enable, .rx_queue_enable = dwmac4_rx_queue_enable, .rx_queue_prio = dwmac4_rx_queue_priority, Loading Loading @@ -730,6 +731,7 @@ static const struct stmmac_ops dwmac4_ops = { static const struct stmmac_ops dwmac410_ops = { .core_init = dwmac4_core_init, .set_mac = stmmac_dwmac4_set_mac, .set_vlan = stmmac_set_vlan_filter_rx_queue, .rx_ipc = dwmac4_rx_ipc_enable, .rx_queue_enable = dwmac4_rx_queue_enable, .rx_queue_prio = dwmac4_rx_queue_priority, Loading