diff mbox series

[net-next] net: stmmac: qcom-ethqos: Add sysfs nodes for qcom ethqos

Message ID 20231204084854.31543-1-quic_snehshah@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series [net-next] net: stmmac: qcom-ethqos: Add sysfs nodes for qcom ethqos | expand

Commit Message

Sneh Shah Dec. 4, 2023, 8:48 a.m. UTC
Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.

Signed-off-by: Sneh Shah <quic_snehshah@quicinc.com>
---
 .../stmicro/stmmac/dwmac-qcom-ethqos.c        | 216 +++++++++++++++++-
 1 file changed, 215 insertions(+), 1 deletion(-)

Comments

Bjorn Andersson Dec. 4, 2023, 4:31 p.m. UTC | #1
On Mon, Dec 04, 2023 at 02:18:54PM +0530, Sneh Shah wrote:
> Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
> GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.
> 

Perhaps I'm just not familiar enough with the details of stmmac, but can
you please describe what PVM and GVM is?

Regards,
Bjorn

> Signed-off-by: Sneh Shah <quic_snehshah@quicinc.com>
> ---
>  .../stmicro/stmmac/dwmac-qcom-ethqos.c        | 216 +++++++++++++++++-
>  1 file changed, 215 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> index d3bf42d0fceb..ea89045a90a1 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> @@ -109,6 +109,8 @@ struct qcom_ethqos {
>  	unsigned int num_por;
>  	bool rgmii_config_loopback_en;
>  	bool has_emac_ge_3;
> +	int gvm_vlan_prio;
> +	int gvm_queue;
>  };
>  
>  static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset)
> @@ -710,6 +712,214 @@ static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
>  	netdev_dbg(priv->dev, "PTP rate %d\n", plat_dat->clk_ptp_rate);
>  }
>  
> +static ssize_t gvm_vlan_routing_store(struct device *dev,
> +				      struct device_attribute *attr,
> +				      const char *user_buf, size_t size)
> +{
> +	struct net_device *netdev = to_net_dev(dev);
> +	struct stmmac_priv *priv;
> +	struct qcom_ethqos *ethqos;
> +	u32 prio;
> +	s8 input = 0;
> +
> +	if (!netdev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = netdev_priv(netdev);
> +	if (!priv) {
> +		pr_err("priv is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	ethqos = priv->plat->bsp_priv;
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	if (kstrtos8(user_buf, 0, &input)) {
> +		pr_err("Error in reading option from user\n");
> +		return -EINVAL;
> +	}
> +
> +	if (input < 1 || input > 7) {
> +		pr_err("Invalid option set by user\n");
> +		return -EINVAL;
> +	}
> +
> +	if (input == ethqos->gvm_vlan_prio)
> +		pr_err("No effect as duplicate input\n");
> +
> +	ethqos->gvm_vlan_prio = input;
> +	prio  = 1 << input;
> +
> +	stmmac_rx_queue_prio(priv, priv->hw, prio, ethqos->gvm_queue);
> +
> +	return size;
> +}
> +
> +static ssize_t gvm_queue_mapping_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *user_buf, size_t size)
> +{
> +	struct net_device *netdev = to_net_dev(dev);
> +	struct stmmac_priv *priv;
> +	struct qcom_ethqos *ethqos;
> +	u32 prio;
> +	s8 input = 0;
> +
> +	if (!netdev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = netdev_priv(netdev);
> +	if (!priv) {
> +		pr_err("priv is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	ethqos = priv->plat->bsp_priv;
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	if (kstrtos8(user_buf, 0, &input)) {
> +		pr_err("Error in reading option from user\n");
> +		return -EINVAL;
> +	}
> +
> +	if (input == ethqos->gvm_queue)
> +		pr_err("No effect as duplicate input\n");
> +
> +	ethqos->gvm_queue = input;
> +	prio  = 1 << input;
> +
> +	return size;
> +}
> +
> +static ssize_t gvm_queue_mapping_show(struct device *dev,
> +				      struct device_attribute *attr, char *user_buf)
> +{
> +	struct net_device *netdev = to_net_dev(dev);
> +	struct stmmac_priv *priv;
> +	struct qcom_ethqos *ethqos;
> +
> +	if (!netdev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = netdev_priv(netdev);
> +	if (!priv) {
> +		pr_err("priv is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	ethqos = priv->plat->bsp_priv;
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	return scnprintf(user_buf, 256, "%d\n", ethqos->gvm_queue);
> +}
> +
> +static ssize_t gvm_vlan_routing_show(struct device *dev,
> +				     struct device_attribute *attr, char *user_buf)
> +{
> +	struct net_device *netdev = to_net_dev(dev);
> +	struct stmmac_priv *priv;
> +	struct qcom_ethqos *ethqos;
> +
> +	if (!netdev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = netdev_priv(netdev);
> +	if (!priv) {
> +		pr_err("priv is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	ethqos = priv->plat->bsp_priv;
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	return scnprintf(user_buf, 256, "%d\n", ethqos->gvm_vlan_prio);
> +}
> +
> +static DEVICE_ATTR_RW(gvm_queue_mapping);
> +
> +static DEVICE_ATTR_RW(gvm_vlan_routing);
> +
> +static int ethqos_remove_sysfs(struct qcom_ethqos *ethqos)
> +{
> +	struct net_device *net_dev;
> +
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	net_dev = platform_get_drvdata(ethqos->pdev);
> +	if (!net_dev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	sysfs_remove_file(&net_dev->dev.kobj,
> +			  &dev_attr_gvm_queue_mapping.attr);
> +	sysfs_remove_file(&net_dev->dev.kobj,
> +			  &dev_attr_gvm_vlan_routing.attr);
> +
> +	return 0;
> +}
> +
> +static int ethqos_create_sysfs(struct qcom_ethqos *ethqos)
> +{
> +	int ret;
> +	struct net_device *net_dev;
> +
> +	if (!ethqos) {
> +		pr_err("ethqos is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	net_dev = platform_get_drvdata(ethqos->pdev);
> +	if (!net_dev) {
> +		pr_err("netdev is NULL\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = sysfs_create_file(&net_dev->dev.kobj,
> +				&dev_attr_gvm_queue_mapping.attr);
> +	if (ret) {
> +		pr_err("unable to create passthrough_en sysfs node\n");
> +		goto fail;
> +	}
> +
> +	ret = sysfs_create_file(&net_dev->dev.kobj,
> +				&dev_attr_gvm_vlan_routing.attr);
> +	if (ret) {
> +		pr_err("unable to create cv2x_priority sysfs node\n");
> +		goto fail;
> +	}
> +
> +	return ret;
> +
> +fail:
> +	ethqos_remove_sysfs(ethqos);
> +
> +	return ret;
> +}
> +
>  static int qcom_ethqos_probe(struct platform_device *pdev)
>  {
>  	struct device_node *np = pdev->dev.of_node;
> @@ -812,7 +1022,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  		plat_dat->serdes_powerdown  = qcom_ethqos_serdes_powerdown;
>  	}
>  
> -	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
> +	ret = devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
> +	if (ret)
> +		return ret;
> +
> +	return ethqos_create_sysfs(ethqos);
>  }
>  
>  static const struct of_device_id qcom_ethqos_match[] = {
> -- 
> 2.17.1
> 
>
kernel test robot Dec. 5, 2023, 5:53 a.m. UTC | #2
Hi Sneh,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Sneh-Shah/net-stmmac-qcom-ethqos-Add-sysfs-nodes-for-qcom-ethqos/20231204-165232
base:   net-next/main
patch link:    https://lore.kernel.org/r/20231204084854.31543-1-quic_snehshah%40quicinc.com
patch subject: [PATCH net-next] net: stmmac: qcom-ethqos: Add sysfs nodes for qcom ethqos
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20231205/202312051347.L3L2pNLv-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231205/202312051347.L3L2pNLv-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312051347.L3L2pNLv-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c: In function 'gvm_queue_mapping_store':
>> drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c:770:13: warning: variable 'prio' set but not used [-Wunused-but-set-variable]
     770 |         u32 prio;
         |             ^~~~


vim +/prio +770 drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c

   762	
   763	static ssize_t gvm_queue_mapping_store(struct device *dev,
   764					       struct device_attribute *attr,
   765					       const char *user_buf, size_t size)
   766	{
   767		struct net_device *netdev = to_net_dev(dev);
   768		struct stmmac_priv *priv;
   769		struct qcom_ethqos *ethqos;
 > 770		u32 prio;
   771		s8 input = 0;
   772	
   773		if (!netdev) {
   774			pr_err("netdev is NULL\n");
   775			return -EINVAL;
   776		}
   777	
   778		priv = netdev_priv(netdev);
   779		if (!priv) {
   780			pr_err("priv is NULL\n");
   781			return -EINVAL;
   782		}
   783	
   784		ethqos = priv->plat->bsp_priv;
   785		if (!ethqos) {
   786			pr_err("ethqos is NULL\n");
   787			return -EINVAL;
   788		}
   789	
   790		if (kstrtos8(user_buf, 0, &input)) {
   791			pr_err("Error in reading option from user\n");
   792			return -EINVAL;
   793		}
   794	
   795		if (input == ethqos->gvm_queue)
   796			pr_err("No effect as duplicate input\n");
   797	
   798		ethqos->gvm_queue = input;
   799		prio  = 1 << input;
   800	
   801		return size;
   802	}
   803
Andrew Lunn Dec. 5, 2023, 3:08 p.m. UTC | #3
On Mon, Dec 04, 2023 at 02:18:54PM +0530, Sneh Shah wrote:
> Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
> GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.

Adding files in /sysfs has ~0 chance of being accepted.

As requested, please explain what all these different hardware blocks
are, and what you are trying to achieve. We can then recommend the
correct interface.

    Andrew

---
pw-bot: cr
Sneh Shah Dec. 6, 2023, 11:47 a.m. UTC | #4
On 12/5/2023 8:38 PM, Andrew Lunn wrote:
> On Mon, Dec 04, 2023 at 02:18:54PM +0530, Sneh Shah wrote:
>> Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
>> GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.
> 
> Adding files in /sysfs has ~0 chance of being accepted.
> 
> As requested, please explain what all these different hardware blocks
> are, and what you are trying to achieve. We can then recommend the
> correct interface.
> 
>     Andrew
> 
> ---
> pw-bot: cr

We have multiVM Architecture here. PVM  will have stmmac running with 4 Rx Tx queues. stmmac in PVM is responsible to configure whole ethernet HW MAC/DMA/MTL ( including clocks, regulators and other core bsp elements).
In GVM we have thin Ethernet driver, which is responsible to configure and manage only 1 Rx/TX queue, i.e 5th Rx/Tx ethernet queue. GVM can't access any other resisters apart from this 5th queue specific MTL and DMA registers.

We need to route vlan traffic of a specific Priority to GVM Queue (Ethernet queue 5) via programming a MAC register. The MAC register is not accessible in GVM and has to be programmed from PVM. stmmac already has TC OPS to program this routing via vlan priority. However, as PVM has only 4 queues enabled, TC tool will not take 5th queue as input. Hence, these nodes were added to conifure the MAC register to route specific vlan packets to 5th queue in GVM.

Note: The queues mentioned above are HW MTL Queues and DMA Channels. The routing can be done in the HW itself based on vlan pcp before the packets reach to driver.
Andrew Lunn Dec. 6, 2023, 1:52 p.m. UTC | #5
On Wed, Dec 06, 2023 at 05:17:25PM +0530, Sneh Shah wrote:
> 
> 
> On 12/5/2023 8:38 PM, Andrew Lunn wrote:
> > On Mon, Dec 04, 2023 at 02:18:54PM +0530, Sneh Shah wrote:
> >> Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
> >> GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.
> > 
> > Adding files in /sysfs has ~0 chance of being accepted.
> > 
> > As requested, please explain what all these different hardware blocks
> > are, and what you are trying to achieve. We can then recommend the
> > correct interface.
> > 
> >     Andrew
> > 
> > ---
> > pw-bot: cr
> 

> We have multiVM Architecture here. PVM will have stmmac running with
> 4 Rx Tx queues. stmmac in PVM is responsible to configure whole
> ethernet HW MAC/DMA/MTL ( including clocks, regulators and other
> core bsp elements).

Please remember that stmmac is mostly used in embedded systems. People
used to embedded systems generally don't know virtual machine
terminology. So please spell out what PBM, GVM, etc mean.

> In GVM we have thin Ethernet driver, which is responsible to
> configure and manage only 1 Rx/TX queue, i.e 5th Rx/Tx ethernet
> queue. GVM can't access any other resisters apart from this 5th
> queue specific MTL and DMA registers.
 
> We need to route vlan traffic of a specific Priority to GVM Queue
> (Ethernet queue 5) via programming a MAC register. The MAC register
> is not accessible in GVM and has to be programmed from PVM. stmmac
> already has TC OPS to program this routing via vlan
> priority. However, as PVM has only 4 queues enabled, TC tool will
> not take 5th queue as input. Hence, these nodes were added to
> conifure the MAC register to route specific vlan packets to 5th
> queue in GVM.
 
> Note: The queues mentioned above are HW MTL Queues and DMA
> Channels. The routing can be done in the HW itself based on vlan pcp
> before the packets reach to driver.

Is the normal way you would do this is like this:

tc qdisc add dev eth1 parent root handle 100 \
mqprio num_tc 4 \
map 0 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 \
queues 1@0 1@1 1@2 1@3 \
hw 1

But you are saying that you cannot extend this to 5 queues?

    Andrew
Sneh Shah Dec. 8, 2023, 6:28 a.m. UTC | #6
On 12/6/2023 7:22 PM, Andrew Lunn wrote:
> On Wed, Dec 06, 2023 at 05:17:25PM +0530, Sneh Shah wrote:
>>
>>
>> On 12/5/2023 8:38 PM, Andrew Lunn wrote:
>>> On Mon, Dec 04, 2023 at 02:18:54PM +0530, Sneh Shah wrote:
>>>> Add sysfs nodes to conifigure routing of specific vlan id to GVM queue.
>>>> GVM queue is not exposed to PVM stmmac, so TC ops can't configure routing.
>>>
>>> Adding files in /sysfs has ~0 chance of being accepted.
>>>
>>> As requested, please explain what all these different hardware blocks
>>> are, and what you are trying to achieve. We can then recommend the
>>> correct interface.
>>>
>>>     Andrew
>>>
>>> ---
>>> pw-bot: cr
>>
> 
>> We have multiVM Architecture here. PVM will have stmmac running with
>> 4 Rx Tx queues. stmmac in PVM is responsible to configure whole
>> ethernet HW MAC/DMA/MTL ( including clocks, regulators and other
>> core bsp elements).
> 
> Please remember that stmmac is mostly used in embedded systems. People
> used to embedded systems generally don't know virtual machine
> terminology. So please spell out what PBM, GVM, etc mean.
> 
>> In GVM we have thin Ethernet driver, which is responsible to
>> configure and manage only 1 Rx/TX queue, i.e 5th Rx/Tx ethernet
>> queue. GVM can't access any other resisters apart from this 5th
>> queue specific MTL and DMA registers.
>  
>> We need to route vlan traffic of a specific Priority to GVM Queue
>> (Ethernet queue 5) via programming a MAC register. The MAC register
>> is not accessible in GVM and has to be programmed from PVM. stmmac
>> already has TC OPS to program this routing via vlan
>> priority. However, as PVM has only 4 queues enabled, TC tool will
>> not take 5th queue as input. Hence, these nodes were added to
>> conifure the MAC register to route specific vlan packets to 5th
>> queue in GVM.
>  
>> Note: The queues mentioned above are HW MTL Queues and DMA
>> Channels. The routing can be done in the HW itself based on vlan pcp
>> before the packets reach to driver.
> 
> Is the normal way you would do this is like this:
> 
> tc qdisc add dev eth1 parent root handle 100 \
> mqprio num_tc 4 \
> map 0 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 \
> queues 1@0 1@1 1@2 1@3 \
> hw 1
> 
> But you are saying that you cannot extend this to 5 queues?
> 
>     Andrew

Yes this can't extend to 5 queues. Because, stmmac in primary virtual machine will only have 4 netdev queues. So TC won't take input for 5th queue.
Andrew Lunn Dec. 13, 2023, 9:54 a.m. UTC | #7
> >> We need to route vlan traffic of a specific Priority to GVM Queue
> >> (Ethernet queue 5) via programming a MAC register. The MAC register
> >> is not accessible in GVM and has to be programmed from PVM. stmmac
> >> already has TC OPS to program this routing via vlan
> >> priority. However, as PVM has only 4 queues enabled, TC tool will
> >> not take 5th queue as input. Hence, these nodes were added to
> >> conifure the MAC register to route specific vlan packets to 5th
> >> queue in GVM.
> >  
> >> Note: The queues mentioned above are HW MTL Queues and DMA
> >> Channels. The routing can be done in the HW itself based on vlan pcp
> >> before the packets reach to driver.
> > 
> > Is the normal way you would do this is like this:
> > 
> > tc qdisc add dev eth1 parent root handle 100 \
> > mqprio num_tc 4 \
> > map 0 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 \
> > queues 1@0 1@1 1@2 1@3 \
> > hw 1
> > 
> > But you are saying that you cannot extend this to 5 queues?
> > 
> >     Andrew
> 

> Yes this can't extend to 5 queues. Because, stmmac in primary
> virtual machine will only have 4 netdev queues. So TC won't take
> input for 5th queue.

I still don't understand your architecture. How can you have 5 queues
if the physical hardware only has 4?

Is there any documentation for all this? Any datasheet?

   Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index d3bf42d0fceb..ea89045a90a1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -109,6 +109,8 @@  struct qcom_ethqos {
 	unsigned int num_por;
 	bool rgmii_config_loopback_en;
 	bool has_emac_ge_3;
+	int gvm_vlan_prio;
+	int gvm_queue;
 };
 
 static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset)
@@ -710,6 +712,214 @@  static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
 	netdev_dbg(priv->dev, "PTP rate %d\n", plat_dat->clk_ptp_rate);
 }
 
+static ssize_t gvm_vlan_routing_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *user_buf, size_t size)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct stmmac_priv *priv;
+	struct qcom_ethqos *ethqos;
+	u32 prio;
+	s8 input = 0;
+
+	if (!netdev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	priv = netdev_priv(netdev);
+	if (!priv) {
+		pr_err("priv is NULL\n");
+		return -EINVAL;
+	}
+
+	ethqos = priv->plat->bsp_priv;
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	if (kstrtos8(user_buf, 0, &input)) {
+		pr_err("Error in reading option from user\n");
+		return -EINVAL;
+	}
+
+	if (input < 1 || input > 7) {
+		pr_err("Invalid option set by user\n");
+		return -EINVAL;
+	}
+
+	if (input == ethqos->gvm_vlan_prio)
+		pr_err("No effect as duplicate input\n");
+
+	ethqos->gvm_vlan_prio = input;
+	prio  = 1 << input;
+
+	stmmac_rx_queue_prio(priv, priv->hw, prio, ethqos->gvm_queue);
+
+	return size;
+}
+
+static ssize_t gvm_queue_mapping_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *user_buf, size_t size)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct stmmac_priv *priv;
+	struct qcom_ethqos *ethqos;
+	u32 prio;
+	s8 input = 0;
+
+	if (!netdev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	priv = netdev_priv(netdev);
+	if (!priv) {
+		pr_err("priv is NULL\n");
+		return -EINVAL;
+	}
+
+	ethqos = priv->plat->bsp_priv;
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	if (kstrtos8(user_buf, 0, &input)) {
+		pr_err("Error in reading option from user\n");
+		return -EINVAL;
+	}
+
+	if (input == ethqos->gvm_queue)
+		pr_err("No effect as duplicate input\n");
+
+	ethqos->gvm_queue = input;
+	prio  = 1 << input;
+
+	return size;
+}
+
+static ssize_t gvm_queue_mapping_show(struct device *dev,
+				      struct device_attribute *attr, char *user_buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct stmmac_priv *priv;
+	struct qcom_ethqos *ethqos;
+
+	if (!netdev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	priv = netdev_priv(netdev);
+	if (!priv) {
+		pr_err("priv is NULL\n");
+		return -EINVAL;
+	}
+
+	ethqos = priv->plat->bsp_priv;
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	return scnprintf(user_buf, 256, "%d\n", ethqos->gvm_queue);
+}
+
+static ssize_t gvm_vlan_routing_show(struct device *dev,
+				     struct device_attribute *attr, char *user_buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct stmmac_priv *priv;
+	struct qcom_ethqos *ethqos;
+
+	if (!netdev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	priv = netdev_priv(netdev);
+	if (!priv) {
+		pr_err("priv is NULL\n");
+		return -EINVAL;
+	}
+
+	ethqos = priv->plat->bsp_priv;
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	return scnprintf(user_buf, 256, "%d\n", ethqos->gvm_vlan_prio);
+}
+
+static DEVICE_ATTR_RW(gvm_queue_mapping);
+
+static DEVICE_ATTR_RW(gvm_vlan_routing);
+
+static int ethqos_remove_sysfs(struct qcom_ethqos *ethqos)
+{
+	struct net_device *net_dev;
+
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	net_dev = platform_get_drvdata(ethqos->pdev);
+	if (!net_dev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	sysfs_remove_file(&net_dev->dev.kobj,
+			  &dev_attr_gvm_queue_mapping.attr);
+	sysfs_remove_file(&net_dev->dev.kobj,
+			  &dev_attr_gvm_vlan_routing.attr);
+
+	return 0;
+}
+
+static int ethqos_create_sysfs(struct qcom_ethqos *ethqos)
+{
+	int ret;
+	struct net_device *net_dev;
+
+	if (!ethqos) {
+		pr_err("ethqos is NULL\n");
+		return -EINVAL;
+	}
+
+	net_dev = platform_get_drvdata(ethqos->pdev);
+	if (!net_dev) {
+		pr_err("netdev is NULL\n");
+		return -EINVAL;
+	}
+
+	ret = sysfs_create_file(&net_dev->dev.kobj,
+				&dev_attr_gvm_queue_mapping.attr);
+	if (ret) {
+		pr_err("unable to create passthrough_en sysfs node\n");
+		goto fail;
+	}
+
+	ret = sysfs_create_file(&net_dev->dev.kobj,
+				&dev_attr_gvm_vlan_routing.attr);
+	if (ret) {
+		pr_err("unable to create cv2x_priority sysfs node\n");
+		goto fail;
+	}
+
+	return ret;
+
+fail:
+	ethqos_remove_sysfs(ethqos);
+
+	return ret;
+}
+
 static int qcom_ethqos_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -812,7 +1022,11 @@  static int qcom_ethqos_probe(struct platform_device *pdev)
 		plat_dat->serdes_powerdown  = qcom_ethqos_serdes_powerdown;
 	}
 
-	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
+	ret = devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
+	if (ret)
+		return ret;
+
+	return ethqos_create_sysfs(ethqos);
 }
 
 static const struct of_device_id qcom_ethqos_match[] = {