ftgmac100: Rework MAC reset and init

The HW requires a full MAC reset when changing the speed.

Additionally the Aspeed documentation spells out that the
MAC needs to be reset twice with a 10us interval.

We thus move the speed setting and top level reset code
into a new ftgmac100_reset_and_config_mac() function which
handles both. Move the ring pointers initialization there
too in order to reflect the HW change.

Also reduce the timeout for the MAC reset as it shouldn't
take more than 300 clock cycles according to the doc.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Benjamin Herrenschmidt 2017-04-05 12:28:51 +10:00 committed by David S. Miller
parent 855944ce1c
commit 874b55bf62

View File

@ -114,27 +114,64 @@ static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD); iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
} }
static int ftgmac100_reset_hw(struct ftgmac100 *priv) static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
{ {
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
int i; int i;
/* NOTE: reset clears all registers */ /* NOTE: reset clears all registers */
iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR); iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
for (i = 0; i < 5; i++) { iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
priv->base + FTGMAC100_OFFSET_MACCR);
for (i = 0; i < 50; i++) {
unsigned int maccr; unsigned int maccr;
maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR); maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
if (!(maccr & FTGMAC100_MACCR_SW_RST)) if (!(maccr & FTGMAC100_MACCR_SW_RST))
return 0; return 0;
udelay(1000); udelay(1);
} }
netdev_err(netdev, "software reset failed\n"); netdev_err(netdev, "Hardware reset failed\n");
return -EIO; return -EIO;
} }
static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
{
u32 maccr = 0;
switch (priv->cur_speed) {
case SPEED_10:
case 0: /* no link */
break;
case SPEED_100:
maccr |= FTGMAC100_MACCR_FAST_MODE;
break;
case SPEED_1000:
maccr |= FTGMAC100_MACCR_GIGA_MODE;
break;
default:
netdev_err(priv->netdev, "Unknown speed %d !\n",
priv->cur_speed);
break;
}
/* (Re)initialize the queue pointers */
priv->rx_pointer = 0;
priv->tx_clean_pointer = 0;
priv->tx_pointer = 0;
priv->tx_pending = 0;
/* The doc says reset twice with 10us interval */
if (ftgmac100_reset_mac(priv, maccr))
return -EIO;
usleep_range(10, 1000);
return ftgmac100_reset_mac(priv, maccr);
}
static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac) static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
{ {
unsigned int maddr = mac[0] << 8 | mac[1]; unsigned int maddr = mac[0] << 8 | mac[1];
@ -210,35 +247,28 @@ static void ftgmac100_init_hw(struct ftgmac100 *priv)
ftgmac100_set_mac(priv, priv->netdev->dev_addr); ftgmac100_set_mac(priv, priv->netdev->dev_addr);
} }
#define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | \
FTGMAC100_MACCR_RXDMA_EN | \
FTGMAC100_MACCR_TXMAC_EN | \
FTGMAC100_MACCR_RXMAC_EN | \
FTGMAC100_MACCR_CRC_APD | \
FTGMAC100_MACCR_RX_RUNT | \
FTGMAC100_MACCR_RX_BROADPKT)
static void ftgmac100_start_hw(struct ftgmac100 *priv) static void ftgmac100_start_hw(struct ftgmac100 *priv)
{ {
int maccr = MACCR_ENABLE_ALL; u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
switch (priv->cur_speed) { /* Keep the original GMAC and FAST bits */
default: maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE);
case 10:
break;
case 100: /* Add all the main enable bits */
maccr |= FTGMAC100_MACCR_FAST_MODE; maccr |= FTGMAC100_MACCR_TXDMA_EN |
break; FTGMAC100_MACCR_RXDMA_EN |
FTGMAC100_MACCR_TXMAC_EN |
case 1000: FTGMAC100_MACCR_RXMAC_EN |
maccr |= FTGMAC100_MACCR_GIGA_MODE; FTGMAC100_MACCR_CRC_APD |
break; FTGMAC100_MACCR_PHY_LINK_LEVEL |
} FTGMAC100_MACCR_RX_RUNT |
FTGMAC100_MACCR_RX_BROADPKT;
/* Add other bits as needed */
if (priv->cur_duplex == DUPLEX_FULL) if (priv->cur_duplex == DUPLEX_FULL)
maccr |= FTGMAC100_MACCR_FULLDUP; maccr |= FTGMAC100_MACCR_FULLDUP;
/* Hit the HW */
iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR); iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
} }
@ -1156,7 +1186,7 @@ static void ftgmac100_reset_task(struct work_struct *work)
/* Stop and reset the MAC */ /* Stop and reset the MAC */
ftgmac100_stop_hw(priv); ftgmac100_stop_hw(priv);
err = ftgmac100_reset_hw(priv); err = ftgmac100_reset_and_config_mac(priv);
if (err) { if (err) {
/* Not much we can do ... it might come back... */ /* Not much we can do ... it might come back... */
netdev_err(netdev, "attempting to continue...\n"); netdev_err(netdev, "attempting to continue...\n");
@ -1165,12 +1195,6 @@ static void ftgmac100_reset_task(struct work_struct *work)
/* Free all rx and tx buffers */ /* Free all rx and tx buffers */
ftgmac100_free_buffers(priv); ftgmac100_free_buffers(priv);
/* The ring pointers have been reset in HW, reflect this here */
priv->rx_pointer = 0;
priv->tx_clean_pointer = 0;
priv->tx_pointer = 0;
priv->tx_pending = 0;
/* Setup everything again and restart chip */ /* Setup everything again and restart chip */
ftgmac100_init_all(priv, true); ftgmac100_init_all(priv, true);
@ -1209,12 +1233,8 @@ static int ftgmac100_open(struct net_device *netdev)
priv->cur_speed = 0; priv->cur_speed = 0;
} }
priv->rx_pointer = 0; /* Reset the hardware */
priv->tx_clean_pointer = 0; err = ftgmac100_reset_and_config_mac(priv);
priv->tx_pointer = 0;
priv->tx_pending = 0;
err = ftgmac100_reset_hw(priv);
if (err) if (err)
goto err_hw; goto err_hw;