Skip to content

Commit

Permalink
Merge branch 'stmmac-next'
Browse files Browse the repository at this point in the history
Giuseppe Cavallaro says:

====================
stmmac: rework and enhance the PCS support

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 these patches aim to reorganize and enhance the PCS support;
to do that, some small inline functions have been provided and
also some rework to the PCS ISR part has been done.

In the end, the SGMII for MAC2MAC connection has been introduced.

All patches have been built on top of net-next git and, as for
the previous version, not fully tested.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 28, 2016
2 parents a5e4bd9 + 02e57b9 commit 8f659ae
Show file tree
Hide file tree
Showing 13 changed files with 474 additions and 194 deletions.
3 changes: 3 additions & 0 deletions Documentation/devicetree/bindings/net/stmmac.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ Optional properties:
supported by this device instance
- snps,perfect-filter-entries: Number of perfect filter entries supported
by this device instance
- snps,ps-speed: port selection speed that can be passed to the core when
PCS is supported. For example, this is used in case of SGMII
and MAC2MAC connection.
- AXI BUS Mode parameters: below the list of all the parameters to program the
AXI register inside the DMA module:
- snps,lpi_en: enable Low Power Interface
Expand Down
1 change: 1 addition & 0 deletions Documentation/networking/stmmac.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
19 changes: 14 additions & 5 deletions drivers/net/ethernet/stmicro/stmmac/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -524,6 +529,9 @@ struct mac_device_info {
int unicast_filter_entries;
int mcast_bits_log2;
unsigned int rx_csum;
unsigned int pcs;
unsigned int pmt;
unsigned int ps;
};

struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
Expand All @@ -546,6 +554,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;
Expand Down
86 changes: 37 additions & 49 deletions drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,26 @@
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */

#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
enum dwmac1000_irq_status {
lpiis_irq = 0x400,
time_stamp_irq = 0x0200,
mmc_rx_csum_offload_irq = 0x0080,
mmc_tx_irq = 0x0040,
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 */
#define GMAC_INT_STATUS_PMT BIT(3)
#define GMAC_INT_STATUS_MMCIS BIT(4)
#define GMAC_INT_STATUS_MMCRIS BIT(5)
#define GMAC_INT_STATUS_MMCTIS BIT(6)
#define GMAC_INT_STATUS_MMCCSUM BIT(7)
#define GMAC_INT_STATUS_TSTAMP BIT(9)
#define GMAC_INT_STATUS_LPIIS BIT(10)

/* interrupt mask register */
#define GMAC_INT_MASK 0x0000003c
#define GMAC_INT_DISABLE_RGMII BIT(0)
#define GMAC_INT_DISABLE_PCSLINK BIT(1)
#define GMAC_INT_DISABLE_PCSAN BIT(2)
#define GMAC_INT_DISABLE_PMT BIT(3)
#define GMAC_INT_DISABLE_TIMESTAMP BIT(9)
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \
GMAC_INT_DISABLE_PCSLINK | \
GMAC_INT_DISABLE_PCSAN)
#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \
GMAC_INT_DISABLE_PCS)

/* PMT Control and Status */
#define GMAC_PMT 0x0000002c
Expand Down Expand Up @@ -90,42 +97,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 */

/* 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
#define GMAC_PCS_BASE 0x000000c0 /* PCS register base */
#define GMAC_RGSMIIIS 0x000000d8 /* RGMII/SMII status */

/* 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 */
Expand Down
147 changes: 82 additions & 65 deletions drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,48 @@
#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)
{
void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + GMAC_CONTROL);

/* Configure GMAC core */
value |= GMAC_CORE_INIT;

if (mtu > 1500)
value |= GMAC_CONTROL_2K;
if (mtu > 2000)
value |= GMAC_CONTROL_JE;

if (hw->ps) {
value |= GMAC_CONTROL_TE;

if (hw->ps == SPEED_1000) {
value &= ~GMAC_CONTROL_PS;
} else {
value |= GMAC_CONTROL_PS;

if (hw->ps == SPEED_10)
value &= ~GMAC_CONTROL_FES;
else
value |= GMAC_CONTROL_FES;
}
}

writel(value, ioaddr + GMAC_CONTROL);

/* Mask GMAC interrupts */
writel(0x207, ioaddr + GMAC_INT_MASK);
value = GMAC_INT_DEFAULT_MASK;

if (hw->pmt)
value &= ~GMAC_INT_DISABLE_PMT;
if (hw->pcs)
value &= ~GMAC_INT_DISABLE_PCS;

writel(value, ioaddr + GMAC_INT_MASK);

#ifdef STMMAC_VLAN_TAG_USED
/* Tag detection without filtering */
Expand Down Expand Up @@ -241,6 +267,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)
{
Expand All @@ -249,19 +308,20 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
int ret = 0;

/* Not used events (e.g. MMC interrupts) are not handled. */
if ((intr_status & mmc_tx_irq))
if ((intr_status & GMAC_INT_STATUS_MMCTIS))
x->mmc_tx_irq_n++;
if (unlikely(intr_status & mmc_rx_irq))
if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
x->mmc_rx_irq_n++;
if (unlikely(intr_status & mmc_rx_csum_offload_irq))
if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
x->mmc_rx_csum_offload_irq_n++;
if (unlikely(intr_status & pmt_irq)) {
if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
readl(ioaddr + GMAC_PMT);
x->irq_receive_pmt_irq_n++;
}
/* MAC trx/rx EEE LPI entry/exit interrupts */
if (intr_status & lpiis_irq) {

/* MAC tx/rx EEE LPI entry/exit interrupts */
if (intr_status & GMAC_INT_STATUS_LPIIS) {
/* Clean LPI interrupt by reading the Reg 12 */
ret = readl(ioaddr + LPI_CTRL_STATUS);

Expand All @@ -275,36 +335,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++;

/* 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;
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);

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;
}
Expand Down Expand Up @@ -363,38 +397,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);

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;
dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
}

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)
Expand Down Expand Up @@ -485,9 +501,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,
Expand Down
Loading

0 comments on commit 8f659ae

Please sign in to comment.