]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
net: stmmac: fix rx queue priority assignment
authorPiotr Wejman <piotrwejman90@gmail.com>
Mon, 1 Apr 2024 19:22:39 +0000 (21:22 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Apr 2024 02:22:25 +0000 (19:22 -0700)
The driver should ensure that same priority is not mapped to multiple
rx queues. From DesignWare Cores Ethernet Quality-of-Service
Databook, section 17.1.29 MAC_RxQ_Ctrl2:
"[...]The software must ensure that the content of this field is
mutually exclusive to the PSRQ fields for other queues, that is,
the same priority is not mapped to multiple Rx queues[...]"

Previously rx_queue_priority() function was:
- clearing all priorities from a queue
- adding new priorities to that queue
After this patch it will:
- first assign new priorities to a queue
- then remove those priorities from all other queues
- keep other priorities previously assigned to that queue

Fixes: a8f5102af2a7 ("net: stmmac: TX and RX queue priority configuration")
Fixes: 2142754f8b9c ("net: stmmac: Add MAC related callbacks for XGMAC2")
Signed-off-by: Piotr Wejman <piotrwejman90@gmail.com>
Link: https://lore.kernel.org/r/20240401192239.33942-1-piotrwejman90@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c

index 6b6d0de0961975133d9990a5c296c916ecd00491..cef25efbdff99fdc07a313ab678869e83c85f79e 100644 (file)
@@ -92,19 +92,41 @@ static void dwmac4_rx_queue_priority(struct mac_device_info *hw,
                                     u32 prio, u32 queue)
 {
        void __iomem *ioaddr = hw->pcsr;
-       u32 base_register;
-       u32 value;
+       u32 clear_mask = 0;
+       u32 ctrl2, ctrl3;
+       int i;
 
-       base_register = (queue < 4) ? GMAC_RXQ_CTRL2 : GMAC_RXQ_CTRL3;
-       if (queue >= 4)
-               queue -= 4;
+       ctrl2 = readl(ioaddr + GMAC_RXQ_CTRL2);
+       ctrl3 = readl(ioaddr + GMAC_RXQ_CTRL3);
 
-       value = readl(ioaddr + base_register);
+       /* The software must ensure that the same priority
+        * is not mapped to multiple Rx queues
+        */
+       for (i = 0; i < 4; i++)
+               clear_mask |= ((prio << GMAC_RXQCTRL_PSRQX_SHIFT(i)) &
+                                               GMAC_RXQCTRL_PSRQX_MASK(i));
+
+       ctrl2 &= ~clear_mask;
+       ctrl3 &= ~clear_mask;
+
+       /* First assign new priorities to a queue, then
+        * clear them from others queues
+        */
+       if (queue < 4) {
+               ctrl2 |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) &
+                                               GMAC_RXQCTRL_PSRQX_MASK(queue);
 
-       value &= ~GMAC_RXQCTRL_PSRQX_MASK(queue);
-       value |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) &
+               writel(ctrl2, ioaddr + GMAC_RXQ_CTRL2);
+               writel(ctrl3, ioaddr + GMAC_RXQ_CTRL3);
+       } else {
+               queue -= 4;
+
+               ctrl3 |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) &
                                                GMAC_RXQCTRL_PSRQX_MASK(queue);
-       writel(value, ioaddr + base_register);
+
+               writel(ctrl3, ioaddr + GMAC_RXQ_CTRL3);
+               writel(ctrl2, ioaddr + GMAC_RXQ_CTRL2);
+       }
 }
 
 static void dwmac4_tx_queue_priority(struct mac_device_info *hw,
index 1af2f89a0504ab4c7ad6042e52f5898ba064df6c..e841e312077ef0604c5b17a5473069cc4affadff 100644 (file)
@@ -105,17 +105,41 @@ static void dwxgmac2_rx_queue_prio(struct mac_device_info *hw, u32 prio,
                                   u32 queue)
 {
        void __iomem *ioaddr = hw->pcsr;
-       u32 value, reg;
+       u32 clear_mask = 0;
+       u32 ctrl2, ctrl3;
+       int i;
 
-       reg = (queue < 4) ? XGMAC_RXQ_CTRL2 : XGMAC_RXQ_CTRL3;
-       if (queue >= 4)
+       ctrl2 = readl(ioaddr + XGMAC_RXQ_CTRL2);
+       ctrl3 = readl(ioaddr + XGMAC_RXQ_CTRL3);
+
+       /* The software must ensure that the same priority
+        * is not mapped to multiple Rx queues
+        */
+       for (i = 0; i < 4; i++)
+               clear_mask |= ((prio << XGMAC_PSRQ_SHIFT(i)) &
+                                               XGMAC_PSRQ(i));
+
+       ctrl2 &= ~clear_mask;
+       ctrl3 &= ~clear_mask;
+
+       /* First assign new priorities to a queue, then
+        * clear them from others queues
+        */
+       if (queue < 4) {
+               ctrl2 |= (prio << XGMAC_PSRQ_SHIFT(queue)) &
+                                               XGMAC_PSRQ(queue);
+
+               writel(ctrl2, ioaddr + XGMAC_RXQ_CTRL2);
+               writel(ctrl3, ioaddr + XGMAC_RXQ_CTRL3);
+       } else {
                queue -= 4;
 
-       value = readl(ioaddr + reg);
-       value &= ~XGMAC_PSRQ(queue);
-       value |= (prio << XGMAC_PSRQ_SHIFT(queue)) & XGMAC_PSRQ(queue);
+               ctrl3 |= (prio << XGMAC_PSRQ_SHIFT(queue)) &
+                                               XGMAC_PSRQ(queue);
 
-       writel(value, ioaddr + reg);
+               writel(ctrl3, ioaddr + XGMAC_RXQ_CTRL3);
+               writel(ctrl2, ioaddr + XGMAC_RXQ_CTRL2);
+       }
 }
 
 static void dwxgmac2_tx_queue_prio(struct mac_device_info *hw, u32 prio,