drivers: net: stmmac: reworking the PCS code.
The 3.xx and 4.xx synopsys gmacs have a very similar PCS embedded module and they share almost the same registers: for example: AN_Control, AN_Status, AN_Advertisement, AN_Link_Partner_Ability, AN_Expansion, TBI_Extended_Status. Just the RGMII/SMII Control/Status register differs. So This patch aims to reorganize and enhance the PCS support. It removes the existent support from the dwmac1000/dwmac4_core.c moving basic PCS functions inside a new file called: stmmac_pcs.h. The patch also reviews the available APIs to be better shared among different hardware and easily enhanced to support new features. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a5e4bd9913
commit
70523e639b
@ -285,6 +285,7 @@ Please see the following document:
|
||||
o mmc_core.c/mmc.h: Management MAC Counters;
|
||||
o stmmac_hwtstamp.c: HW timestamp support for PTP;
|
||||
o stmmac_ptp.c: PTP 1588 clock;
|
||||
o stmmac_pcs.h: Physical Coding Sublayer common implementation;
|
||||
o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c
|
||||
for STMicroelectronics SoCs.
|
||||
|
||||
|
@ -232,6 +232,11 @@ struct stmmac_extra_stats {
|
||||
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
|
||||
#define DEFAULT_DMA_PBL 8
|
||||
|
||||
/* PCS status and mask defines */
|
||||
#define PCS_ANE_IRQ BIT(2) /* PCS Auto-Negotiation */
|
||||
#define PCS_LINK_IRQ BIT(1) /* PCS Link */
|
||||
#define PCS_RGSMIIIS_IRQ BIT(0) /* RGMII or SMII Interrupt */
|
||||
|
||||
/* Max/Min RI Watchdog Timer count value */
|
||||
#define MAX_DMA_RIWT 0xff
|
||||
#define MIN_DMA_RIWT 0x20
|
||||
@ -272,9 +277,6 @@ enum dma_irq_status {
|
||||
#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2)
|
||||
#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3)
|
||||
|
||||
#define CORE_PCS_ANE_COMPLETE (1 << 5)
|
||||
#define CORE_PCS_LINK_STATUS (1 << 6)
|
||||
#define CORE_RGMII_IRQ (1 << 7)
|
||||
#define CORE_IRQ_MTL_RX_OVERFLOW BIT(8)
|
||||
|
||||
/* Physical Coding Sublayer */
|
||||
@ -469,9 +471,12 @@ struct stmmac_ops {
|
||||
void (*reset_eee_mode)(struct mac_device_info *hw);
|
||||
void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
|
||||
void (*set_eee_pls)(struct mac_device_info *hw, int link);
|
||||
void (*ctrl_ane)(struct mac_device_info *hw, bool restart);
|
||||
void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv);
|
||||
void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x);
|
||||
/* PCS calls */
|
||||
void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback);
|
||||
void (*pcs_rane)(void __iomem *ioaddr, bool restart);
|
||||
void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
|
||||
};
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
@ -546,6 +551,7 @@ void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
|
||||
extern const struct stmmac_mode_ops ring_mode_ops;
|
||||
extern const struct stmmac_mode_ops chain_mode_ops;
|
||||
extern const struct stmmac_desc_ops dwmac4_desc_ops;
|
||||
|
@ -46,9 +46,6 @@ enum dwmac1000_irq_status {
|
||||
mmc_rx_irq = 0x0020,
|
||||
mmc_irq = 0x0010,
|
||||
pmt_irq = 0x0008,
|
||||
pcs_ane_irq = 0x0004,
|
||||
pcs_link_irq = 0x0002,
|
||||
rgmii_irq = 0x0001,
|
||||
};
|
||||
#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
|
||||
|
||||
@ -90,42 +87,23 @@ enum power_event {
|
||||
(reg * 8))
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 1
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offset */
|
||||
#define GMAC_AN_CTRL 0x000000c0 /* AN control */
|
||||
#define GMAC_AN_STATUS 0x000000c4 /* AN status */
|
||||
#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
|
||||
#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */
|
||||
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
|
||||
#define GMAC_TBI 0x000000d4 /* TBI extend status */
|
||||
#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
|
||||
#define GMAC_PCS_BASE 0x000000c0 /* PCS register base */
|
||||
#define GMAC_RGSMIIIS 0x000000d8 /* RGMII/SMII status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
|
||||
|
||||
/* Register 54 (SGMII/RGMII status register) */
|
||||
#define GMAC_S_R_GMII_LINK 0x8
|
||||
#define GMAC_S_R_GMII_SPEED 0x5
|
||||
#define GMAC_S_R_GMII_SPEED_SHIFT 0x1
|
||||
#define GMAC_S_R_GMII_MODE 0x1
|
||||
#define GMAC_S_R_GMII_SPEED_125 2
|
||||
#define GMAC_S_R_GMII_SPEED_25 1
|
||||
|
||||
/* Common ADV and LPA defines */
|
||||
#define GMAC_ANE_FD (1 << 5)
|
||||
#define GMAC_ANE_HD (1 << 6)
|
||||
#define GMAC_ANE_PSE (3 << 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_RGSMIIIS_LNKMODE BIT(0)
|
||||
#define GMAC_RGSMIIIS_SPEED GENMASK(2, 1)
|
||||
#define GMAC_RGSMIIIS_SPEED_SHIFT 1
|
||||
#define GMAC_RGSMIIIS_LNKSTS BIT(3)
|
||||
#define GMAC_RGSMIIIS_JABTO BIT(4)
|
||||
#define GMAC_RGSMIIIS_FALSECARDET BIT(5)
|
||||
#define GMAC_RGSMIIIS_SMIDRXS BIT(16)
|
||||
/* LNKMOD */
|
||||
#define GMAC_RGSMIIIS_LNKMOD_MASK 0x1
|
||||
/* LNKSPEED */
|
||||
#define GMAC_RGSMIIIS_SPEED_125 0x2
|
||||
#define GMAC_RGSMIIIS_SPEED_25 0x1
|
||||
#define GMAC_RGSMIIIS_SPEED_2_5 0x0
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac1000.h"
|
||||
|
||||
static void dwmac1000_core_init(struct mac_device_info *hw, int mtu)
|
||||
@ -241,6 +242,39 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(ioaddr + GMAC_RGSMIIIS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Check the link status */
|
||||
if (status & GMAC_RGSMIIIS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
|
||||
GMAC_RGSMIIIS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_RGSMIIIS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
@ -260,6 +294,7 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
|
||||
/* MAC trx/rx EEE LPI entry/exit interrupts */
|
||||
if (intr_status & lpiis_irq) {
|
||||
/* Clean LPI interrupt by reading the Reg 12 */
|
||||
@ -275,36 +310,10 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
x->irq_rx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
|
||||
if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
|
||||
readl(ioaddr + GMAC_AN_STATUS);
|
||||
x->irq_pcs_ane_n++;
|
||||
}
|
||||
if (intr_status & rgmii_irq) {
|
||||
u32 status = readl(ioaddr + GMAC_S_R_GMII);
|
||||
x->irq_rgmii_n++;
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
|
||||
/* Save and dump the link status. */
|
||||
if (status & GMAC_S_R_GMII_LINK) {
|
||||
int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
|
||||
GMAC_S_R_GMII_SPEED_SHIFT;
|
||||
x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
|
||||
|
||||
if (speed_value == GMAC_S_R_GMII_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_S_R_GMII_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_link = 1;
|
||||
pr_debug("%s: Link is Up - %d/%s\n", __func__,
|
||||
(int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_debug("%s: Link is Down\n", __func__);
|
||||
}
|
||||
}
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac1000_rgsmii(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -363,38 +372,20 @@ static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
|
||||
writel(value, ioaddr + LPI_TIMER_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart)
|
||||
static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
/* auto negotiation enable and External Loopback enable */
|
||||
u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
|
||||
|
||||
if (restart)
|
||||
value |= GMAC_AN_CTRL_RAN;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL);
|
||||
dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
}
|
||||
|
||||
static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv)
|
||||
static void dwmac1000_rane(void __iomem *ioaddr, bool restart)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV);
|
||||
dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
|
||||
}
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA);
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
|
||||
{
|
||||
dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
|
||||
}
|
||||
|
||||
static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
@ -485,9 +476,10 @@ static const struct stmmac_ops dwmac1000_ops = {
|
||||
.reset_eee_mode = dwmac1000_reset_eee_mode,
|
||||
.set_eee_timer = dwmac1000_set_eee_timer,
|
||||
.set_eee_pls = dwmac1000_set_eee_pls,
|
||||
.ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.get_adv = dwmac1000_get_adv,
|
||||
.debug = dwmac1000_debug,
|
||||
.pcs_ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.pcs_rane = dwmac1000_rane,
|
||||
.pcs_get_adv_lp = dwmac1000_get_adv_lp,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
|
||||
|
@ -24,10 +24,8 @@
|
||||
#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
|
||||
#define GMAC_INT_STATUS 0x000000b0
|
||||
#define GMAC_INT_EN 0x000000b4
|
||||
#define GMAC_AN_CTRL 0x000000e0
|
||||
#define GMAC_AN_STATUS 0x000000e4
|
||||
#define GMAC_AN_ADV 0x000000e8
|
||||
#define GMAC_AN_LPA 0x000000ec
|
||||
#define GMAC_PCS_BASE 0x000000e0
|
||||
#define GMAC_PHYIF_CONTROL_STATUS 0x000000f8
|
||||
#define GMAC_PMT 0x000000c0
|
||||
#define GMAC_VERSION 0x00000110
|
||||
#define GMAC_DEBUG 0x00000114
|
||||
@ -64,19 +62,8 @@ enum dwmac4_irq_status {
|
||||
mmc_rx_irq = 0x00000200,
|
||||
mmc_irq = 0x00000100,
|
||||
pmt_irq = 0x00000010,
|
||||
pcs_ane_irq = 0x00000004,
|
||||
pcs_link_irq = 0x00000002,
|
||||
};
|
||||
|
||||
/* MAC Auto-Neg bitmap*/
|
||||
#define GMAC_AN_CTRL_RAN BIT(9)
|
||||
#define GMAC_AN_CTRL_ANE BIT(12)
|
||||
#define GMAC_AN_CTRL_ELE BIT(14)
|
||||
#define GMAC_AN_FD BIT(5)
|
||||
#define GMAC_AN_HD BIT(6)
|
||||
#define GMAC_AN_PSE_MASK GENMASK(8, 7)
|
||||
#define GMAC_AN_PSE_SHIFT 7
|
||||
|
||||
/* MAC PMT bitmap */
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
@ -250,6 +237,23 @@ enum power_event {
|
||||
#define MTL_DEBUG_RRCSTS_FLUSH 3
|
||||
#define MTL_DEBUG_RWCSTS BIT(0)
|
||||
|
||||
/* SGMII/RGMII status register */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_TC BIT(0)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LUD BIT(1)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT(4)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT(16)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT(19)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_JABTO BIT(20)
|
||||
#define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT(21)
|
||||
/* LNKMOD */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK 0x1
|
||||
/* LNKSPEED */
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_125 0x2
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_25 0x1
|
||||
#define GMAC_PHYIF_CTRLSTATUS_SPEED_2_5 0x0
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
#endif /* __DWMAC4_H__ */
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac4.h"
|
||||
|
||||
static void dwmac4_core_init(struct mac_device_info *hw, int mtu)
|
||||
@ -190,39 +191,53 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac4_ctrl_ane(struct mac_device_info *hw, bool restart)
|
||||
static void dwmac4_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
|
||||
bool loopback)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
|
||||
/* auto negotiation enable and External Loopback enable */
|
||||
u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
|
||||
|
||||
if (restart)
|
||||
value |= GMAC_AN_CTRL_RAN;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL);
|
||||
dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
|
||||
}
|
||||
|
||||
static void dwmac4_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv)
|
||||
static void dwmac4_rane(void __iomem *ioaddr, bool restart)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_AN_ADV);
|
||||
dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
|
||||
}
|
||||
|
||||
if (value & GMAC_AN_FD)
|
||||
adv->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_AN_HD)
|
||||
adv->duplex |= DUPLEX_HALF;
|
||||
static void dwmac4_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
|
||||
{
|
||||
dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
|
||||
}
|
||||
|
||||
adv->pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT;
|
||||
/* RGMII or SMII interface */
|
||||
static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
value = readl(ioaddr + GMAC_AN_LPA);
|
||||
status = readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
if (value & GMAC_AN_FD)
|
||||
adv->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_AN_HD)
|
||||
adv->lp_duplex = DUPLEX_HALF;
|
||||
/* Check the link status */
|
||||
if (status & GMAC_PHYIF_CTRLSTATUS_LNKSTS) {
|
||||
int speed_value;
|
||||
|
||||
adv->lp_pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT;
|
||||
x->pcs_link = 1;
|
||||
|
||||
speed_value = ((status & GMAC_PHYIF_CTRLSTATUS_SPEED) >>
|
||||
GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT);
|
||||
if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_duplex = (status & GMAC_PHYIF_CTRLSTATUS_LNKMOD_MASK);
|
||||
|
||||
pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_info("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dwmac4_irq_status(struct mac_device_info *hw,
|
||||
@ -248,11 +263,6 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
|
||||
if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
|
||||
readl(ioaddr + GMAC_AN_STATUS);
|
||||
x->irq_pcs_ane_n++;
|
||||
}
|
||||
|
||||
mtl_int_qx_status = readl(ioaddr + MTL_INT_STATUS);
|
||||
/* Check MTL Interrupt: Currently only one queue is used: Q0. */
|
||||
if (mtl_int_qx_status & MTL_INT_Q0) {
|
||||
@ -267,6 +277,10 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
|
||||
}
|
||||
}
|
||||
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac4_phystatus(ioaddr, x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -363,8 +377,9 @@ static const struct stmmac_ops dwmac4_ops = {
|
||||
.pmt = dwmac4_pmt,
|
||||
.set_umac_addr = dwmac4_set_umac_addr,
|
||||
.get_umac_addr = dwmac4_get_umac_addr,
|
||||
.ctrl_ane = dwmac4_ctrl_ane,
|
||||
.get_adv = dwmac4_get_adv,
|
||||
.pcs_ctrl_ane = dwmac4_ctrl_ane,
|
||||
.pcs_rane = dwmac4_rane,
|
||||
.pcs_get_adv_lp = dwmac4_get_adv_lp,
|
||||
.debug = dwmac4_debug,
|
||||
.set_filter = dwmac4_set_filter,
|
||||
};
|
||||
|
@ -289,10 +289,10 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
|
||||
ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
|
||||
|
||||
/* Get and convert ADV/LP_ADV from the HW AN registers */
|
||||
if (!priv->hw->mac->get_adv)
|
||||
if (!priv->hw->mac->pcs_get_adv_lp)
|
||||
return -EOPNOTSUPP; /* should never happen indeed */
|
||||
|
||||
priv->hw->mac->get_adv(priv->hw, &adv);
|
||||
priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv);
|
||||
|
||||
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
|
||||
|
||||
@ -376,8 +376,10 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
|
||||
ADVERTISED_10baseT_Full);
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
if (priv->hw->mac->ctrl_ane)
|
||||
priv->hw->mac->ctrl_ane(priv->hw, 1);
|
||||
|
||||
if (priv->hw->mac->pcs_ctrl_ane)
|
||||
priv->hw->mac->pcs_ctrl_ane(priv->ioaddr, 1, 0, 0);
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return 0;
|
||||
@ -452,11 +454,22 @@ stmmac_get_pauseparam(struct net_device *netdev,
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return;
|
||||
|
||||
pause->rx_pause = 0;
|
||||
pause->tx_pause = 0;
|
||||
|
||||
if (priv->pcs && priv->hw->mac->pcs_get_adv_lp) {
|
||||
struct rgmii_adv adv_lp;
|
||||
|
||||
pause->autoneg = 1;
|
||||
priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv_lp);
|
||||
if (!adv_lp.pause)
|
||||
return;
|
||||
} else {
|
||||
if (!(priv->phydev->supported & SUPPORTED_Pause) ||
|
||||
!(priv->phydev->supported & SUPPORTED_Asym_Pause))
|
||||
return;
|
||||
}
|
||||
|
||||
pause->autoneg = priv->phydev->autoneg;
|
||||
|
||||
if (priv->flow_ctrl & FLOW_RX)
|
||||
@ -473,10 +486,19 @@ stmmac_set_pauseparam(struct net_device *netdev,
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int new_pause = FLOW_OFF;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return -EOPNOTSUPP;
|
||||
if (priv->pcs && priv->hw->mac->pcs_get_adv_lp) {
|
||||
struct rgmii_adv adv_lp;
|
||||
|
||||
pause->autoneg = 1;
|
||||
priv->hw->mac->pcs_get_adv_lp(priv->ioaddr, &adv_lp);
|
||||
if (!adv_lp.pause)
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
if (!(phy->supported & SUPPORTED_Pause) ||
|
||||
!(phy->supported & SUPPORTED_Asym_Pause))
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (pause->rx_pause)
|
||||
new_pause |= FLOW_RX;
|
||||
@ -485,14 +507,14 @@ stmmac_set_pauseparam(struct net_device *netdev,
|
||||
|
||||
priv->flow_ctrl = new_pause;
|
||||
phy->autoneg = pause->autoneg;
|
||||
|
||||
if (phy->autoneg) {
|
||||
if (netif_running(netdev))
|
||||
ret = phy_start_aneg(phy);
|
||||
} else
|
||||
priv->hw->mac->flow_ctrl(priv->hw, phy->duplex,
|
||||
priv->flow_ctrl, priv->pause);
|
||||
return ret;
|
||||
return phy_start_aneg(phy);
|
||||
}
|
||||
|
||||
priv->hw->mac->flow_ctrl(priv->hw, phy->duplex, priv->flow_ctrl,
|
||||
priv->pause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmmac_get_ethtool_stats(struct net_device *dev,
|
||||
|
@ -1714,8 +1714,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
|
||||
priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
|
||||
}
|
||||
|
||||
if (priv->pcs && priv->hw->mac->ctrl_ane)
|
||||
priv->hw->mac->ctrl_ane(priv->hw, 0);
|
||||
if (priv->pcs && priv->hw->mac->pcs_ctrl_ane)
|
||||
priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, 0, 0);
|
||||
|
||||
/* set TX ring length */
|
||||
if (priv->hw->dma->set_tx_ring_len)
|
||||
@ -2809,6 +2809,14 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
|
||||
priv->rx_tail_addr,
|
||||
STMMAC_CHAN0);
|
||||
}
|
||||
|
||||
/* PCS link status */
|
||||
if (priv->pcs) {
|
||||
if (priv->xstats.pcs_link)
|
||||
netif_carrier_on(dev);
|
||||
else
|
||||
netif_carrier_off(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* To handle DMA interrupts */
|
||||
|
159
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h
Normal file
159
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* stmmac_pcs.h: Physical Coding Sublayer Header File
|
||||
*
|
||||
* Copyright (C) 2016 STMicroelectronics (R&D) Limited
|
||||
* Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __STMMAC_PCS_H__
|
||||
#define __STMMAC_PCS_H__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offsets */
|
||||
#define GMAC_AN_CTRL(x) (x) /* AN control */
|
||||
#define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */
|
||||
#define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */
|
||||
#define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */
|
||||
#define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */
|
||||
#define GMAC_TBI(x) (x + 0x14) /* TBI extend status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN BIT(9) /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE BIT(12) /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE BIT(14) /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD BIT(16) /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR BIT(17) /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL BIT(18) /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS BIT(2) /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA BIT(3) /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC BIT(5) /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES BIT(8) /* Extended Status */
|
||||
|
||||
/* ADV and LPA defines */
|
||||
#define GMAC_ANE_FD BIT(5)
|
||||
#define GMAC_ANE_HD BIT(6)
|
||||
#define GMAC_ANE_PSE GENMASK(8, 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
#define GMAC_ANE_RFE GENMASK(13, 12)
|
||||
#define GMAC_ANE_RFE_SHIFT 12
|
||||
#define GMAC_ANE_ACK BIT(14)
|
||||
|
||||
/**
|
||||
* dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @intr_status: GMAC core interrupt status
|
||||
* @x: pointer to log these events as stats
|
||||
* Description: it is the ISR for PCS events: Auto-Negotiation Completed and
|
||||
* Link status.
|
||||
*/
|
||||
static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg,
|
||||
unsigned int intr_status,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 val = readl(ioaddr + GMAC_AN_STATUS(reg));
|
||||
|
||||
if (intr_status & PCS_ANE_IRQ) {
|
||||
x->irq_pcs_ane_n++;
|
||||
if (val & GMAC_AN_STATUS_ANC)
|
||||
pr_info("stmmac_pcs: ANE process completed\n");
|
||||
}
|
||||
|
||||
if (intr_status & PCS_LINK_IRQ) {
|
||||
x->irq_pcs_link_n++;
|
||||
if (val & GMAC_AN_STATUS_LS)
|
||||
pr_info("stmmac_pcs: Link Up\n");
|
||||
else
|
||||
pr_info("stmmac_pcs: Link Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_rane - To restart ANE
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @restart: to restart ANE
|
||||
* Description: this is to just restart the Auto-Negotiation.
|
||||
*/
|
||||
static inline void dwmac_rane(void __iomem *ioaddr, u32 reg, bool restart)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
|
||||
|
||||
if (restart)
|
||||
value |= GMAC_AN_CTRL_RAN;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL(reg));
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_ctrl_ane - To program the AN Control Register.
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @ane: to enable the auto-negotiation
|
||||
* @srgmi_ral: to manage MAC-2-MAC SGMII connections.
|
||||
* @loopback: to cause the PHY to loopback tx data into rx path.
|
||||
* Description: this is the main function to configure the AN control register
|
||||
* and init the ANE, select loopback (usually for debugging purpose) and
|
||||
* configure SGMII RAL.
|
||||
*/
|
||||
static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane,
|
||||
bool srgmi_ral, bool loopback)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_AN_CTRL(reg));
|
||||
|
||||
/* Enable and restart the Auto-Negotiation */
|
||||
if (ane)
|
||||
value |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN;
|
||||
|
||||
/* In case of MAC-2-MAC connection, block is configured to operate
|
||||
* according to MAC conf register.
|
||||
*/
|
||||
if (srgmi_ral)
|
||||
value |= GMAC_AN_CTRL_SGMRAL;
|
||||
|
||||
if (loopback)
|
||||
value |= GMAC_AN_CTRL_ELE;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL(reg));
|
||||
}
|
||||
|
||||
/**
|
||||
* dwmac_get_adv_lp - Get ADV and LP cap
|
||||
* @ioaddr: IO registers pointer
|
||||
* @reg: Base address of the AN Control Register.
|
||||
* @adv_lp: structure to store the adv,lp status
|
||||
* Description: this is to expose the ANE advertisement and Link partner ability
|
||||
* status to ethtool support.
|
||||
*/
|
||||
static inline void dwmac_get_adv_lp(void __iomem *ioaddr, u32 reg,
|
||||
struct rgmii_adv *adv_lp)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv_lp->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA(reg));
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv_lp->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv_lp->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv_lp->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
}
|
||||
#endif /* __STMMAC_PCS_H__ */
|
Loading…
Reference in New Issue
Block a user