Commit d83d508b authored by David S. Miller's avatar David S. Miller

Merge branch 'stmmac-next'

Jose Abreu says:

====================
net: stmmac: Improvements for -next

Couple of improvements for -next tree. More info in commit logs.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 83beee5a 94e18382
...@@ -75,6 +75,7 @@ struct stmmac_extra_stats { ...@@ -75,6 +75,7 @@ struct stmmac_extra_stats {
unsigned long rx_missed_cntr; unsigned long rx_missed_cntr;
unsigned long rx_overflow_cntr; unsigned long rx_overflow_cntr;
unsigned long rx_vlan; unsigned long rx_vlan;
unsigned long rx_split_hdr_pkt_n;
/* Tx/Rx IRQ error info */ /* Tx/Rx IRQ error info */
unsigned long tx_undeflow_irq; unsigned long tx_undeflow_irq;
unsigned long tx_process_stopped_irq; unsigned long tx_process_stopped_irq;
...@@ -356,6 +357,9 @@ struct dma_features { ...@@ -356,6 +357,9 @@ struct dma_features {
unsigned int addr64; unsigned int addr64;
unsigned int rssen; unsigned int rssen;
unsigned int vlhash; unsigned int vlhash;
unsigned int sphen;
unsigned int vlins;
unsigned int dvlan;
}; };
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
...@@ -387,6 +391,12 @@ struct dma_features { ...@@ -387,6 +391,12 @@ struct dma_features {
#define STMMAC_RSS_HASH_KEY_SIZE 40 #define STMMAC_RSS_HASH_KEY_SIZE 40
#define STMMAC_RSS_MAX_TABLE_SIZE 256 #define STMMAC_RSS_MAX_TABLE_SIZE 256
/* VLAN */
#define STMMAC_VLAN_NONE 0x0
#define STMMAC_VLAN_REMOVE 0x1
#define STMMAC_VLAN_INSERT 0x2
#define STMMAC_VLAN_REPLACE 0x3
extern const struct stmmac_desc_ops enh_desc_ops; extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops; extern const struct stmmac_desc_ops ndesc_ops;
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
#define XGMAC_CONFIG_ARPEN BIT(31) #define XGMAC_CONFIG_ARPEN BIT(31)
#define XGMAC_CONFIG_GPSL GENMASK(29, 16) #define XGMAC_CONFIG_GPSL GENMASK(29, 16)
#define XGMAC_CONFIG_GPSL_SHIFT 16 #define XGMAC_CONFIG_GPSL_SHIFT 16
#define XGMAC_CONFIG_HDSMS GENMASK(14, 12)
#define XGMAC_CONFIG_HDSMS_SHIFT 12
#define XGMAC_CONFIG_HDSMS_256 (0x2 << XGMAC_CONFIG_HDSMS_SHIFT)
#define XGMAC_CONFIG_S2KP BIT(11) #define XGMAC_CONFIG_S2KP BIT(11)
#define XGMAC_CONFIG_LM BIT(10) #define XGMAC_CONFIG_LM BIT(10)
#define XGMAC_CONFIG_IPC BIT(9) #define XGMAC_CONFIG_IPC BIT(9)
...@@ -60,6 +63,11 @@ ...@@ -60,6 +63,11 @@
#define XGMAC_VLAN_ETV BIT(16) #define XGMAC_VLAN_ETV BIT(16)
#define XGMAC_VLAN_VID GENMASK(15, 0) #define XGMAC_VLAN_VID GENMASK(15, 0)
#define XGMAC_VLAN_HASH_TABLE 0x00000058 #define XGMAC_VLAN_HASH_TABLE 0x00000058
#define XGMAC_VLAN_INCL 0x00000060
#define XGMAC_VLAN_VLTI BIT(20)
#define XGMAC_VLAN_CSVL BIT(19)
#define XGMAC_VLAN_VLC GENMASK(17, 16)
#define XGMAC_VLAN_VLC_SHIFT 16
#define XGMAC_RXQ_CTRL0 0x000000a0 #define XGMAC_RXQ_CTRL0 0x000000a0
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2) #define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2) #define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
...@@ -68,6 +76,7 @@ ...@@ -68,6 +76,7 @@
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8) #define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
#define XGMAC_PSRQ_SHIFT(x) ((x) * 8) #define XGMAC_PSRQ_SHIFT(x) ((x) * 8)
#define XGMAC_INT_STATUS 0x000000b0 #define XGMAC_INT_STATUS 0x000000b0
#define XGMAC_LPIIS BIT(5)
#define XGMAC_PMTIS BIT(4) #define XGMAC_PMTIS BIT(4)
#define XGMAC_INT_EN 0x000000b4 #define XGMAC_INT_EN 0x000000b4
#define XGMAC_TSIE BIT(12) #define XGMAC_TSIE BIT(12)
...@@ -85,10 +94,21 @@ ...@@ -85,10 +94,21 @@
#define XGMAC_RWKPKTEN BIT(2) #define XGMAC_RWKPKTEN BIT(2)
#define XGMAC_MGKPKTEN BIT(1) #define XGMAC_MGKPKTEN BIT(1)
#define XGMAC_PWRDWN BIT(0) #define XGMAC_PWRDWN BIT(0)
#define XGMAC_LPI_CTRL 0x000000d0
#define XGMAC_TXCGE BIT(21)
#define XGMAC_LPITXA BIT(19)
#define XGMAC_PLS BIT(17)
#define XGMAC_LPITXEN BIT(16)
#define XGMAC_RLPIEX BIT(3)
#define XGMAC_RLPIEN BIT(2)
#define XGMAC_TLPIEX BIT(1)
#define XGMAC_TLPIEN BIT(0)
#define XGMAC_LPI_TIMER_CTRL 0x000000d4
#define XGMAC_HW_FEATURE0 0x0000011c #define XGMAC_HW_FEATURE0 0x0000011c
#define XGMAC_HWFEAT_SAVLANINS BIT(27) #define XGMAC_HWFEAT_SAVLANINS BIT(27)
#define XGMAC_HWFEAT_RXCOESEL BIT(16) #define XGMAC_HWFEAT_RXCOESEL BIT(16)
#define XGMAC_HWFEAT_TXCOESEL BIT(14) #define XGMAC_HWFEAT_TXCOESEL BIT(14)
#define XGMAC_HWFEAT_EEESEL BIT(13)
#define XGMAC_HWFEAT_TSSEL BIT(12) #define XGMAC_HWFEAT_TSSEL BIT(12)
#define XGMAC_HWFEAT_AVSEL BIT(11) #define XGMAC_HWFEAT_AVSEL BIT(11)
#define XGMAC_HWFEAT_RAVSEL BIT(10) #define XGMAC_HWFEAT_RAVSEL BIT(10)
...@@ -101,6 +121,7 @@ ...@@ -101,6 +121,7 @@
#define XGMAC_HW_FEATURE1 0x00000120 #define XGMAC_HW_FEATURE1 0x00000120
#define XGMAC_HWFEAT_RSSEN BIT(20) #define XGMAC_HWFEAT_RSSEN BIT(20)
#define XGMAC_HWFEAT_TSOEN BIT(18) #define XGMAC_HWFEAT_TSOEN BIT(18)
#define XGMAC_HWFEAT_SPHEN BIT(17)
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14) #define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6) #define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0) #define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
...@@ -112,6 +133,7 @@ ...@@ -112,6 +133,7 @@
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0) #define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
#define XGMAC_HW_FEATURE3 0x00000128 #define XGMAC_HW_FEATURE3 0x00000128
#define XGMAC_HWFEAT_ASP GENMASK(15, 14) #define XGMAC_HWFEAT_ASP GENMASK(15, 14)
#define XGMAC_HWFEAT_DVLAN BIT(13)
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11) #define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9) #define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
#define XGMAC_HWFEAT_FRPSEL BIT(3) #define XGMAC_HWFEAT_FRPSEL BIT(3)
...@@ -145,6 +167,25 @@ ...@@ -145,6 +167,25 @@
#define XGMAC_TXTIMESTAMP_NSEC 0x00000d30 #define XGMAC_TXTIMESTAMP_NSEC 0x00000d30
#define XGMAC_TXTSSTSLO GENMASK(30, 0) #define XGMAC_TXTSSTSLO GENMASK(30, 0)
#define XGMAC_TXTIMESTAMP_SEC 0x00000d34 #define XGMAC_TXTIMESTAMP_SEC 0x00000d34
#define XGMAC_PPS_CONTROL 0x00000d70
#define XGMAC_PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
#define XGMAC_PPS_MINIDX(x) ((x) * 8)
#define XGMAC_PPSx_MASK(x) \
GENMASK(XGMAC_PPS_MAXIDX(x), XGMAC_PPS_MINIDX(x))
#define XGMAC_TRGTMODSELx(x, val) \
GENMASK(XGMAC_PPS_MAXIDX(x) - 1, XGMAC_PPS_MAXIDX(x) - 2) & \
((val) << (XGMAC_PPS_MAXIDX(x) - 2))
#define XGMAC_PPSCMDx(x, val) \
GENMASK(XGMAC_PPS_MINIDX(x) + 3, XGMAC_PPS_MINIDX(x)) & \
((val) << XGMAC_PPS_MINIDX(x))
#define XGMAC_PPSCMD_START 0x2
#define XGMAC_PPSCMD_STOP 0x5
#define XGMAC_PPSEN0 BIT(4)
#define XGMAC_PPSx_TARGET_TIME_SEC(x) (0x00000d80 + (x) * 0x10)
#define XGMAC_PPSx_TARGET_TIME_NSEC(x) (0x00000d84 + (x) * 0x10)
#define XGMAC_TRGTBUSY0 BIT(31)
#define XGMAC_PPSx_INTERVAL(x) (0x00000d88 + (x) * 0x10)
#define XGMAC_PPSx_WIDTH(x) (0x00000d8c + (x) * 0x10)
/* MTL Registers */ /* MTL Registers */
#define XGMAC_MTL_OPMODE 0x00001000 #define XGMAC_MTL_OPMODE 0x00001000
...@@ -221,6 +262,7 @@ ...@@ -221,6 +262,7 @@
#define XGMAC_RXOVFIS BIT(16) #define XGMAC_RXOVFIS BIT(16)
#define XGMAC_ABPSIS BIT(1) #define XGMAC_ABPSIS BIT(1)
#define XGMAC_TXUNFIS BIT(0) #define XGMAC_TXUNFIS BIT(0)
#define XGMAC_MAC_REGSIZE (XGMAC_MTL_QINT_STATUS(15) / 4)
/* DMA Registers */ /* DMA Registers */
#define XGMAC_DMA_MODE 0x00003000 #define XGMAC_DMA_MODE 0x00003000
...@@ -258,6 +300,7 @@ ...@@ -258,6 +300,7 @@
#define XGMAC_TCEIE BIT(0) #define XGMAC_TCEIE BIT(0)
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c #define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x))) #define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
#define XGMAC_SPH BIT(24)
#define XGMAC_PBLx8 BIT(16) #define XGMAC_PBLx8 BIT(16)
#define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x))) #define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x)))
#define XGMAC_TxPBL GENMASK(21, 16) #define XGMAC_TxPBL GENMASK(21, 16)
...@@ -297,12 +340,17 @@ ...@@ -297,12 +340,17 @@
#define XGMAC_TBU BIT(2) #define XGMAC_TBU BIT(2)
#define XGMAC_TPS BIT(1) #define XGMAC_TPS BIT(1)
#define XGMAC_TI BIT(0) #define XGMAC_TI BIT(0)
#define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4)
/* Descriptors */ /* Descriptors */
#define XGMAC_TDES2_IVT GENMASK(31, 16)
#define XGMAC_TDES2_IVT_SHIFT 16
#define XGMAC_TDES2_IOC BIT(31) #define XGMAC_TDES2_IOC BIT(31)
#define XGMAC_TDES2_TTSE BIT(30) #define XGMAC_TDES2_TTSE BIT(30)
#define XGMAC_TDES2_B2L GENMASK(29, 16) #define XGMAC_TDES2_B2L GENMASK(29, 16)
#define XGMAC_TDES2_B2L_SHIFT 16 #define XGMAC_TDES2_B2L_SHIFT 16
#define XGMAC_TDES2_VTIR GENMASK(15, 14)
#define XGMAC_TDES2_VTIR_SHIFT 14
#define XGMAC_TDES2_B1L GENMASK(13, 0) #define XGMAC_TDES2_B1L GENMASK(13, 0)
#define XGMAC_TDES3_OWN BIT(31) #define XGMAC_TDES3_OWN BIT(31)
#define XGMAC_TDES3_CTXT BIT(30) #define XGMAC_TDES3_CTXT BIT(30)
...@@ -311,13 +359,21 @@ ...@@ -311,13 +359,21 @@
#define XGMAC_TDES3_CPC GENMASK(27, 26) #define XGMAC_TDES3_CPC GENMASK(27, 26)
#define XGMAC_TDES3_CPC_SHIFT 26 #define XGMAC_TDES3_CPC_SHIFT 26
#define XGMAC_TDES3_TCMSSV BIT(26) #define XGMAC_TDES3_TCMSSV BIT(26)
#define XGMAC_TDES3_SAIC GENMASK(25, 23)
#define XGMAC_TDES3_SAIC_SHIFT 23
#define XGMAC_TDES3_THL GENMASK(22, 19) #define XGMAC_TDES3_THL GENMASK(22, 19)
#define XGMAC_TDES3_THL_SHIFT 19 #define XGMAC_TDES3_THL_SHIFT 19
#define XGMAC_TDES3_IVTIR GENMASK(19, 18)
#define XGMAC_TDES3_IVTIR_SHIFT 18
#define XGMAC_TDES3_TSE BIT(18) #define XGMAC_TDES3_TSE BIT(18)
#define XGMAC_TDES3_IVLTV BIT(17)
#define XGMAC_TDES3_CIC GENMASK(17, 16) #define XGMAC_TDES3_CIC GENMASK(17, 16)
#define XGMAC_TDES3_CIC_SHIFT 16 #define XGMAC_TDES3_CIC_SHIFT 16
#define XGMAC_TDES3_TPL GENMASK(17, 0) #define XGMAC_TDES3_TPL GENMASK(17, 0)
#define XGMAC_TDES3_VLTV BIT(16)
#define XGMAC_TDES3_VT GENMASK(15, 0)
#define XGMAC_TDES3_FL GENMASK(14, 0) #define XGMAC_TDES3_FL GENMASK(14, 0)
#define XGMAC_RDES2_HL GENMASK(9, 0)
#define XGMAC_RDES3_OWN BIT(31) #define XGMAC_RDES3_OWN BIT(31)
#define XGMAC_RDES3_CTXT BIT(30) #define XGMAC_RDES3_CTXT BIT(30)
#define XGMAC_RDES3_IOC BIT(30) #define XGMAC_RDES3_IOC BIT(30)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include "stmmac.h" #include "stmmac.h"
#include "stmmac_ptp.h"
#include "dwxgmac2.h" #include "dwxgmac2.h"
static void dwxgmac2_core_init(struct mac_device_info *hw, static void dwxgmac2_core_init(struct mac_device_info *hw,
...@@ -238,11 +239,21 @@ static void dwxgmac2_config_cbs(struct mac_device_info *hw, ...@@ -238,11 +239,21 @@ static void dwxgmac2_config_cbs(struct mac_device_info *hw,
writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue)); writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
} }
static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
{
void __iomem *ioaddr = hw->pcsr;
int i;
for (i = 0; i < XGMAC_MAC_REGSIZE; i++)
reg_space[i] = readl(ioaddr + i * 4);
}
static int dwxgmac2_host_irq_status(struct mac_device_info *hw, static int dwxgmac2_host_irq_status(struct mac_device_info *hw,
struct stmmac_extra_stats *x) struct stmmac_extra_stats *x)
{ {
void __iomem *ioaddr = hw->pcsr; void __iomem *ioaddr = hw->pcsr;
u32 stat, en; u32 stat, en;
int ret = 0;
en = readl(ioaddr + XGMAC_INT_EN); en = readl(ioaddr + XGMAC_INT_EN);
stat = readl(ioaddr + XGMAC_INT_STATUS); stat = readl(ioaddr + XGMAC_INT_STATUS);
...@@ -254,7 +265,24 @@ static int dwxgmac2_host_irq_status(struct mac_device_info *hw, ...@@ -254,7 +265,24 @@ static int dwxgmac2_host_irq_status(struct mac_device_info *hw,
readl(ioaddr + XGMAC_PMT); readl(ioaddr + XGMAC_PMT);
} }
return 0; if (stat & XGMAC_LPIIS) {
u32 lpi = readl(ioaddr + XGMAC_LPI_CTRL);
if (lpi & XGMAC_TLPIEN) {
ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
x->irq_tx_path_in_lpi_mode_n++;
}
if (lpi & XGMAC_TLPIEX) {
ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
x->irq_tx_path_exit_lpi_mode_n++;
}
if (lpi & XGMAC_RLPIEN)
x->irq_rx_path_in_lpi_mode_n++;
if (lpi & XGMAC_RLPIEX)
x->irq_rx_path_exit_lpi_mode_n++;
}
return ret;
} }
static int dwxgmac2_host_mtl_irq_status(struct mac_device_info *hw, u32 chan) static int dwxgmac2_host_mtl_irq_status(struct mac_device_info *hw, u32 chan)
...@@ -347,6 +375,53 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw, ...@@ -347,6 +375,53 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
addr[5] = (hi_addr >> 8) & 0xff; addr[5] = (hi_addr >> 8) & 0xff;
} }
static void dwxgmac2_set_eee_mode(struct mac_device_info *hw,
bool en_tx_lpi_clockgating)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_LPI_CTRL);
value |= XGMAC_LPITXEN | XGMAC_LPITXA;
if (en_tx_lpi_clockgating)
value |= XGMAC_TXCGE;
writel(value, ioaddr + XGMAC_LPI_CTRL);
}
static void dwxgmac2_reset_eee_mode(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_LPI_CTRL);
value &= ~(XGMAC_LPITXEN | XGMAC_LPITXA | XGMAC_TXCGE);
writel(value, ioaddr + XGMAC_LPI_CTRL);
}
static void dwxgmac2_set_eee_pls(struct mac_device_info *hw, int link)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_LPI_CTRL);
if (link)
value |= XGMAC_PLS;
else
value &= ~XGMAC_PLS;
writel(value, ioaddr + XGMAC_LPI_CTRL);
}
static void dwxgmac2_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = (tw & 0xffff) | ((ls & 0x3ff) << 16);
writel(value, ioaddr + XGMAC_LPI_TIMER_CTRL);
}
static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, static void dwxgmac2_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
int mcbitslog2) int mcbitslog2)
{ {
...@@ -997,6 +1072,97 @@ static int dwxgmac3_rxp_config(void __iomem *ioaddr, ...@@ -997,6 +1072,97 @@ static int dwxgmac3_rxp_config(void __iomem *ioaddr,
return ret; return ret;
} }
static int dwxgmac2_get_mac_tx_timestamp(struct mac_device_info *hw, u64 *ts)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
if (readl_poll_timeout_atomic(ioaddr + XGMAC_TIMESTAMP_STATUS,
value, value & XGMAC_TXTSC, 100, 10000))
return -EBUSY;
*ts = readl(ioaddr + XGMAC_TXTIMESTAMP_NSEC) & XGMAC_TXTSSTSLO;
*ts += readl(ioaddr + XGMAC_TXTIMESTAMP_SEC) * 1000000000ULL;
return 0;
}
static int dwxgmac2_flex_pps_config(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags)
{
u32 tnsec = readl(ioaddr + XGMAC_PPSx_TARGET_TIME_NSEC(index));
u32 val = readl(ioaddr + XGMAC_PPS_CONTROL);
u64 period;
if (!cfg->available)
return -EINVAL;
if (tnsec & XGMAC_TRGTBUSY0)
return -EBUSY;
if (!sub_second_inc || !systime_flags)
return -EINVAL;
val &= ~XGMAC_PPSx_MASK(index);
if (!enable) {
val |= XGMAC_PPSCMDx(index, XGMAC_PPSCMD_STOP);
writel(val, ioaddr + XGMAC_PPS_CONTROL);
return 0;
}
val |= XGMAC_PPSCMDx(index, XGMAC_PPSCMD_START);
val |= XGMAC_TRGTMODSELx(index, XGMAC_PPSCMD_START);
val |= XGMAC_PPSEN0;
writel(cfg->start.tv_sec, ioaddr + XGMAC_PPSx_TARGET_TIME_SEC(index));
if (!(systime_flags & PTP_TCR_TSCTRLSSR))
cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
writel(cfg->start.tv_nsec, ioaddr + XGMAC_PPSx_TARGET_TIME_NSEC(index));
period = cfg->period.tv_sec * 1000000000;
period += cfg->period.tv_nsec;
do_div(period, sub_second_inc);
if (period <= 1)
return -EINVAL;
writel(period - 1, ioaddr + XGMAC_PPSx_INTERVAL(index));
period >>= 1;
if (period <= 1)
return -EINVAL;
writel(period - 1, ioaddr + XGMAC_PPSx_WIDTH(index));
/* Finally, activate it */
writel(val, ioaddr + XGMAC_PPS_CONTROL);
return 0;
}
static void dwxgmac2_sarc_configure(void __iomem *ioaddr, int val)
{
u32 value = readl(ioaddr + XGMAC_TX_CONFIG);
value &= ~XGMAC_CONFIG_SARC;
value |= val << XGMAC_CONFIG_SARC_SHIFT;
writel(value, ioaddr + XGMAC_TX_CONFIG);
}
static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_VLAN_INCL);
value |= XGMAC_VLAN_VLTI;
value |= XGMAC_VLAN_CSVL; /* Only use SVLAN */
value &= ~XGMAC_VLAN_VLC;
value |= (type << XGMAC_VLAN_VLC_SHIFT) & XGMAC_VLAN_VLC;
writel(value, ioaddr + XGMAC_VLAN_INCL);
}
const struct stmmac_ops dwxgmac210_ops = { const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init, .core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac, .set_mac = dwxgmac2_set_mac,
...@@ -1010,17 +1176,17 @@ const struct stmmac_ops dwxgmac210_ops = { ...@@ -1010,17 +1176,17 @@ const struct stmmac_ops dwxgmac210_ops = {
.set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight, .set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight,
.map_mtl_to_dma = dwxgmac2_map_mtl_to_dma, .map_mtl_to_dma = dwxgmac2_map_mtl_to_dma,
.config_cbs = dwxgmac2_config_cbs, .config_cbs = dwxgmac2_config_cbs,
.dump_regs = NULL, .dump_regs = dwxgmac2_dump_regs,
.host_irq_status = dwxgmac2_host_irq_status, .host_irq_status = dwxgmac2_host_irq_status,
.host_mtl_irq_status = dwxgmac2_host_mtl_irq_status, .host_mtl_irq_status = dwxgmac2_host_mtl_irq_status,
.flow_ctrl = dwxgmac2_flow_ctrl, .flow_ctrl = dwxgmac2_flow_ctrl,
.pmt = dwxgmac2_pmt, .pmt = dwxgmac2_pmt,
.set_umac_addr = dwxgmac2_set_umac_addr, .set_umac_addr = dwxgmac2_set_umac_addr,
.get_umac_addr = dwxgmac2_get_umac_addr, .get_umac_addr = dwxgmac2_get_umac_addr,
.set_eee_mode = NULL, .set_eee_mode = dwxgmac2_set_eee_mode,
.reset_eee_mode = NULL, .reset_eee_mode = dwxgmac2_reset_eee_mode,
.set_eee_timer = NULL, .set_eee_timer = dwxgmac2_set_eee_timer,
.set_eee_pls = NULL, .set_eee_pls = dwxgmac2_set_eee_pls,
.pcs_ctrl_ane = NULL, .pcs_ctrl_ane = NULL,
.pcs_rane = NULL, .pcs_rane = NULL,
.pcs_get_adv_lp = NULL, .pcs_get_adv_lp = NULL,
...@@ -1033,6 +1199,10 @@ const struct stmmac_ops dwxgmac210_ops = { ...@@ -1033,6 +1199,10 @@ const struct stmmac_ops dwxgmac210_ops = {
.rss_configure = dwxgmac2_rss_configure, .rss_configure = dwxgmac2_rss_configure,
.update_vlan_hash = dwxgmac2_update_vlan_hash, .update_vlan_hash = dwxgmac2_update_vlan_hash,
.rxp_config = dwxgmac3_rxp_config, .rxp_config = dwxgmac3_rxp_config,
.get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp,
.flex_pps_config = dwxgmac2_flex_pps_config,
.sarc_configure = dwxgmac2_sarc_configure,
.enable_vlan = dwxgmac2_enable_vlan,
}; };
int dwxgmac2_setup(struct stmmac_priv *priv) int dwxgmac2_setup(struct stmmac_priv *priv)
......
...@@ -26,16 +26,17 @@ static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x, ...@@ -26,16 +26,17 @@ static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p) struct dma_desc *p)
{ {
unsigned int rdes3 = le32_to_cpu(p->des3); unsigned int rdes3 = le32_to_cpu(p->des3);
int ret = good_frame;
if (unlikely(rdes3 & XGMAC_RDES3_OWN)) if (unlikely(rdes3 & XGMAC_RDES3_OWN))
return dma_own; return dma_own;
if (unlikely(rdes3 & XGMAC_RDES3_CTXT))
return discard_frame;
if (likely(!(rdes3 & XGMAC_RDES3_LD))) if (likely(!(rdes3 & XGMAC_RDES3_LD)))
return rx_not_ls;
if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
return discard_frame; return discard_frame;
if (unlikely(rdes3 & XGMAC_RDES3_ES))
ret = discard_frame;
return ret; return good_frame;
} }
static int dwxgmac2_get_tx_len(struct dma_desc *p) static int dwxgmac2_get_tx_len(struct dma_desc *p)
...@@ -55,7 +56,7 @@ static void dwxgmac2_set_tx_owner(struct dma_desc *p) ...@@ -55,7 +56,7 @@ static void dwxgmac2_set_tx_owner(struct dma_desc *p)
static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic) static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
{ {
p->des3 = cpu_to_le32(XGMAC_RDES3_OWN); p->des3 |= cpu_to_le32(XGMAC_RDES3_OWN);
if (!disable_rx_ic) if (!disable_rx_ic)
p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC); p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
...@@ -98,11 +99,17 @@ static int dwxgmac2_rx_check_timestamp(void *desc) ...@@ -98,11 +99,17 @@ static int dwxgmac2_rx_check_timestamp(void *desc)
unsigned int rdes3 = le32_to_cpu(p->des3); unsigned int rdes3 = le32_to_cpu(p->des3);
bool desc_valid, ts_valid; bool desc_valid, ts_valid;
dma_rmb();
desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT); desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA); ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
if (likely(desc_valid && ts_valid)) if (likely(desc_valid && ts_valid)) {
if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
return -EINVAL;
return 0; return 0;
}
return -EINVAL; return -EINVAL;
} }
...@@ -113,13 +120,10 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc, ...@@ -113,13 +120,10 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
unsigned int rdes3 = le32_to_cpu(p->des3); unsigned int rdes3 = le32_to_cpu(p->des3);
int ret = -EBUSY; int ret = -EBUSY;
if (likely(rdes3 & XGMAC_RDES3_CDA)) { if (likely(rdes3 & XGMAC_RDES3_CDA))
ret = dwxgmac2_rx_check_timestamp(next_desc); ret = dwxgmac2_rx_check_timestamp(next_desc);
if (ret)
return ret;
}
return ret; return !ret;
} }
static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic, static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
...@@ -144,7 +148,7 @@ static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, ...@@ -144,7 +148,7 @@ static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L); p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
tdes3 = tot_pkt_len & XGMAC_TDES3_FL; tdes3 |= tot_pkt_len & XGMAC_TDES3_FL;
if (is_fs) if (is_fs)
tdes3 |= XGMAC_TDES3_FD; tdes3 |= XGMAC_TDES3_FD;
else else
...@@ -282,6 +286,58 @@ static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash, ...@@ -282,6 +286,58 @@ static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash,
return -EINVAL; return -EINVAL;
} }
static int dwxgmac2_get_rx_header_len(struct dma_desc *p, unsigned int *len)
{
*len = le32_to_cpu(p->des2) & XGMAC_RDES2_HL;
return 0;
}
static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr)
{
p->des2 = cpu_to_le32(lower_32_bits(addr));
p->des3 = cpu_to_le32(upper_32_bits(addr));
}
static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type)
{
sarc_type <<= XGMAC_TDES3_SAIC_SHIFT;
p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC);
}
static void dwxgmac2_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
u32 inner_type)
{
p->des0 = 0;
p->des1 = 0;
p->des2 = 0;
p->des3 = 0;
/* Inner VLAN */
if (inner_type) {
u32 des = inner_tag << XGMAC_TDES2_IVT_SHIFT;
des &= XGMAC_TDES2_IVT;
p->des2 = cpu_to_le32(des);
des = inner_type << XGMAC_TDES3_IVTIR_SHIFT;
des &= XGMAC_TDES3_IVTIR;
p->des3 = cpu_to_le32(des | XGMAC_TDES3_IVLTV);
}
/* Outer VLAN */
p->des3 |= cpu_to_le32(tag & XGMAC_TDES3_VT);
p->des3 |= cpu_to_le32(XGMAC_TDES3_VLTV);
p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT);
}
static void dwxgmac2_set_vlan(struct dma_desc *p, u32 type)
{
type <<= XGMAC_TDES2_VTIR_SHIFT;
p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR);
}
const struct stmmac_desc_ops dwxgmac210_desc_ops = { const struct stmmac_desc_ops dwxgmac210_desc_ops = {
.tx_status = dwxgmac2_get_tx_status, .tx_status = dwxgmac2_get_tx_status,
.rx_status = dwxgmac2_get_rx_status, .rx_status = dwxgmac2_get_rx_status,
...@@ -306,4 +362,9 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = { ...@@ -306,4 +362,9 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = {
.set_addr = dwxgmac2_set_addr, .set_addr = dwxgmac2_set_addr,
.clear = dwxgmac2_clear, .clear = dwxgmac2_clear,
.get_rx_hash = dwxgmac2_get_rx_hash, .get_rx_hash = dwxgmac2_get_rx_hash,
.get_rx_header_len = dwxgmac2_get_rx_header_len,
.set_sec_addr = dwxgmac2_set_sec_addr,
.set_sarc = dwxgmac2_set_sarc,
.set_vlan_tag = dwxgmac2_set_vlan_tag,
.set_vlan = dwxgmac2_set_vlan,
}; };
...@@ -128,6 +128,14 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) ...@@ -128,6 +128,14 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL); writel(XGMAC_RDPS, ioaddr + XGMAC_RX_EDMA_CTRL);
} }
static void dwxgmac2_dma_dump_regs(void __iomem *ioaddr, u32 *reg_space)
{
int i;
for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
reg_space[i] = readl(ioaddr + i * 4);
}
static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode, static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode,
u32 channel, int fifosz, u8 qmode) u32 channel, int fifosz, u8 qmode)
{ {
...@@ -351,8 +359,10 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr, ...@@ -351,8 +359,10 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 0 */ /* MAC HW feature 0 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16; dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16;
dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14; dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14;
dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12; dma_cap->atime_stamp = (hw_cap & XGMAC_HWFEAT_TSSEL) >> 12;
dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11; dma_cap->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11;
dma_cap->av &= (hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10; dma_cap->av &= (hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10;
...@@ -366,6 +376,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr, ...@@ -366,6 +376,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1); hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20; dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18; dma_cap->tsoen = (hw_cap & XGMAC_HWFEAT_TSOEN) >> 18;
dma_cap->sphen = (hw_cap & XGMAC_HWFEAT_SPHEN) >> 17;
dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14; dma_cap->addr64 = (hw_cap & XGMAC_HWFEAT_ADDR64) >> 14;
switch (dma_cap->addr64) { switch (dma_cap->addr64) {
...@@ -403,6 +414,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr, ...@@ -403,6 +414,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 3 */ /* MAC HW feature 3 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3); hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14; dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11; dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9; dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3; dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
...@@ -472,6 +484,22 @@ static void dwxgmac2_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan) ...@@ -472,6 +484,22 @@ static void dwxgmac2_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan)
writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
} }
static void dwxgmac2_enable_sph(void __iomem *ioaddr, bool en, u32 chan)
{
u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
value &= ~XGMAC_CONFIG_HDSMS;
value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
writel(value, ioaddr + XGMAC_RX_CONFIG);
value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
if (en)
value |= XGMAC_SPH;
else
value &= ~XGMAC_SPH;
writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
}
const struct stmmac_dma_ops dwxgmac210_dma_ops = { const struct stmmac_dma_ops dwxgmac210_dma_ops = {
.reset = dwxgmac2_dma_reset, .reset = dwxgmac2_dma_reset,
.init = dwxgmac2_dma_init, .init = dwxgmac2_dma_init,
...@@ -479,7 +507,7 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = { ...@@ -479,7 +507,7 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
.init_rx_chan = dwxgmac2_dma_init_rx_chan, .init_rx_chan = dwxgmac2_dma_init_rx_chan,
.init_tx_chan = dwxgmac2_dma_init_tx_chan, .init_tx_chan = dwxgmac2_dma_init_tx_chan,
.axi = dwxgmac2_dma_axi, .axi = dwxgmac2_dma_axi,
.dump_regs = NULL, .dump_regs = dwxgmac2_dma_dump_regs,
.dma_rx_mode = dwxgmac2_dma_rx_mode, .dma_rx_mode = dwxgmac2_dma_rx_mode,
.dma_tx_mode = dwxgmac2_dma_tx_mode, .dma_tx_mode = dwxgmac2_dma_tx_mode,
.enable_dma_irq = dwxgmac2_enable_dma_irq, .enable_dma_irq = dwxgmac2_enable_dma_irq,
...@@ -498,4 +526,5 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = { ...@@ -498,4 +526,5 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
.enable_tso = dwxgmac2_enable_tso, .enable_tso = dwxgmac2_enable_tso,
.qmode = dwxgmac2_qmode, .qmode = dwxgmac2_qmode,
.set_bfsize = dwxgmac2_set_bfsize, .set_bfsize = dwxgmac2_set_bfsize,
.enable_sph = dwxgmac2_enable_sph,
}; };
...@@ -89,6 +89,12 @@ struct stmmac_desc_ops { ...@@ -89,6 +89,12 @@ struct stmmac_desc_ops {
/* RSS */ /* RSS */
int (*get_rx_hash)(struct dma_desc *p, u32 *hash, int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
enum pkt_hash_types *type); enum pkt_hash_types *type);
int (*get_rx_header_len)(struct dma_desc *p, unsigned int *len);
void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr);
void (*set_sarc)(struct dma_desc *p, u32 sarc_type);
void (*set_vlan_tag)(struct dma_desc *p, u16 tag, u16 inner_tag,
u32 inner_type);
void (*set_vlan)(struct dma_desc *p, u32 type);
}; };
#define stmmac_init_rx_desc(__priv, __args...) \ #define stmmac_init_rx_desc(__priv, __args...) \
...@@ -141,6 +147,16 @@ struct stmmac_desc_ops { ...@@ -141,6 +147,16 @@ struct stmmac_desc_ops {
stmmac_do_void_callback(__priv, desc, clear, __args) stmmac_do_void_callback(__priv, desc, clear, __args)
#define stmmac_get_rx_hash(__priv, __args...) \ #define stmmac_get_rx_hash(__priv, __args...) \
stmmac_do_callback(__priv, desc, get_rx_hash, __args) stmmac_do_callback(__priv, desc, get_rx_hash, __args)
#define stmmac_get_rx_header_len(__priv, __args...) \
stmmac_do_callback(__priv, desc, get_rx_header_len, __args)
#define stmmac_set_desc_sec_addr(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_sec_addr, __args)
#define stmmac_set_desc_sarc(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_sarc, __args)
#define stmmac_set_desc_vlan_tag(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_vlan_tag, __args)
#define stmmac_set_desc_vlan(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_vlan, __args)
struct stmmac_dma_cfg; struct stmmac_dma_cfg;
struct dma_features; struct dma_features;
...@@ -191,6 +207,7 @@ struct stmmac_dma_ops { ...@@ -191,6 +207,7 @@ struct stmmac_dma_ops {
void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan); void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode); void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode);
void (*set_bfsize)(void __iomem *ioaddr, int bfsize, u32 chan); void (*set_bfsize)(void __iomem *ioaddr, int bfsize, u32 chan);
void (*enable_sph)(void __iomem *ioaddr, bool en, u32 chan);
}; };
#define stmmac_reset(__priv, __args...) \ #define stmmac_reset(__priv, __args...) \
...@@ -247,6 +264,8 @@ struct stmmac_dma_ops { ...@@ -247,6 +264,8 @@ struct stmmac_dma_ops {
stmmac_do_void_callback(__priv, dma, qmode, __args) stmmac_do_void_callback(__priv, dma, qmode, __args)
#define stmmac_set_dma_bfsize(__priv, __args...) \ #define stmmac_set_dma_bfsize(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, set_bfsize, __args) stmmac_do_void_callback(__priv, dma, set_bfsize, __args)
#define stmmac_enable_sph(__priv, __args...) \
stmmac_do_void_callback(__priv, dma, enable_sph, __args)
struct mac_device_info; struct mac_device_info;
struct net_device; struct net_device;
...@@ -339,6 +358,11 @@ struct stmmac_ops { ...@@ -339,6 +358,11 @@ struct stmmac_ops {
/* VLAN */ /* VLAN */
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
bool is_double); bool is_double);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
/* TX Timestamp */
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
/* Source Address Insertion / Replacement */
void (*sarc_configure)(void __iomem *ioaddr, int val);
}; };
#define stmmac_core_init(__priv, __args...) \ #define stmmac_core_init(__priv, __args...) \
...@@ -413,6 +437,12 @@ struct stmmac_ops { ...@@ -413,6 +437,12 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, rss_configure, __args) stmmac_do_callback(__priv, mac, rss_configure, __args)
#define stmmac_update_vlan_hash(__priv, __args...) \ #define stmmac_update_vlan_hash(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args) stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
#define stmmac_enable_vlan(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
#define stmmac_get_mac_tx_timestamp(__priv, __args...) \
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
#define stmmac_sarc_configure(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, sarc_configure, __args)
/* PTP and HW Timer helpers */ /* PTP and HW Timer helpers */
struct stmmac_hwtimestamp { struct stmmac_hwtimestamp {
......
...@@ -58,7 +58,9 @@ struct stmmac_tx_queue { ...@@ -58,7 +58,9 @@ struct stmmac_tx_queue {
struct stmmac_rx_buffer { struct stmmac_rx_buffer {
struct page *page; struct page *page;
struct page *sec_page;
dma_addr_t addr; dma_addr_t addr;
dma_addr_t sec_addr;
}; };
struct stmmac_rx_queue { struct stmmac_rx_queue {
...@@ -74,6 +76,12 @@ struct stmmac_rx_queue { ...@@ -74,6 +76,12 @@ struct stmmac_rx_queue {
u32 rx_zeroc_thresh; u32 rx_zeroc_thresh;
dma_addr_t dma_rx_phy; dma_addr_t dma_rx_phy;
u32 rx_tail_addr; u32 rx_tail_addr;
unsigned int state_saved;
struct {
struct sk_buff *skb;
unsigned int len;
unsigned int error;
} state;
}; };
struct stmmac_channel { struct stmmac_channel {
...@@ -130,6 +138,8 @@ struct stmmac_priv { ...@@ -130,6 +138,8 @@ struct stmmac_priv {
int hwts_tx_en; int hwts_tx_en;
bool tx_path_in_lpi_mode; bool tx_path_in_lpi_mode;
bool tso; bool tso;
int sph;
u32 sarc_type;
unsigned int dma_buf_sz; unsigned int dma_buf_sz;
unsigned int rx_copybreak; unsigned int rx_copybreak;
......
...@@ -18,10 +18,12 @@ ...@@ -18,10 +18,12 @@
#include "stmmac.h" #include "stmmac.h"
#include "dwmac_dma.h" #include "dwmac_dma.h"
#include "dwxgmac2.h"
#define REG_SPACE_SIZE 0x1060 #define REG_SPACE_SIZE 0x1060
#define MAC100_ETHTOOL_NAME "st_mac100" #define MAC100_ETHTOOL_NAME "st_mac100"
#define GMAC_ETHTOOL_NAME "st_gmac" #define GMAC_ETHTOOL_NAME "st_gmac"
#define XGMAC_ETHTOOL_NAME "st_xgmac"
#define ETHTOOL_DMA_OFFSET 55 #define ETHTOOL_DMA_OFFSET 55
...@@ -65,6 +67,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { ...@@ -65,6 +67,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(rx_missed_cntr), STMMAC_STAT(rx_missed_cntr),
STMMAC_STAT(rx_overflow_cntr), STMMAC_STAT(rx_overflow_cntr),
STMMAC_STAT(rx_vlan), STMMAC_STAT(rx_vlan),
STMMAC_STAT(rx_split_hdr_pkt_n),
/* Tx/Rx IRQ error info */ /* Tx/Rx IRQ error info */
STMMAC_STAT(tx_undeflow_irq), STMMAC_STAT(tx_undeflow_irq),
STMMAC_STAT(tx_process_stopped_irq), STMMAC_STAT(tx_process_stopped_irq),
...@@ -259,6 +262,8 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev, ...@@ -259,6 +262,8 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
if (priv->plat->has_gmac || priv->plat->has_gmac4) if (priv->plat->has_gmac || priv->plat->has_gmac4)
strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver)); strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
else if (priv->plat->has_xgmac)
strlcpy(info->driver, XGMAC_ETHTOOL_NAME, sizeof(info->driver));
else else
strlcpy(info->driver, MAC100_ETHTOOL_NAME, strlcpy(info->driver, MAC100_ETHTOOL_NAME,
sizeof(info->driver)); sizeof(info->driver));
...@@ -404,23 +409,28 @@ static int stmmac_check_if_running(struct net_device *dev) ...@@ -404,23 +409,28 @@ static int stmmac_check_if_running(struct net_device *dev)
static int stmmac_ethtool_get_regs_len(struct net_device *dev) static int stmmac_ethtool_get_regs_len(struct net_device *dev)
{ {
struct stmmac_priv *priv = netdev_priv(dev);
if (priv->plat->has_xgmac)
return XGMAC_REGSIZE * 4;
return REG_SPACE_SIZE; return REG_SPACE_SIZE;
} }
static void stmmac_ethtool_gregs(struct net_device *dev, static void stmmac_ethtool_gregs(struct net_device *dev,
struct ethtool_regs *regs, void *space) struct ethtool_regs *regs, void *space)
{ {
u32 *reg_space = (u32 *) space;
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
u32 *reg_space = (u32 *) space;
memset(reg_space, 0x0, REG_SPACE_SIZE);
stmmac_dump_mac_regs(priv, priv->hw, reg_space); stmmac_dump_mac_regs(priv, priv->hw, reg_space);
stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
/* Copy DMA registers to where ethtool expects them */
memcpy(&reg_space[ETHTOOL_DMA_OFFSET], &reg_space[DMA_BUS_MODE / 4], if (!priv->plat->has_xgmac) {
NUM_DWMAC1000_DMA_REGS * 4); /* Copy DMA registers to where ethtool expects them */
memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
&reg_space[DMA_BUS_MODE / 4],
NUM_DWMAC1000_DMA_REGS * 4);
}
} }
static int stmmac_nway_reset(struct net_device *dev) static int stmmac_nway_reset(struct net_device *dev)
......
...@@ -432,6 +432,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, ...@@ -432,6 +432,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
struct dma_desc *p, struct sk_buff *skb) struct dma_desc *p, struct sk_buff *skb)
{ {
struct skb_shared_hwtstamps shhwtstamp; struct skb_shared_hwtstamps shhwtstamp;
bool found = false;
u64 ns = 0; u64 ns = 0;
if (!priv->hwts_tx_en) if (!priv->hwts_tx_en)
...@@ -443,9 +444,13 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, ...@@ -443,9 +444,13 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
/* check tx tstamp status */ /* check tx tstamp status */
if (stmmac_get_tx_timestamp_status(priv, p)) { if (stmmac_get_tx_timestamp_status(priv, p)) {
/* get the valid tstamp */
stmmac_get_timestamp(priv, p, priv->adv_ts, &ns); stmmac_get_timestamp(priv, p, priv->adv_ts, &ns);
found = true;
} else if (!stmmac_get_mac_tx_timestamp(priv, priv->hw, &ns)) {
found = true;
}
if (found) {
memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp.hwtstamp = ns_to_ktime(ns); shhwtstamp.hwtstamp = ns_to_ktime(ns);
...@@ -453,8 +458,6 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, ...@@ -453,8 +458,6 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
/* pass tstamp to stack */ /* pass tstamp to stack */
skb_tstamp_tx(skb, &shhwtstamp); skb_tstamp_tx(skb, &shhwtstamp);
} }
return;
} }
/* stmmac_get_rx_hwtstamp - get HW RX timestamps /* stmmac_get_rx_hwtstamp - get HW RX timestamps
...@@ -1198,6 +1201,17 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, ...@@ -1198,6 +1201,17 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
if (!buf->page) if (!buf->page)
return -ENOMEM; return -ENOMEM;
if (priv->sph) {
buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->sec_page)
return -ENOMEM;
buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr);
} else {
buf->sec_page = NULL;
}
buf->addr = page_pool_get_dma_addr(buf->page); buf->addr = page_pool_get_dma_addr(buf->page);
stmmac_set_desc_addr(priv, p, buf->addr); stmmac_set_desc_addr(priv, p, buf->addr);
if (priv->dma_buf_sz == BUF_SIZE_16KiB) if (priv->dma_buf_sz == BUF_SIZE_16KiB)
...@@ -1220,6 +1234,10 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) ...@@ -1220,6 +1234,10 @@ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i)
if (buf->page) if (buf->page)
page_pool_put_page(rx_q->page_pool, buf->page, false); page_pool_put_page(rx_q->page_pool, buf->page, false);
buf->page = NULL; buf->page = NULL;
if (buf->sec_page)
page_pool_put_page(rx_q->page_pool, buf->sec_page, false);
buf->sec_page = NULL;
} }
/** /**
...@@ -2593,6 +2611,16 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) ...@@ -2593,6 +2611,16 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
stmmac_enable_tso(priv, priv->ioaddr, 1, chan); stmmac_enable_tso(priv, priv->ioaddr, 1, chan);
} }
/* Enable Split Header */
if (priv->sph && priv->hw->rx_csum) {
for (chan = 0; chan < rx_cnt; chan++)
stmmac_enable_sph(priv, priv->ioaddr, 1, chan);
}
/* VLAN Tag Insertion */
if (priv->dma_cap.vlins)
stmmac_enable_vlan(priv, priv->hw, STMMAC_VLAN_INSERT);
/* Start the ball rolling... */ /* Start the ball rolling... */
stmmac_start_all_dma(priv); stmmac_start_all_dma(priv);
...@@ -2770,6 +2798,33 @@ static int stmmac_release(struct net_device *dev) ...@@ -2770,6 +2798,33 @@ static int stmmac_release(struct net_device *dev)
return 0; return 0;
} }
static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb,
struct stmmac_tx_queue *tx_q)
{
u16 tag = 0x0, inner_tag = 0x0;
u32 inner_type = 0x0;
struct dma_desc *p;
if (!priv->dma_cap.vlins)
return false;
if (!skb_vlan_tag_present(skb))
return false;
if (skb->vlan_proto == htons(ETH_P_8021AD)) {
inner_tag = skb_vlan_tag_get(skb);
inner_type = STMMAC_VLAN_INSERT;
}
tag = skb_vlan_tag_get(skb);
p = tx_q->dma_tx + tx_q->cur_tx;
if (stmmac_set_desc_vlan_tag(priv, p, tag, inner_tag, inner_type))
return false;
stmmac_set_tx_owner(priv, p);
tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, DMA_TX_SIZE);
return true;
}
/** /**
* stmmac_tso_allocator - close entry point of the driver * stmmac_tso_allocator - close entry point of the driver
* @priv: driver private structure * @priv: driver private structure
...@@ -2849,12 +2904,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2849,12 +2904,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
int nfrags = skb_shinfo(skb)->nr_frags; int nfrags = skb_shinfo(skb)->nr_frags;
u32 queue = skb_get_queue_mapping(skb); u32 queue = skb_get_queue_mapping(skb);
unsigned int first_entry;
struct stmmac_tx_queue *tx_q; struct stmmac_tx_queue *tx_q;
unsigned int first_entry;
int tmp_pay_len = 0; int tmp_pay_len = 0;
u32 pay_len, mss; u32 pay_len, mss;
u8 proto_hdr_len; u8 proto_hdr_len;
dma_addr_t des; dma_addr_t des;
bool has_vlan;
int i; int i;
tx_q = &priv->tx_queue[queue]; tx_q = &priv->tx_queue[queue];
...@@ -2896,12 +2952,18 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2896,12 +2952,18 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
skb->data_len); skb->data_len);
} }
/* Check if VLAN can be inserted by HW */
has_vlan = stmmac_vlan_insert(priv, skb, tx_q);
first_entry = tx_q->cur_tx; first_entry = tx_q->cur_tx;
WARN_ON(tx_q->tx_skbuff[first_entry]); WARN_ON(tx_q->tx_skbuff[first_entry]);
desc = tx_q->dma_tx + first_entry; desc = tx_q->dma_tx + first_entry;
first = desc; first = desc;
if (has_vlan)
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
/* first descriptor: fill Headers on Buf1 */ /* first descriptor: fill Headers on Buf1 */
des = dma_map_single(priv->device, skb->data, skb_headlen(skb), des = dma_map_single(priv->device, skb->data, skb_headlen(skb),
DMA_TO_DEVICE); DMA_TO_DEVICE);
...@@ -2980,6 +3042,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2980,6 +3042,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
priv->xstats.tx_set_ic_bit++; priv->xstats.tx_set_ic_bit++;
} }
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
...@@ -3058,6 +3123,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3058,6 +3123,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int first_entry; unsigned int first_entry;
unsigned int enh_desc; unsigned int enh_desc;
dma_addr_t des; dma_addr_t des;
bool has_vlan;
int entry; int entry;
tx_q = &priv->tx_queue[queue]; tx_q = &priv->tx_queue[queue];
...@@ -3083,6 +3149,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3083,6 +3149,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
/* Check if VLAN can be inserted by HW */
has_vlan = stmmac_vlan_insert(priv, skb, tx_q);
entry = tx_q->cur_tx; entry = tx_q->cur_tx;
first_entry = entry; first_entry = entry;
WARN_ON(tx_q->tx_skbuff[first_entry]); WARN_ON(tx_q->tx_skbuff[first_entry]);
...@@ -3096,6 +3165,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3096,6 +3165,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
first = desc; first = desc;
if (has_vlan)
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
enh_desc = priv->plat->enh_desc; enh_desc = priv->plat->enh_desc;
/* To program the descriptors according to the size of the frame */ /* To program the descriptors according to the size of the frame */
if (enh_desc) if (enh_desc)
...@@ -3193,6 +3265,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3193,6 +3265,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
priv->xstats.tx_set_ic_bit++; priv->xstats.tx_set_ic_bit++;
} }
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
/* Ready to fill the first descriptor and set the OWN bit w/o any /* Ready to fill the first descriptor and set the OWN bit w/o any
...@@ -3312,6 +3387,17 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) ...@@ -3312,6 +3387,17 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
break; break;
} }
if (priv->sph && !buf->sec_page) {
buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->sec_page)
break;
buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
dma_sync_single_for_device(priv->device, buf->sec_addr,
len, DMA_FROM_DEVICE);
}
buf->addr = page_pool_get_dma_addr(buf->page); buf->addr = page_pool_get_dma_addr(buf->page);
/* Sync whole allocation to device. This will invalidate old /* Sync whole allocation to device. This will invalidate old
...@@ -3321,6 +3407,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) ...@@ -3321,6 +3407,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
stmmac_set_desc_addr(priv, p, buf->addr); stmmac_set_desc_addr(priv, p, buf->addr);
stmmac_set_desc_sec_addr(priv, p, buf->sec_addr);
stmmac_refill_desc3(priv, rx_q, p); stmmac_refill_desc3(priv, rx_q, p);
rx_q->rx_count_frames++; rx_q->rx_count_frames++;
...@@ -3350,9 +3437,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3350,9 +3437,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
{ {
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue]; struct stmmac_channel *ch = &priv->channel[queue];
unsigned int count = 0, error = 0, len = 0;
int status = 0, coe = priv->hw->rx_csum;
unsigned int next_entry = rx_q->cur_rx; unsigned int next_entry = rx_q->cur_rx;
int coe = priv->hw->rx_csum; struct sk_buff *skb = NULL;
unsigned int count = 0;
if (netif_msg_rx_status(priv)) { if (netif_msg_rx_status(priv)) {
void *rx_head; void *rx_head;
...@@ -3366,10 +3454,30 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3366,10 +3454,30 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true); stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
} }
while (count < limit) { while (count < limit) {
unsigned int hlen = 0, prev_len = 0;
enum pkt_hash_types hash_type;
struct stmmac_rx_buffer *buf; struct stmmac_rx_buffer *buf;
struct dma_desc *np, *p; struct dma_desc *np, *p;
int entry, status; unsigned int sec_len;
int entry;
u32 hash;
if (!count && rx_q->state_saved) {
skb = rx_q->state.skb;
error = rx_q->state.error;
len = rx_q->state.len;
} else {
rx_q->state_saved = false;
skb = NULL;
error = 0;
len = 0;
}
if (count >= limit)
break;
read_again:
sec_len = 0;
entry = next_entry; entry = next_entry;
buf = &rx_q->buf_pool[entry]; buf = &rx_q->buf_pool[entry];
...@@ -3396,6 +3504,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3396,6 +3504,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
np = rx_q->dma_rx + next_entry; np = rx_q->dma_rx + next_entry;
prefetch(np); prefetch(np);
prefetch(page_address(buf->page));
if (priv->extend_desc) if (priv->extend_desc)
stmmac_rx_extended_status(priv, &priv->dev->stats, stmmac_rx_extended_status(priv, &priv->dev->stats,
...@@ -3404,28 +3513,24 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3404,28 +3513,24 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
page_pool_recycle_direct(rx_q->page_pool, buf->page); page_pool_recycle_direct(rx_q->page_pool, buf->page);
priv->dev->stats.rx_errors++; priv->dev->stats.rx_errors++;
buf->page = NULL; buf->page = NULL;
error = 1;
}
if (unlikely(error && (status & rx_not_ls)))
goto read_again;
if (unlikely(error)) {
if (skb)
dev_kfree_skb(skb);
continue;
}
/* Buffer is good. Go on. */
if (likely(status & rx_not_ls)) {
len += priv->dma_buf_sz;
} else { } else {
enum pkt_hash_types hash_type; prev_len = len;
struct sk_buff *skb; len = stmmac_get_rx_frame_len(priv, p, coe);
unsigned int des;
int frame_len;
u32 hash;
stmmac_get_desc_addr(priv, p, &des);
frame_len = stmmac_get_rx_frame_len(priv, p, coe);
/* If frame length is greater than skb buffer size
* (preallocated during init) then the packet is
* ignored
*/
if (frame_len > priv->dma_buf_sz) {
if (net_ratelimit())
netdev_err(priv->dev,
"len %d larger than size (%d)\n",
frame_len, priv->dma_buf_sz);
priv->dev->stats.rx_length_errors++;
continue;
}
/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
* Type frames (LLC/LLC-SNAP) * Type frames (LLC/LLC-SNAP)
...@@ -3436,57 +3541,97 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) ...@@ -3436,57 +3541,97 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
*/ */
if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) || if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) ||
unlikely(status != llc_snap)) unlikely(status != llc_snap))
frame_len -= ETH_FCS_LEN; len -= ETH_FCS_LEN;
}
if (!skb) {
int ret = stmmac_get_rx_header_len(priv, p, &hlen);
if (priv->sph && !ret && (hlen > 0)) {
sec_len = len;
if (!(status & rx_not_ls))
sec_len = sec_len - hlen;
len = hlen;
if (netif_msg_rx_status(priv)) { prefetch(page_address(buf->sec_page));
netdev_dbg(priv->dev, "\tdesc: %p [entry %d] buff=0x%x\n", priv->xstats.rx_split_hdr_pkt_n++;
p, entry, des);
netdev_dbg(priv->dev, "frame size %d, COE: %d\n",
frame_len, status);
} }
skb = netdev_alloc_skb_ip_align(priv->dev, frame_len); skb = napi_alloc_skb(&ch->rx_napi, len);
if (unlikely(!skb)) { if (!skb) {
priv->dev->stats.rx_dropped++; priv->dev->stats.rx_dropped++;
continue; continue;
} }
dma_sync_single_for_cpu(priv->device, buf->addr, dma_sync_single_for_cpu(priv->device, buf->addr, len,
frame_len, DMA_FROM_DEVICE); DMA_FROM_DEVICE);
skb_copy_to_linear_data(skb, page_address(buf->page), skb_copy_to_linear_data(skb, page_address(buf->page),
frame_len); len);
skb_put(skb, frame_len); skb_put(skb, len);
if (netif_msg_pktdata(priv)) { /* Data payload copied into SKB, page ready for recycle */
netdev_dbg(priv->dev, "frame received (%dbytes)", page_pool_recycle_direct(rx_q->page_pool, buf->page);
frame_len); buf->page = NULL;
print_pkt(skb->data, frame_len); } else {
} unsigned int buf_len = len - prev_len;
stmmac_get_rx_hwtstamp(priv, p, np, skb); if (likely(status & rx_not_ls))
buf_len = priv->dma_buf_sz;
stmmac_rx_vlan(priv->dev, skb); dma_sync_single_for_cpu(priv->device, buf->addr,
buf_len, DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
buf->page, 0, buf_len,
priv->dma_buf_sz);
skb->protocol = eth_type_trans(skb, priv->dev); /* Data payload appended into SKB */
page_pool_release_page(rx_q->page_pool, buf->page);
buf->page = NULL;
}
if (unlikely(!coe)) if (sec_len > 0) {
skb_checksum_none_assert(skb); dma_sync_single_for_cpu(priv->device, buf->sec_addr,
else sec_len, DMA_FROM_DEVICE);
skb->ip_summed = CHECKSUM_UNNECESSARY; skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
buf->sec_page, 0, sec_len,
priv->dma_buf_sz);
if (!stmmac_get_rx_hash(priv, p, &hash, &hash_type)) len += sec_len;
skb_set_hash(skb, hash, hash_type);
skb_record_rx_queue(skb, queue); /* Data payload appended into SKB */
napi_gro_receive(&ch->rx_napi, skb); page_pool_release_page(rx_q->page_pool, buf->sec_page);
buf->sec_page = NULL;
}
/* Data payload copied into SKB, page ready for recycle */ if (likely(status & rx_not_ls))
page_pool_recycle_direct(rx_q->page_pool, buf->page); goto read_again;
buf->page = NULL;
priv->dev->stats.rx_packets++; /* Got entire packet into SKB. Finish it. */
priv->dev->stats.rx_bytes += frame_len;
} stmmac_get_rx_hwtstamp(priv, p, np, skb);
stmmac_rx_vlan(priv->dev, skb);
skb->protocol = eth_type_trans(skb, priv->dev);
if (unlikely(!coe))
skb_checksum_none_assert(skb);
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (!stmmac_get_rx_hash(priv, p, &hash, &hash_type))
skb_set_hash(skb, hash, hash_type);
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rx_napi, skb);
priv->dev->stats.rx_packets++;
priv->dev->stats.rx_bytes += len;
}
if (status & rx_not_ls) {
rx_q->state_saved = true;
rx_q->state.skb = skb;
rx_q->state.error = error;
rx_q->state.len = len;
} }
stmmac_rx_refill(priv, queue); stmmac_rx_refill(priv, queue);
...@@ -3632,6 +3777,8 @@ static int stmmac_set_features(struct net_device *netdev, ...@@ -3632,6 +3777,8 @@ static int stmmac_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
struct stmmac_priv *priv = netdev_priv(netdev); struct stmmac_priv *priv = netdev_priv(netdev);
bool sph_en;
u32 chan;
/* Keep the COE Type in case of csum is supporting */ /* Keep the COE Type in case of csum is supporting */
if (features & NETIF_F_RXCSUM) if (features & NETIF_F_RXCSUM)
...@@ -3643,6 +3790,10 @@ static int stmmac_set_features(struct net_device *netdev, ...@@ -3643,6 +3790,10 @@ static int stmmac_set_features(struct net_device *netdev,
*/ */
stmmac_rx_ipc(priv, priv->hw); stmmac_rx_ipc(priv, priv->hw);
sph_en = (priv->hw->rx_csum > 0) && priv->sph;
for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++)
stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan);
return 0; return 0;
} }
...@@ -4335,6 +4486,12 @@ int stmmac_dvr_probe(struct device *device, ...@@ -4335,6 +4486,12 @@ int stmmac_dvr_probe(struct device *device,
dev_info(priv->device, "TSO feature enabled\n"); dev_info(priv->device, "TSO feature enabled\n");
} }
if (priv->dma_cap.sphen) {
ndev->hw_features |= NETIF_F_GRO;
priv->sph = true;
dev_info(priv->device, "SPH feature enabled\n");
}
if (priv->dma_cap.addr64) { if (priv->dma_cap.addr64) {
ret = dma_set_mask_and_coherent(device, ret = dma_set_mask_and_coherent(device,
DMA_BIT_MASK(priv->dma_cap.addr64)); DMA_BIT_MASK(priv->dma_cap.addr64));
...@@ -4361,6 +4518,11 @@ int stmmac_dvr_probe(struct device *device, ...@@ -4361,6 +4518,11 @@ int stmmac_dvr_probe(struct device *device,
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
} }
if (priv->dma_cap.vlins) {
ndev->features |= NETIF_F_HW_VLAN_CTAG_TX;
if (priv->dma_cap.dvlan)
ndev->features |= NETIF_F_HW_VLAN_STAG_TX;
}
#endif #endif
priv->msg_enable = netif_msg_init(debug, default_msg_level); priv->msg_enable = netif_msg_init(debug, default_msg_level);
......
...@@ -45,6 +45,7 @@ struct stmmac_packet_attrs { ...@@ -45,6 +45,7 @@ struct stmmac_packet_attrs {
int size; int size;
int remove_sa; int remove_sa;
u8 id; u8 id;
int sarc;
}; };
static u8 stmmac_test_next_id; static u8 stmmac_test_next_id;
...@@ -230,7 +231,10 @@ static int stmmac_test_loopback_validate(struct sk_buff *skb, ...@@ -230,7 +231,10 @@ static int stmmac_test_loopback_validate(struct sk_buff *skb,
if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst)) if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
goto out; goto out;
} }
if (tpriv->packet->src) { if (tpriv->packet->sarc) {
if (!ether_addr_equal(ehdr->h_source, ehdr->h_dest))
goto out;
} else if (tpriv->packet->src) {
if (!ether_addr_equal(ehdr->h_source, tpriv->packet->src)) if (!ether_addr_equal(ehdr->h_source, tpriv->packet->src))
goto out; goto out;
} }
...@@ -292,7 +296,9 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv, ...@@ -292,7 +296,9 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
tpriv->pt.dev = priv->dev; tpriv->pt.dev = priv->dev;
tpriv->pt.af_packet_priv = tpriv; tpriv->pt.af_packet_priv = tpriv;
tpriv->packet = attr; tpriv->packet = attr;
dev_add_pack(&tpriv->pt);
if (!attr->dont_wait)
dev_add_pack(&tpriv->pt);
skb = stmmac_test_get_udp_skb(priv, attr); skb = stmmac_test_get_udp_skb(priv, attr);
if (!skb) { if (!skb) {
...@@ -315,7 +321,8 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv, ...@@ -315,7 +321,8 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
ret = !tpriv->ok; ret = !tpriv->ok;
cleanup: cleanup:
dev_remove_pack(&tpriv->pt); if (!attr->dont_wait)
dev_remove_pack(&tpriv->pt);
kfree(tpriv); kfree(tpriv);
return ret; return ret;
} }
...@@ -727,6 +734,9 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb, ...@@ -727,6 +734,9 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
struct ethhdr *ehdr; struct ethhdr *ehdr;
struct udphdr *uhdr; struct udphdr *uhdr;
struct iphdr *ihdr; struct iphdr *ihdr;
u16 proto;
proto = tpriv->double_vlan ? ETH_P_8021AD : ETH_P_8021Q;
skb = skb_unshare(skb, GFP_ATOMIC); skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb) if (!skb)
...@@ -736,6 +746,12 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb, ...@@ -736,6 +746,12 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
goto out; goto out;
if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN)) if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
goto out; goto out;
if (tpriv->vlan_id) {
if (skb->vlan_proto != htons(proto))
goto out;
if (skb->vlan_tci != tpriv->vlan_id)
goto out;
}
ehdr = (struct ethhdr *)skb_mac_header(skb); ehdr = (struct ethhdr *)skb_mac_header(skb);
if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst)) if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
...@@ -1004,6 +1020,154 @@ static int stmmac_test_rxp(struct stmmac_priv *priv) ...@@ -1004,6 +1020,154 @@ static int stmmac_test_rxp(struct stmmac_priv *priv)
} }
#endif #endif
static int stmmac_test_desc_sai(struct stmmac_priv *priv)
{
unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct stmmac_packet_attrs attr = { };
int ret;
attr.remove_sa = true;
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
priv->sarc_type = 0x1;
ret = __stmmac_test_loopback(priv, &attr);
priv->sarc_type = 0x0;
return ret;
}
static int stmmac_test_desc_sar(struct stmmac_priv *priv)
{
unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct stmmac_packet_attrs attr = { };
int ret;
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
priv->sarc_type = 0x2;
ret = __stmmac_test_loopback(priv, &attr);
priv->sarc_type = 0x0;
return ret;
}
static int stmmac_test_reg_sai(struct stmmac_priv *priv)
{
unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct stmmac_packet_attrs attr = { };
int ret;
attr.remove_sa = true;
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
if (stmmac_sarc_configure(priv, priv->ioaddr, 0x2))
return -EOPNOTSUPP;
ret = __stmmac_test_loopback(priv, &attr);
stmmac_sarc_configure(priv, priv->ioaddr, 0x0);
return ret;
}
static int stmmac_test_reg_sar(struct stmmac_priv *priv)
{
unsigned char src[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct stmmac_packet_attrs attr = { };
int ret;
attr.sarc = true;
attr.src = src;
attr.dst = priv->dev->dev_addr;
if (stmmac_sarc_configure(priv, priv->ioaddr, 0x3))
return -EOPNOTSUPP;
ret = __stmmac_test_loopback(priv, &attr);
stmmac_sarc_configure(priv, priv->ioaddr, 0x0);
return ret;
}
static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
{
struct stmmac_packet_attrs attr = { };
struct stmmac_test_priv *tpriv;
struct sk_buff *skb = NULL;
int ret = 0;
u16 proto;
if (!priv->dma_cap.vlins)
return -EOPNOTSUPP;
tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL);
if (!tpriv)
return -ENOMEM;
proto = svlan ? ETH_P_8021AD : ETH_P_8021Q;
tpriv->ok = false;
tpriv->double_vlan = svlan;
init_completion(&tpriv->comp);
tpriv->pt.type = svlan ? htons(ETH_P_8021Q) : htons(ETH_P_IP);
tpriv->pt.func = stmmac_test_vlan_validate;
tpriv->pt.dev = priv->dev;
tpriv->pt.af_packet_priv = tpriv;
tpriv->packet = &attr;
tpriv->vlan_id = 0x123;
dev_add_pack(&tpriv->pt);
ret = vlan_vid_add(priv->dev, htons(proto), tpriv->vlan_id);
if (ret)
goto cleanup;
attr.dst = priv->dev->dev_addr;
skb = stmmac_test_get_udp_skb(priv, &attr);
if (!skb) {
ret = -ENOMEM;
goto vlan_del;
}
__vlan_hwaccel_put_tag(skb, htons(proto), tpriv->vlan_id);
skb->protocol = htons(proto);
skb_set_queue_mapping(skb, 0);
ret = dev_queue_xmit(skb);
if (ret)
goto vlan_del;
wait_for_completion_timeout(&tpriv->comp, STMMAC_LB_TIMEOUT);
ret = tpriv->ok ? 0 : -ETIMEDOUT;
vlan_del:
vlan_vid_del(priv->dev, htons(proto), tpriv->vlan_id);
cleanup:
dev_remove_pack(&tpriv->pt);
kfree(tpriv);
return ret;
}
static int stmmac_test_vlanoff(struct stmmac_priv *priv)
{
return stmmac_test_vlanoff_common(priv, false);
}
static int stmmac_test_svlanoff(struct stmmac_priv *priv)
{
if (!priv->dma_cap.dvlan)
return -EOPNOTSUPP;
return stmmac_test_vlanoff_common(priv, true);
}
#define STMMAC_LOOPBACK_NONE 0 #define STMMAC_LOOPBACK_NONE 0
#define STMMAC_LOOPBACK_MAC 1 #define STMMAC_LOOPBACK_MAC 1
#define STMMAC_LOOPBACK_PHY 2 #define STMMAC_LOOPBACK_PHY 2
...@@ -1065,6 +1229,30 @@ static const struct stmmac_test { ...@@ -1065,6 +1229,30 @@ static const struct stmmac_test {
.name = "Flexible RX Parser ", .name = "Flexible RX Parser ",
.lb = STMMAC_LOOPBACK_PHY, .lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_rxp, .fn = stmmac_test_rxp,
}, {
.name = "SA Insertion (desc) ",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_desc_sai,
}, {
.name = "SA Replacement (desc)",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_desc_sar,
}, {
.name = "SA Insertion (reg) ",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_reg_sai,
}, {
.name = "SA Replacement (reg)",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_reg_sar,
}, {
.name = "VLAN TX Insertion ",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_vlanoff,
}, {
.name = "SVLAN TX Insertion ",
.lb = STMMAC_LOOPBACK_PHY,
.fn = stmmac_test_svlanoff,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment