mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-18 04:54:52 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d83d508b74
10 changed files with 821 additions and 95 deletions
|
@ -75,6 +75,7 @@ struct stmmac_extra_stats {
|
|||
unsigned long rx_missed_cntr;
|
||||
unsigned long rx_overflow_cntr;
|
||||
unsigned long rx_vlan;
|
||||
unsigned long rx_split_hdr_pkt_n;
|
||||
/* Tx/Rx IRQ error info */
|
||||
unsigned long tx_undeflow_irq;
|
||||
unsigned long tx_process_stopped_irq;
|
||||
|
@ -356,6 +357,9 @@ struct dma_features {
|
|||
unsigned int addr64;
|
||||
unsigned int rssen;
|
||||
unsigned int vlhash;
|
||||
unsigned int sphen;
|
||||
unsigned int vlins;
|
||||
unsigned int dvlan;
|
||||
};
|
||||
|
||||
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
|
||||
|
@ -387,6 +391,12 @@ struct dma_features {
|
|||
#define STMMAC_RSS_HASH_KEY_SIZE 40
|
||||
#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 ndesc_ops;
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#define XGMAC_CONFIG_ARPEN BIT(31)
|
||||
#define XGMAC_CONFIG_GPSL GENMASK(29, 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_LM BIT(10)
|
||||
#define XGMAC_CONFIG_IPC BIT(9)
|
||||
|
@ -60,6 +63,11 @@
|
|||
#define XGMAC_VLAN_ETV BIT(16)
|
||||
#define XGMAC_VLAN_VID GENMASK(15, 0)
|
||||
#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_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
|
||||
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
|
||||
|
@ -68,6 +76,7 @@
|
|||
#define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8)
|
||||
#define XGMAC_PSRQ_SHIFT(x) ((x) * 8)
|
||||
#define XGMAC_INT_STATUS 0x000000b0
|
||||
#define XGMAC_LPIIS BIT(5)
|
||||
#define XGMAC_PMTIS BIT(4)
|
||||
#define XGMAC_INT_EN 0x000000b4
|
||||
#define XGMAC_TSIE BIT(12)
|
||||
|
@ -85,10 +94,21 @@
|
|||
#define XGMAC_RWKPKTEN BIT(2)
|
||||
#define XGMAC_MGKPKTEN BIT(1)
|
||||
#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_HWFEAT_SAVLANINS BIT(27)
|
||||
#define XGMAC_HWFEAT_RXCOESEL BIT(16)
|
||||
#define XGMAC_HWFEAT_TXCOESEL BIT(14)
|
||||
#define XGMAC_HWFEAT_EEESEL BIT(13)
|
||||
#define XGMAC_HWFEAT_TSSEL BIT(12)
|
||||
#define XGMAC_HWFEAT_AVSEL BIT(11)
|
||||
#define XGMAC_HWFEAT_RAVSEL BIT(10)
|
||||
|
@ -101,6 +121,7 @@
|
|||
#define XGMAC_HW_FEATURE1 0x00000120
|
||||
#define XGMAC_HWFEAT_RSSEN BIT(20)
|
||||
#define XGMAC_HWFEAT_TSOEN BIT(18)
|
||||
#define XGMAC_HWFEAT_SPHEN BIT(17)
|
||||
#define XGMAC_HWFEAT_ADDR64 GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_TXFIFOSIZE GENMASK(10, 6)
|
||||
#define XGMAC_HWFEAT_RXFIFOSIZE GENMASK(4, 0)
|
||||
|
@ -112,6 +133,7 @@
|
|||
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
|
||||
#define XGMAC_HW_FEATURE3 0x00000128
|
||||
#define XGMAC_HWFEAT_ASP GENMASK(15, 14)
|
||||
#define XGMAC_HWFEAT_DVLAN BIT(13)
|
||||
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
|
||||
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
|
||||
#define XGMAC_HWFEAT_FRPSEL BIT(3)
|
||||
|
@ -145,6 +167,25 @@
|
|||
#define XGMAC_TXTIMESTAMP_NSEC 0x00000d30
|
||||
#define XGMAC_TXTSSTSLO GENMASK(30, 0)
|
||||
#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 */
|
||||
#define XGMAC_MTL_OPMODE 0x00001000
|
||||
|
@ -221,6 +262,7 @@
|
|||
#define XGMAC_RXOVFIS BIT(16)
|
||||
#define XGMAC_ABPSIS BIT(1)
|
||||
#define XGMAC_TXUNFIS BIT(0)
|
||||
#define XGMAC_MAC_REGSIZE (XGMAC_MTL_QINT_STATUS(15) / 4)
|
||||
|
||||
/* DMA Registers */
|
||||
#define XGMAC_DMA_MODE 0x00003000
|
||||
|
@ -258,6 +300,7 @@
|
|||
#define XGMAC_TCEIE BIT(0)
|
||||
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
|
||||
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
|
||||
#define XGMAC_SPH BIT(24)
|
||||
#define XGMAC_PBLx8 BIT(16)
|
||||
#define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x)))
|
||||
#define XGMAC_TxPBL GENMASK(21, 16)
|
||||
|
@ -297,12 +340,17 @@
|
|||
#define XGMAC_TBU BIT(2)
|
||||
#define XGMAC_TPS BIT(1)
|
||||
#define XGMAC_TI BIT(0)
|
||||
#define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4)
|
||||
|
||||
/* Descriptors */
|
||||
#define XGMAC_TDES2_IVT GENMASK(31, 16)
|
||||
#define XGMAC_TDES2_IVT_SHIFT 16
|
||||
#define XGMAC_TDES2_IOC BIT(31)
|
||||
#define XGMAC_TDES2_TTSE BIT(30)
|
||||
#define XGMAC_TDES2_B2L GENMASK(29, 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_TDES3_OWN BIT(31)
|
||||
#define XGMAC_TDES3_CTXT BIT(30)
|
||||
|
@ -311,13 +359,21 @@
|
|||
#define XGMAC_TDES3_CPC GENMASK(27, 26)
|
||||
#define XGMAC_TDES3_CPC_SHIFT 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_SHIFT 19
|
||||
#define XGMAC_TDES3_IVTIR GENMASK(19, 18)
|
||||
#define XGMAC_TDES3_IVTIR_SHIFT 18
|
||||
#define XGMAC_TDES3_TSE BIT(18)
|
||||
#define XGMAC_TDES3_IVLTV BIT(17)
|
||||
#define XGMAC_TDES3_CIC GENMASK(17, 16)
|
||||
#define XGMAC_TDES3_CIC_SHIFT 16
|
||||
#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_RDES2_HL GENMASK(9, 0)
|
||||
#define XGMAC_RDES3_OWN BIT(31)
|
||||
#define XGMAC_RDES3_CTXT BIT(30)
|
||||
#define XGMAC_RDES3_IOC BIT(30)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/crc32.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
||||
static void dwxgmac2_core_init(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));
|
||||
}
|
||||
|
||||
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,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 stat, en;
|
||||
int ret = 0;
|
||||
|
||||
en = readl(ioaddr + XGMAC_INT_EN);
|
||||
stat = readl(ioaddr + XGMAC_INT_STATUS);
|
||||
|
@ -254,7 +265,24 @@ static int dwxgmac2_host_irq_status(struct mac_device_info *hw,
|
|||
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)
|
||||
|
@ -347,6 +375,53 @@ static void dwxgmac2_get_umac_addr(struct mac_device_info *hw,
|
|||
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,
|
||||
int mcbitslog2)
|
||||
{
|
||||
|
@ -997,6 +1072,97 @@ re_enable:
|
|||
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 = {
|
||||
.core_init = dwxgmac2_core_init,
|
||||
.set_mac = dwxgmac2_set_mac,
|
||||
|
@ -1010,17 +1176,17 @@ const struct stmmac_ops dwxgmac210_ops = {
|
|||
.set_mtl_tx_queue_weight = dwxgmac2_set_mtl_tx_queue_weight,
|
||||
.map_mtl_to_dma = dwxgmac2_map_mtl_to_dma,
|
||||
.config_cbs = dwxgmac2_config_cbs,
|
||||
.dump_regs = NULL,
|
||||
.dump_regs = dwxgmac2_dump_regs,
|
||||
.host_irq_status = dwxgmac2_host_irq_status,
|
||||
.host_mtl_irq_status = dwxgmac2_host_mtl_irq_status,
|
||||
.flow_ctrl = dwxgmac2_flow_ctrl,
|
||||
.pmt = dwxgmac2_pmt,
|
||||
.set_umac_addr = dwxgmac2_set_umac_addr,
|
||||
.get_umac_addr = dwxgmac2_get_umac_addr,
|
||||
.set_eee_mode = NULL,
|
||||
.reset_eee_mode = NULL,
|
||||
.set_eee_timer = NULL,
|
||||
.set_eee_pls = NULL,
|
||||
.set_eee_mode = dwxgmac2_set_eee_mode,
|
||||
.reset_eee_mode = dwxgmac2_reset_eee_mode,
|
||||
.set_eee_timer = dwxgmac2_set_eee_timer,
|
||||
.set_eee_pls = dwxgmac2_set_eee_pls,
|
||||
.pcs_ctrl_ane = NULL,
|
||||
.pcs_rane = NULL,
|
||||
.pcs_get_adv_lp = NULL,
|
||||
|
@ -1033,6 +1199,10 @@ const struct stmmac_ops dwxgmac210_ops = {
|
|||
.rss_configure = dwxgmac2_rss_configure,
|
||||
.update_vlan_hash = dwxgmac2_update_vlan_hash,
|
||||
.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)
|
||||
|
|
|
@ -26,16 +26,17 @@ static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x,
|
|||
struct dma_desc *p)
|
||||
{
|
||||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int ret = good_frame;
|
||||
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_OWN))
|
||||
return dma_own;
|
||||
if (likely(!(rdes3 & XGMAC_RDES3_LD)))
|
||||
if (unlikely(rdes3 & XGMAC_RDES3_CTXT))
|
||||
return discard_frame;
|
||||
if (likely(!(rdes3 & XGMAC_RDES3_LD)))
|
||||
return rx_not_ls;
|
||||
if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
p->des3 = cpu_to_le32(XGMAC_RDES3_OWN);
|
||||
p->des3 |= cpu_to_le32(XGMAC_RDES3_OWN);
|
||||
|
||||
if (!disable_rx_ic)
|
||||
p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
|
||||
|
@ -98,11 +99,17 @@ static int dwxgmac2_rx_check_timestamp(void *desc)
|
|||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
bool desc_valid, ts_valid;
|
||||
|
||||
dma_rmb();
|
||||
|
||||
desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
|
||||
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 -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -113,13 +120,10 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
|
|||
unsigned int rdes3 = le32_to_cpu(p->des3);
|
||||
int ret = -EBUSY;
|
||||
|
||||
if (likely(rdes3 & XGMAC_RDES3_CDA)) {
|
||||
if (likely(rdes3 & XGMAC_RDES3_CDA))
|
||||
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,
|
||||
|
@ -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);
|
||||
|
||||
tdes3 = tot_pkt_len & XGMAC_TDES3_FL;
|
||||
tdes3 |= tot_pkt_len & XGMAC_TDES3_FL;
|
||||
if (is_fs)
|
||||
tdes3 |= XGMAC_TDES3_FD;
|
||||
else
|
||||
|
@ -282,6 +286,58 @@ static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash,
|
|||
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 = {
|
||||
.tx_status = dwxgmac2_get_tx_status,
|
||||
.rx_status = dwxgmac2_get_rx_status,
|
||||
|
@ -306,4 +362,9 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = {
|
|||
.set_addr = dwxgmac2_set_addr,
|
||||
.clear = dwxgmac2_clear,
|
||||
.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)
|
|||
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,
|
||||
u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
|
@ -351,8 +359,10 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
|||
|
||||
/* MAC HW feature 0 */
|
||||
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->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->av = (hw_cap & XGMAC_HWFEAT_AVSEL) >> 11;
|
||||
dma_cap->av &= (hw_cap & XGMAC_HWFEAT_RAVSEL) >> 10;
|
||||
|
@ -366,6 +376,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
|||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1);
|
||||
dma_cap->rssen = (hw_cap & XGMAC_HWFEAT_RSSEN) >> 20;
|
||||
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;
|
||||
switch (dma_cap->addr64) {
|
||||
|
@ -403,6 +414,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
|
|||
/* MAC HW feature 3 */
|
||||
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
|
||||
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->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
|
||||
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)
|
|||
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 = {
|
||||
.reset = dwxgmac2_dma_reset,
|
||||
.init = dwxgmac2_dma_init,
|
||||
|
@ -479,7 +507,7 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
|
|||
.init_rx_chan = dwxgmac2_dma_init_rx_chan,
|
||||
.init_tx_chan = dwxgmac2_dma_init_tx_chan,
|
||||
.axi = dwxgmac2_dma_axi,
|
||||
.dump_regs = NULL,
|
||||
.dump_regs = dwxgmac2_dma_dump_regs,
|
||||
.dma_rx_mode = dwxgmac2_dma_rx_mode,
|
||||
.dma_tx_mode = dwxgmac2_dma_tx_mode,
|
||||
.enable_dma_irq = dwxgmac2_enable_dma_irq,
|
||||
|
@ -498,4 +526,5 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
|
|||
.enable_tso = dwxgmac2_enable_tso,
|
||||
.qmode = dwxgmac2_qmode,
|
||||
.set_bfsize = dwxgmac2_set_bfsize,
|
||||
.enable_sph = dwxgmac2_enable_sph,
|
||||
};
|
||||
|
|
|
@ -89,6 +89,12 @@ struct stmmac_desc_ops {
|
|||
/* RSS */
|
||||
int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
|
||||
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...) \
|
||||
|
@ -141,6 +147,16 @@ struct stmmac_desc_ops {
|
|||
stmmac_do_void_callback(__priv, desc, clear, __args)
|
||||
#define stmmac_get_rx_hash(__priv, __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 dma_features;
|
||||
|
@ -191,6 +207,7 @@ struct stmmac_dma_ops {
|
|||
void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
|
||||
void (*qmode)(void __iomem *ioaddr, u32 channel, u8 qmode);
|
||||
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...) \
|
||||
|
@ -247,6 +264,8 @@ struct stmmac_dma_ops {
|
|||
stmmac_do_void_callback(__priv, dma, qmode, __args)
|
||||
#define stmmac_set_dma_bfsize(__priv, __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 net_device;
|
||||
|
@ -339,6 +358,11 @@ struct stmmac_ops {
|
|||
/* VLAN */
|
||||
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
|
||||
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...) \
|
||||
|
@ -413,6 +437,12 @@ struct stmmac_ops {
|
|||
stmmac_do_callback(__priv, mac, rss_configure, __args)
|
||||
#define stmmac_update_vlan_hash(__priv, __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 */
|
||||
struct stmmac_hwtimestamp {
|
||||
|
|
|
@ -58,7 +58,9 @@ struct stmmac_tx_queue {
|
|||
|
||||
struct stmmac_rx_buffer {
|
||||
struct page *page;
|
||||
struct page *sec_page;
|
||||
dma_addr_t addr;
|
||||
dma_addr_t sec_addr;
|
||||
};
|
||||
|
||||
struct stmmac_rx_queue {
|
||||
|
@ -74,6 +76,12 @@ struct stmmac_rx_queue {
|
|||
u32 rx_zeroc_thresh;
|
||||
dma_addr_t dma_rx_phy;
|
||||
u32 rx_tail_addr;
|
||||
unsigned int state_saved;
|
||||
struct {
|
||||
struct sk_buff *skb;
|
||||
unsigned int len;
|
||||
unsigned int error;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct stmmac_channel {
|
||||
|
@ -130,6 +138,8 @@ struct stmmac_priv {
|
|||
int hwts_tx_en;
|
||||
bool tx_path_in_lpi_mode;
|
||||
bool tso;
|
||||
int sph;
|
||||
u32 sarc_type;
|
||||
|
||||
unsigned int dma_buf_sz;
|
||||
unsigned int rx_copybreak;
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
|
||||
#include "stmmac.h"
|
||||
#include "dwmac_dma.h"
|
||||
#include "dwxgmac2.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1060
|
||||
#define MAC100_ETHTOOL_NAME "st_mac100"
|
||||
#define GMAC_ETHTOOL_NAME "st_gmac"
|
||||
#define XGMAC_ETHTOOL_NAME "st_xgmac"
|
||||
|
||||
#define ETHTOOL_DMA_OFFSET 55
|
||||
|
||||
|
@ -65,6 +67,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
|
|||
STMMAC_STAT(rx_missed_cntr),
|
||||
STMMAC_STAT(rx_overflow_cntr),
|
||||
STMMAC_STAT(rx_vlan),
|
||||
STMMAC_STAT(rx_split_hdr_pkt_n),
|
||||
/* Tx/Rx IRQ error info */
|
||||
STMMAC_STAT(tx_undeflow_irq),
|
||||
STMMAC_STAT(tx_process_stopped_irq),
|
||||
|
@ -259,6 +262,8 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
|
|||
|
||||
if (priv->plat->has_gmac || priv->plat->has_gmac4)
|
||||
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
|
||||
strlcpy(info->driver, MAC100_ETHTOOL_NAME,
|
||||
sizeof(info->driver));
|
||||
|
@ -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)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->plat->has_xgmac)
|
||||
return XGMAC_REGSIZE * 4;
|
||||
return REG_SPACE_SIZE;
|
||||
}
|
||||
|
||||
static void stmmac_ethtool_gregs(struct net_device *dev,
|
||||
struct ethtool_regs *regs, void *space)
|
||||
{
|
||||
u32 *reg_space = (u32 *) space;
|
||||
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
memset(reg_space, 0x0, REG_SPACE_SIZE);
|
||||
u32 *reg_space = (u32 *) space;
|
||||
|
||||
stmmac_dump_mac_regs(priv, priv->hw, reg_space);
|
||||
stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
|
||||
/* Copy DMA registers to where ethtool expects them */
|
||||
memcpy(®_space[ETHTOOL_DMA_OFFSET], ®_space[DMA_BUS_MODE / 4],
|
||||
NUM_DWMAC1000_DMA_REGS * 4);
|
||||
|
||||
if (!priv->plat->has_xgmac) {
|
||||
/* Copy DMA registers to where ethtool expects them */
|
||||
memcpy(®_space[ETHTOOL_DMA_OFFSET],
|
||||
®_space[DMA_BUS_MODE / 4],
|
||||
NUM_DWMAC1000_DMA_REGS * 4);
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_nway_reset(struct net_device *dev)
|
||||
|
|
|
@ -432,6 +432,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
|
|||
struct dma_desc *p, struct sk_buff *skb)
|
||||
{
|
||||
struct skb_shared_hwtstamps shhwtstamp;
|
||||
bool found = false;
|
||||
u64 ns = 0;
|
||||
|
||||
if (!priv->hwts_tx_en)
|
||||
|
@ -443,9 +444,13 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
|
|||
|
||||
/* check tx tstamp status */
|
||||
if (stmmac_get_tx_timestamp_status(priv, p)) {
|
||||
/* get the valid tstamp */
|
||||
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));
|
||||
shhwtstamp.hwtstamp = ns_to_ktime(ns);
|
||||
|
||||
|
@ -453,8 +458,6 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
|
|||
/* pass tstamp to stack */
|
||||
skb_tstamp_tx(skb, &shhwtstamp);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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,
|
|||
if (!buf->page)
|
||||
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);
|
||||
stmmac_set_desc_addr(priv, p, buf->addr);
|
||||
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)
|
|||
if (buf->page)
|
||||
page_pool_put_page(rx_q->page_pool, buf->page, false);
|
||||
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)
|
|||
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... */
|
||||
stmmac_start_all_dma(priv);
|
||||
|
||||
|
@ -2770,6 +2798,33 @@ static int stmmac_release(struct net_device *dev)
|
|||
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
|
||||
* @priv: driver private structure
|
||||
|
@ -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);
|
||||
int nfrags = skb_shinfo(skb)->nr_frags;
|
||||
u32 queue = skb_get_queue_mapping(skb);
|
||||
unsigned int first_entry;
|
||||
struct stmmac_tx_queue *tx_q;
|
||||
unsigned int first_entry;
|
||||
int tmp_pay_len = 0;
|
||||
u32 pay_len, mss;
|
||||
u8 proto_hdr_len;
|
||||
dma_addr_t des;
|
||||
bool has_vlan;
|
||||
int i;
|
||||
|
||||
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)
|
|||
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;
|
||||
WARN_ON(tx_q->tx_skbuff[first_entry]);
|
||||
|
||||
desc = tx_q->dma_tx + first_entry;
|
||||
first = desc;
|
||||
|
||||
if (has_vlan)
|
||||
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
|
||||
|
||||
/* first descriptor: fill Headers on Buf1 */
|
||||
des = dma_map_single(priv->device, skb->data, skb_headlen(skb),
|
||||
DMA_TO_DEVICE);
|
||||
|
@ -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++;
|
||||
}
|
||||
|
||||
if (priv->sarc_type)
|
||||
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
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)
|
|||
unsigned int first_entry;
|
||||
unsigned int enh_desc;
|
||||
dma_addr_t des;
|
||||
bool has_vlan;
|
||||
int entry;
|
||||
|
||||
tx_q = &priv->tx_queue[queue];
|
||||
|
@ -3083,6 +3149,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
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;
|
||||
first_entry = 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)
|
|||
|
||||
first = desc;
|
||||
|
||||
if (has_vlan)
|
||||
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
|
||||
|
||||
enh_desc = priv->plat->enh_desc;
|
||||
/* To program the descriptors according to the size of the frame */
|
||||
if (enh_desc)
|
||||
|
@ -3193,6 +3265,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
priv->xstats.tx_set_ic_bit++;
|
||||
}
|
||||
|
||||
if (priv->sarc_type)
|
||||
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
/* 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)
|
|||
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);
|
||||
|
||||
/* 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)
|
|||
DMA_FROM_DEVICE);
|
||||
|
||||
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);
|
||||
|
||||
rx_q->rx_count_frames++;
|
||||
|
@ -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_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;
|
||||
int coe = priv->hw->rx_csum;
|
||||
unsigned int count = 0;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if (netif_msg_rx_status(priv)) {
|
||||
void *rx_head;
|
||||
|
@ -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);
|
||||
}
|
||||
while (count < limit) {
|
||||
unsigned int hlen = 0, prev_len = 0;
|
||||
enum pkt_hash_types hash_type;
|
||||
struct stmmac_rx_buffer *buf;
|
||||
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;
|
||||
buf = &rx_q->buf_pool[entry];
|
||||
|
||||
|
@ -3396,6 +3504,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
|
|||
np = rx_q->dma_rx + next_entry;
|
||||
|
||||
prefetch(np);
|
||||
prefetch(page_address(buf->page));
|
||||
|
||||
if (priv->extend_desc)
|
||||
stmmac_rx_extended_status(priv, &priv->dev->stats,
|
||||
|
@ -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);
|
||||
priv->dev->stats.rx_errors++;
|
||||
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 {
|
||||
enum pkt_hash_types hash_type;
|
||||
struct sk_buff *skb;
|
||||
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;
|
||||
}
|
||||
prev_len = len;
|
||||
len = stmmac_get_rx_frame_len(priv, p, coe);
|
||||
|
||||
/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
|
||||
* Type frames (LLC/LLC-SNAP)
|
||||
|
@ -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) ||
|
||||
unlikely(status != llc_snap))
|
||||
frame_len -= ETH_FCS_LEN;
|
||||
len -= ETH_FCS_LEN;
|
||||
}
|
||||
|
||||
if (netif_msg_rx_status(priv)) {
|
||||
netdev_dbg(priv->dev, "\tdesc: %p [entry %d] buff=0x%x\n",
|
||||
p, entry, des);
|
||||
netdev_dbg(priv->dev, "frame size %d, COE: %d\n",
|
||||
frame_len, status);
|
||||
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;
|
||||
|
||||
prefetch(page_address(buf->sec_page));
|
||||
priv->xstats.rx_split_hdr_pkt_n++;
|
||||
}
|
||||
|
||||
skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
|
||||
if (unlikely(!skb)) {
|
||||
skb = napi_alloc_skb(&ch->rx_napi, len);
|
||||
if (!skb) {
|
||||
priv->dev->stats.rx_dropped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(priv->device, buf->addr,
|
||||
frame_len, DMA_FROM_DEVICE);
|
||||
dma_sync_single_for_cpu(priv->device, buf->addr, len,
|
||||
DMA_FROM_DEVICE);
|
||||
skb_copy_to_linear_data(skb, page_address(buf->page),
|
||||
frame_len);
|
||||
skb_put(skb, frame_len);
|
||||
|
||||
if (netif_msg_pktdata(priv)) {
|
||||
netdev_dbg(priv->dev, "frame received (%dbytes)",
|
||||
frame_len);
|
||||
print_pkt(skb->data, 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);
|
||||
len);
|
||||
skb_put(skb, len);
|
||||
|
||||
/* Data payload copied into SKB, page ready for recycle */
|
||||
page_pool_recycle_direct(rx_q->page_pool, buf->page);
|
||||
buf->page = NULL;
|
||||
} else {
|
||||
unsigned int buf_len = len - prev_len;
|
||||
|
||||
priv->dev->stats.rx_packets++;
|
||||
priv->dev->stats.rx_bytes += frame_len;
|
||||
if (likely(status & rx_not_ls))
|
||||
buf_len = priv->dma_buf_sz;
|
||||
|
||||
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);
|
||||
|
||||
/* Data payload appended into SKB */
|
||||
page_pool_release_page(rx_q->page_pool, buf->page);
|
||||
buf->page = NULL;
|
||||
}
|
||||
|
||||
if (sec_len > 0) {
|
||||
dma_sync_single_for_cpu(priv->device, buf->sec_addr,
|
||||
sec_len, DMA_FROM_DEVICE);
|
||||
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
|
||||
buf->sec_page, 0, sec_len,
|
||||
priv->dma_buf_sz);
|
||||
|
||||
len += sec_len;
|
||||
|
||||
/* Data payload appended into SKB */
|
||||
page_pool_release_page(rx_q->page_pool, buf->sec_page);
|
||||
buf->sec_page = NULL;
|
||||
}
|
||||
|
||||
if (likely(status & rx_not_ls))
|
||||
goto read_again;
|
||||
|
||||
/* Got entire packet into SKB. Finish it. */
|
||||
|
||||
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);
|
||||
|
@ -3632,6 +3777,8 @@ static int stmmac_set_features(struct net_device *netdev,
|
|||
netdev_features_t features)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
bool sph_en;
|
||||
u32 chan;
|
||||
|
||||
/* Keep the COE Type in case of csum is supporting */
|
||||
if (features & NETIF_F_RXCSUM)
|
||||
|
@ -3643,6 +3790,10 @@ static int stmmac_set_features(struct net_device *netdev,
|
|||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -4335,6 +4486,12 @@ int stmmac_dvr_probe(struct device *device,
|
|||
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) {
|
||||
ret = dma_set_mask_and_coherent(device,
|
||||
DMA_BIT_MASK(priv->dma_cap.addr64));
|
||||
|
@ -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_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
|
||||
priv->msg_enable = netif_msg_init(debug, default_msg_level);
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ struct stmmac_packet_attrs {
|
|||
int size;
|
||||
int remove_sa;
|
||||
u8 id;
|
||||
int sarc;
|
||||
};
|
||||
|
||||
static u8 stmmac_test_next_id;
|
||||
|
@ -230,7 +231,10 @@ static int stmmac_test_loopback_validate(struct sk_buff *skb,
|
|||
if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
|
||||
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))
|
||||
goto out;
|
||||
}
|
||||
|
@ -292,7 +296,9 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
|
|||
tpriv->pt.dev = priv->dev;
|
||||
tpriv->pt.af_packet_priv = tpriv;
|
||||
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);
|
||||
if (!skb) {
|
||||
|
@ -315,7 +321,8 @@ static int __stmmac_test_loopback(struct stmmac_priv *priv,
|
|||
ret = !tpriv->ok;
|
||||
|
||||
cleanup:
|
||||
dev_remove_pack(&tpriv->pt);
|
||||
if (!attr->dont_wait)
|
||||
dev_remove_pack(&tpriv->pt);
|
||||
kfree(tpriv);
|
||||
return ret;
|
||||
}
|
||||
|
@ -727,6 +734,9 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
|
|||
struct ethhdr *ehdr;
|
||||
struct udphdr *uhdr;
|
||||
struct iphdr *ihdr;
|
||||
u16 proto;
|
||||
|
||||
proto = tpriv->double_vlan ? ETH_P_8021AD : ETH_P_8021Q;
|
||||
|
||||
skb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
|
@ -736,6 +746,12 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
|
|||
goto out;
|
||||
if (skb_headlen(skb) < (STMMAC_TEST_PKT_SIZE - ETH_HLEN))
|
||||
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);
|
||||
if (!ether_addr_equal(ehdr->h_dest, tpriv->packet->dst))
|
||||
|
@ -1004,6 +1020,154 @@ static int stmmac_test_rxp(struct stmmac_priv *priv)
|
|||
}
|
||||
#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_MAC 1
|
||||
#define STMMAC_LOOPBACK_PHY 2
|
||||
|
@ -1065,6 +1229,30 @@ static const struct stmmac_test {
|
|||
.name = "Flexible RX Parser ",
|
||||
.lb = STMMAC_LOOPBACK_PHY,
|
||||
.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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue