summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFlorinel Iordache <florinel.iordache@nxp.com>2017-08-10 16:47:04 +0300
committerDavid S. Miller <davem@davemloft.net>2017-08-11 14:37:36 -0700
commite37425c23afd34fb73d329d2ca7b31ae1e6f2be5 (patch)
treef714b707bbedcdd77beb6b4d12737b7db330f35b /drivers
parent720a8478b2689bd221e4a8744e1695de7966a22f (diff)
downloadlinux-e37425c23afd34fb73d329d2ca7b31ae1e6f2be5.tar.bz2
fsl/fman: implement several errata workarounds
Implemented workarounds for the following dTSEC Erratum: A002, A004, A0012, A0014, A004839 on several operations that involve MAC CFG register changes: adjust link, rx pause frames, modify MAC address. Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com> Acked-by: Madalin Bucur <madalin.bucur@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_dtsec.c118
1 files changed, 93 insertions, 25 deletions
diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
index 98bba10fc38c..ea43b4974149 100644
--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
@@ -123,7 +123,7 @@
#define DTSEC_ECNTRL_R100M 0x00000008
#define DTSEC_ECNTRL_QSGMIIM 0x00000001
-#define DTSEC_TCTRL_GTS 0x00000020
+#define TCTRL_GTS 0x00000020
#define RCTRL_PAL_MASK 0x001f0000
#define RCTRL_PAL_SHIFT 16
@@ -863,6 +863,52 @@ int dtsec_cfg_pad_and_crc(struct fman_mac *dtsec, bool new_val)
return 0;
}
+static void graceful_start(struct fman_mac *dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *regs = dtsec->regs;
+
+ if (mode & COMM_MODE_TX)
+ iowrite32be(ioread32be(&regs->tctrl) &
+ ~TCTRL_GTS, &regs->tctrl);
+ if (mode & COMM_MODE_RX)
+ iowrite32be(ioread32be(&regs->rctrl) &
+ ~RCTRL_GRS, &regs->rctrl);
+}
+
+static void graceful_stop(struct fman_mac *dtsec, enum comm_mode mode)
+{
+ struct dtsec_regs __iomem *regs = dtsec->regs;
+ u32 tmp;
+
+ /* Graceful stop - Assert the graceful Rx stop bit */
+ if (mode & COMM_MODE_RX) {
+ tmp = ioread32be(&regs->rctrl) | RCTRL_GRS;
+ iowrite32be(tmp, &regs->rctrl);
+
+ if (dtsec->fm_rev_info.major == 2) {
+ /* Workaround for dTSEC Errata A002 */
+ usleep_range(100, 200);
+ } else {
+ /* Workaround for dTSEC Errata A004839 */
+ usleep_range(10, 50);
+ }
+ }
+
+ /* Graceful stop - Assert the graceful Tx stop bit */
+ if (mode & COMM_MODE_TX) {
+ if (dtsec->fm_rev_info.major == 2) {
+ /* dTSEC Errata A004: Do not use TCTRL[GTS]=1 */
+ pr_debug("GTS not supported due to DTSEC_A004 Errata.\n");
+ } else {
+ tmp = ioread32be(&regs->tctrl) | TCTRL_GTS;
+ iowrite32be(tmp, &regs->tctrl);
+
+ /* Workaround for dTSEC Errata A0012, A0014 */
+ usleep_range(10, 50);
+ }
+ }
+}
+
int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
@@ -880,13 +926,8 @@ int dtsec_enable(struct fman_mac *dtsec, enum comm_mode mode)
iowrite32be(tmp, &regs->maccfg1);
- /* Graceful start - clear the graceful receive stop bit */
- if (mode & COMM_MODE_TX)
- iowrite32be(ioread32be(&regs->tctrl) & ~DTSEC_TCTRL_GTS,
- &regs->tctrl);
- if (mode & COMM_MODE_RX)
- iowrite32be(ioread32be(&regs->rctrl) & ~RCTRL_GRS,
- &regs->rctrl);
+ /* Graceful start - clear the graceful Rx/Tx stop bit */
+ graceful_start(dtsec, mode);
return 0;
}
@@ -899,23 +940,8 @@ int dtsec_disable(struct fman_mac *dtsec, enum comm_mode mode)
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
- /* Gracefull stop - Assert the graceful transmit stop bit */
- if (mode & COMM_MODE_RX) {
- tmp = ioread32be(&regs->rctrl) | RCTRL_GRS;
- iowrite32be(tmp, &regs->rctrl);
-
- if (dtsec->fm_rev_info.major == 2)
- usleep_range(100, 200);
- else
- udelay(10);
- }
-
- if (mode & COMM_MODE_TX) {
- if (dtsec->fm_rev_info.major == 2)
- pr_debug("GTS not supported due to DTSEC_A004 errata.\n");
- else
- pr_debug("GTS not supported due to DTSEC_A0014 errata.\n");
- }
+ /* Graceful stop - Assert the graceful Rx/Tx stop bit */
+ graceful_stop(dtsec, mode);
tmp = ioread32be(&regs->maccfg1);
if (mode & COMM_MODE_RX)
@@ -933,11 +959,19 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
u16 pause_time, u16 __maybe_unused thresh_time)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
+ enum comm_mode mode = COMM_MODE_NONE;
u32 ptv = 0;
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
+ if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
+ mode |= COMM_MODE_RX;
+ if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
+ mode |= COMM_MODE_TX;
+
+ graceful_stop(dtsec, mode);
+
if (pause_time) {
/* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
@@ -958,17 +992,27 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
iowrite32be(ioread32be(&regs->maccfg1) & ~MACCFG1_TX_FLOW,
&regs->maccfg1);
+ graceful_start(dtsec, mode);
+
return 0;
}
int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
+ enum comm_mode mode = COMM_MODE_NONE;
u32 tmp;
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
+ if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
+ mode |= COMM_MODE_RX;
+ if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
+ mode |= COMM_MODE_TX;
+
+ graceful_stop(dtsec, mode);
+
tmp = ioread32be(&regs->maccfg1);
if (en)
tmp |= MACCFG1_RX_FLOW;
@@ -976,20 +1020,34 @@ int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
tmp &= ~MACCFG1_RX_FLOW;
iowrite32be(tmp, &regs->maccfg1);
+ graceful_start(dtsec, mode);
+
return 0;
}
int dtsec_modify_mac_address(struct fman_mac *dtsec, enet_addr_t *enet_addr)
{
+ struct dtsec_regs __iomem *regs = dtsec->regs;
+ enum comm_mode mode = COMM_MODE_NONE;
+
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
+ if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
+ mode |= COMM_MODE_RX;
+ if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
+ mode |= COMM_MODE_TX;
+
+ graceful_stop(dtsec, mode);
+
/* Initialize MAC Station Address registers (1 & 2)
* Station address have to be swapped (big endian to little endian
*/
dtsec->addr = ENET_ADDR_TO_UINT64(*enet_addr);
set_mac_address(dtsec->regs, (u8 *)(*enet_addr));
+ graceful_start(dtsec, mode);
+
return 0;
}
@@ -1162,11 +1220,19 @@ int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val)
int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
+ enum comm_mode mode = COMM_MODE_NONE;
u32 tmp;
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
+ if ((ioread32be(&regs->rctrl) & RCTRL_GRS) == 0)
+ mode |= COMM_MODE_RX;
+ if ((ioread32be(&regs->tctrl) & TCTRL_GTS) == 0)
+ mode |= COMM_MODE_TX;
+
+ graceful_stop(dtsec, mode);
+
tmp = ioread32be(&regs->maccfg2);
/* Full Duplex */
@@ -1186,6 +1252,8 @@ int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
tmp &= ~DTSEC_ECNTRL_R100M;
iowrite32be(tmp, &regs->ecntrl);
+ graceful_start(dtsec, mode);
+
return 0;
}