From 635d320abfa6dc3c0e1d00e3ceae567dd0e55a5b Mon Sep 17 00:00:00 2001 From: Tudor Florea Date: Thu, 8 Oct 2015 22:42:49 +0200 Subject: initial commit for Enea Linux 5.0 arm Signed-off-by: Tudor Florea --- ...rofalcon-Update-xgbe-drivers-for-B0-board.patch | 3557 ++++++++++++++++++++ 1 file changed, 3557 insertions(+) create mode 100644 recipes-kernel/linux/linux-hierofalcon/319-Hierofalcon-Update-xgbe-drivers-for-B0-board.patch (limited to 'recipes-kernel/linux/linux-hierofalcon/319-Hierofalcon-Update-xgbe-drivers-for-B0-board.patch') diff --git a/recipes-kernel/linux/linux-hierofalcon/319-Hierofalcon-Update-xgbe-drivers-for-B0-board.patch b/recipes-kernel/linux/linux-hierofalcon/319-Hierofalcon-Update-xgbe-drivers-for-B0-board.patch new file mode 100644 index 0000000..6c45b11 --- /dev/null +++ b/recipes-kernel/linux/linux-hierofalcon/319-Hierofalcon-Update-xgbe-drivers-for-B0-board.patch @@ -0,0 +1,3557 @@ +From 675ffdbcc905bc44a9fef9a7f6569493a3a8efe1 Mon Sep 17 00:00:00 2001 +From: Adrian Calianu +Date: Fri, 28 Aug 2015 17:35:57 +0200 +Subject: [PATCH] Hierofalcon: Update xgbe drivers for B0 board + +Port ethernet drivers for AMD xgbe from 4.1 kernel to 3.19 +in order to have ethernet working on B0 board + +Signed-off-by: Adrian Calianu +--- + drivers/net/ethernet/amd/xgbe/xgbe-common.h | 2 + + drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 2 +- + drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 34 +- + drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 147 +++- + drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 309 +++---- + drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 29 +- + drivers/net/ethernet/amd/xgbe/xgbe-main.c | 207 ++++- + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 29 +- + drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 21 +- + drivers/net/ethernet/amd/xgbe/xgbe.h | 46 +- + drivers/net/phy/amd-xgbe-phy.c | 1142 ++++++++++++++++++-------- + include/linux/clocksource.h | 9 + + 12 files changed, 1284 insertions(+), 693 deletions(-) + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h +index 29a0927..34c28aa 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h +@@ -365,6 +365,8 @@ + #define MAC_HWF0R_TXCOESEL_WIDTH 1 + #define MAC_HWF0R_VLHASH_INDEX 4 + #define MAC_HWF0R_VLHASH_WIDTH 1 ++#define MAC_HWF1R_ADDR64_INDEX 14 ++#define MAC_HWF1R_ADDR64_WIDTH 2 + #define MAC_HWF1R_ADVTHWORD_INDEX 13 + #define MAC_HWF1R_ADVTHWORD_WIDTH 1 + #define MAC_HWF1R_DBGMEMA_INDEX 19 +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +index 76479d0..2c063b6 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +@@ -328,7 +328,7 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata) + + buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); + pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); +- if (pdata->xgbe_debugfs == NULL) { ++ if (!pdata->xgbe_debugfs) { + netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); + return; + } +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +index a50891f..5c92fb7 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +@@ -263,7 +263,7 @@ static int xgbe_alloc_pages(struct xgbe_prv_data *pdata, + int ret; + + /* Try to obtain pages, decreasing order if necessary */ +- gfp |= __GFP_COLD | __GFP_COMP; ++ gfp |= __GFP_COLD | __GFP_COMP | __GFP_NOWARN; + while (order >= 0) { + pages = alloc_pages(gfp, order); + if (pages) +@@ -422,7 +422,6 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) + + ring->cur = 0; + ring->dirty = 0; +- memset(&ring->rx, 0, sizeof(ring->rx)); + + hw_if->rx_desc_init(channel); + } +@@ -621,35 +620,6 @@ err_out: + return 0; + } + +-static void xgbe_realloc_rx_buffer(struct xgbe_channel *channel) +-{ +- struct xgbe_prv_data *pdata = channel->pdata; +- struct xgbe_hw_if *hw_if = &pdata->hw_if; +- struct xgbe_ring *ring = channel->rx_ring; +- struct xgbe_ring_data *rdata; +- int i; +- +- DBGPR("-->xgbe_realloc_rx_buffer: rx_ring->rx.realloc_index = %u\n", +- ring->rx.realloc_index); +- +- for (i = 0; i < ring->dirty; i++) { +- rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index); +- +- /* Reset rdata values */ +- xgbe_unmap_rdata(pdata, rdata); +- +- if (xgbe_map_rx_buffer(pdata, ring, rdata)) +- break; +- +- hw_if->rx_desc_reset(rdata); +- +- ring->rx.realloc_index++; +- } +- ring->dirty = 0; +- +- DBGPR("<--xgbe_realloc_rx_buffer\n"); +-} +- + void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) + { + DBGPR("-->xgbe_init_function_ptrs_desc\n"); +@@ -657,7 +627,7 @@ void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) + desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; + desc_if->free_ring_resources = xgbe_free_ring_resources; + desc_if->map_tx_skb = xgbe_map_tx_skb; +- desc_if->realloc_rx_buffer = xgbe_realloc_rx_buffer; ++ desc_if->map_rx_buffer = xgbe_map_rx_buffer; + desc_if->unmap_rdata = xgbe_unmap_rdata; + desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; + desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +index 4c66cd1..21d9497 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -115,6 +115,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -130,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, + + DBGPR("-->xgbe_usec_to_riwt\n"); + +- rate = clk_get_rate(pdata->sysclk); ++ rate = pdata->sysclk_rate; + + /* + * Convert the input usec value to the watchdog timer value. Each +@@ -153,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, + + DBGPR("-->xgbe_riwt_to_usec\n"); + +- rate = clk_get_rate(pdata->sysclk); ++ rate = pdata->sysclk_rate; + + /* + * Convert the input watchdog timer value to the usec value. Each +@@ -673,6 +674,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) + + static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) + { ++ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3) ++ return 0; ++ + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3); + + return 0; +@@ -680,6 +684,9 @@ static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) + + static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) + { ++ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2) ++ return 0; ++ + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2); + + return 0; +@@ -687,6 +694,9 @@ static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) + + static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata) + { ++ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0) ++ return 0; ++ + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0); + + return 0; +@@ -843,6 +853,22 @@ static int xgbe_set_mac_address(struct xgbe_prv_data *pdata, u8 *addr) + return 0; + } + ++static int xgbe_config_rx_mode(struct xgbe_prv_data *pdata) ++{ ++ struct net_device *netdev = pdata->netdev; ++ unsigned int pr_mode, am_mode; ++ ++ pr_mode = ((netdev->flags & IFF_PROMISC) != 0); ++ am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); ++ ++ xgbe_set_promiscuous_mode(pdata, pr_mode); ++ xgbe_set_all_multicast_mode(pdata, am_mode); ++ ++ xgbe_add_mac_addresses(pdata); ++ ++ return 0; ++} ++ + static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, + int mmd_reg) + { +@@ -881,6 +907,23 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, + else + mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); + ++ /* If the PCS is changing modes, match the MAC speed to it */ ++ if (((mmd_address >> 16) == MDIO_MMD_PCS) && ++ ((mmd_address & 0xffff) == MDIO_CTRL2)) { ++ struct phy_device *phydev = pdata->phydev; ++ ++ if (mmd_data & MDIO_PCS_CTRL2_TYPE) { ++ /* KX mode */ ++ if (phydev->supported & SUPPORTED_1000baseKX_Full) ++ xgbe_set_gmii_speed(pdata); ++ else ++ xgbe_set_gmii_2500_speed(pdata); ++ } else { ++ /* KR mode */ ++ xgbe_set_xgmii_speed(pdata); ++ } ++ } ++ + /* The PCS registers are accessed using mmio. The underlying APB3 + * management interface uses indirect addressing to access the MMD + * register sets. This requires accessing of the PCS register in two +@@ -1041,7 +1084,7 @@ static void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata) + rdesc->desc3 = 0; + + /* Make sure ownership is written to the descriptor */ +- wmb(); ++ dma_wmb(); + } + + static void xgbe_tx_desc_init(struct xgbe_channel *channel) +@@ -1074,9 +1117,24 @@ static void xgbe_tx_desc_init(struct xgbe_channel *channel) + DBGPR("<--tx_desc_init\n"); + } + +-static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata) ++static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata, ++ struct xgbe_ring_data *rdata, unsigned int index) + { + struct xgbe_ring_desc *rdesc = rdata->rdesc; ++ unsigned int rx_usecs = pdata->rx_usecs; ++ unsigned int rx_frames = pdata->rx_frames; ++ unsigned int inte; ++ ++ if (!rx_usecs && !rx_frames) { ++ /* No coalescing, interrupt for every descriptor */ ++ inte = 1; ++ } else { ++ /* Set interrupt based on Rx frame coalescing setting */ ++ if (rx_frames && !((index + 1) % rx_frames)) ++ inte = 1; ++ else ++ inte = 0; ++ } + + /* Reset the Rx descriptor + * Set buffer 1 (lo) address to header dma address (lo) +@@ -1090,19 +1148,18 @@ static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata) + rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma)); + rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma)); + +- XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, +- rdata->interrupt ? 1 : 0); ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte); + + /* Since the Rx DMA engine is likely running, make sure everything + * is written to the descriptor(s) before setting the OWN bit + * for the descriptor + */ +- wmb(); ++ dma_wmb(); + + XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1); + + /* Make sure ownership is written to the descriptor */ +- wmb(); ++ dma_wmb(); + } + + static void xgbe_rx_desc_init(struct xgbe_channel *channel) +@@ -1111,26 +1168,16 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) + struct xgbe_ring *ring = channel->rx_ring; + struct xgbe_ring_data *rdata; + unsigned int start_index = ring->cur; +- unsigned int rx_coalesce, rx_frames; + unsigned int i; + + DBGPR("-->rx_desc_init\n"); + +- rx_coalesce = (pdata->rx_riwt || pdata->rx_frames) ? 1 : 0; +- rx_frames = pdata->rx_frames; +- + /* Initialize all descriptors */ + for (i = 0; i < ring->rdesc_count; i++) { + rdata = XGBE_GET_DESC_DATA(ring, i); + +- /* Set interrupt on completion bit as appropriate */ +- if (rx_coalesce && (!rx_frames || ((i + 1) % rx_frames))) +- rdata->interrupt = 0; +- else +- rdata->interrupt = 1; +- + /* Initialize Rx descriptor */ +- xgbe_rx_desc_reset(rdata); ++ xgbe_rx_desc_reset(pdata, rdata, i); + } + + /* Update the total number of Rx descriptors */ +@@ -1331,18 +1378,20 @@ static void xgbe_tx_start_xmit(struct xgbe_channel *channel, + struct xgbe_prv_data *pdata = channel->pdata; + struct xgbe_ring_data *rdata; + ++ /* Make sure everything is written before the register write */ ++ wmb(); ++ + /* Issue a poll command to Tx DMA by writing address + * of next immediate free descriptor */ + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, + lower_32_bits(rdata->rdesc_dma)); + +- /* Start the Tx coalescing timer */ ++ /* Start the Tx timer */ + if (pdata->tx_usecs && !channel->tx_timer_active) { + channel->tx_timer_active = 1; +- hrtimer_start(&channel->tx_timer, +- ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC), +- HRTIMER_MODE_REL); ++ mod_timer(&channel->tx_timer, ++ jiffies + usecs_to_jiffies(pdata->tx_usecs)); + } + + ring->tx.xmit_more = 0; +@@ -1359,6 +1408,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + unsigned int tso_context, vlan_context; + unsigned int tx_set_ic; + int start_index = ring->cur; ++ int cur_index = ring->cur; + int i; + + DBGPR("-->xgbe_dev_xmit\n"); +@@ -1401,7 +1451,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + else + tx_set_ic = 0; + +- rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); + rdesc = rdata->rdesc; + + /* Create a context descriptor if this is a TSO packet */ +@@ -1444,8 +1494,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + ring->tx.cur_vlan_ctag = packet->vlan_ctag; + } + +- ring->cur++; +- rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); + rdesc = rdata->rdesc; + } + +@@ -1473,7 +1523,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0); + + /* Set OWN bit if not the first descriptor */ +- if (ring->cur != start_index) ++ if (cur_index != start_index) + XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); + + if (tso) { +@@ -1497,9 +1547,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + packet->length); + } + +- for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) { +- ring->cur++; +- rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) { ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); + rdesc = rdata->rdesc; + + /* Update buffer address */ +@@ -1537,7 +1587,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + * is written to the descriptor(s) before setting the OWN bit + * for the first descriptor + */ +- wmb(); ++ dma_wmb(); + + /* Set OWN bit for the first descriptor */ + rdata = XGBE_GET_DESC_DATA(ring, start_index); +@@ -1549,9 +1599,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) + #endif + + /* Make sure ownership is written to the descriptor */ +- wmb(); ++ dma_wmb(); + +- ring->cur++; ++ ring->cur = cur_index + 1; + if (!packet->skb->xmit_more || + netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, + channel->queue_index))) +@@ -1585,7 +1635,7 @@ static int xgbe_dev_read(struct xgbe_channel *channel) + return 1; + + /* Make sure descriptor fields are read after reading the OWN bit */ +- rmb(); ++ dma_rmb(); + + #ifdef XGMAC_ENABLE_RX_DESC_DUMP + xgbe_dump_rx_desc(ring, rdesc, ring->cur); +@@ -1976,7 +2026,8 @@ static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata) + for (i = 0; i < pdata->tx_q_count; i++) + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size); + +- netdev_notice(pdata->netdev, "%d Tx queues, %d byte fifo per queue\n", ++ netdev_notice(pdata->netdev, ++ "%d Tx hardware queues, %d byte fifo per queue\n", + pdata->tx_q_count, ((fifo_size + 1) * 256)); + } + +@@ -1991,7 +2042,8 @@ static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata) + for (i = 0; i < pdata->rx_q_count; i++) + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size); + +- netdev_notice(pdata->netdev, "%d Rx queues, %d byte fifo per queue\n", ++ netdev_notice(pdata->netdev, ++ "%d Rx hardware queues, %d byte fifo per queue\n", + pdata->rx_q_count, ((fifo_size + 1) * 256)); + } + +@@ -2107,6 +2159,23 @@ static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) + XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val); + } + ++static void xgbe_config_mac_speed(struct xgbe_prv_data *pdata) ++{ ++ switch (pdata->phy_speed) { ++ case SPEED_10000: ++ xgbe_set_xgmii_speed(pdata); ++ break; ++ ++ case SPEED_2500: ++ xgbe_set_gmii_2500_speed(pdata); ++ break; ++ ++ case SPEED_1000: ++ xgbe_set_gmii_speed(pdata); ++ break; ++ } ++} ++ + static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) + { + if (pdata->netdev->features & NETIF_F_RXCSUM) +@@ -2755,8 +2824,10 @@ static int xgbe_init(struct xgbe_prv_data *pdata) + * Initialize MAC related features + */ + xgbe_config_mac_address(pdata); ++ xgbe_config_rx_mode(pdata); + xgbe_config_jumbo_enable(pdata); + xgbe_config_flow_control(pdata); ++ xgbe_config_mac_speed(pdata); + xgbe_config_checksum_offload(pdata); + xgbe_config_vlan_support(pdata); + xgbe_config_mmc(pdata); +@@ -2773,10 +2844,8 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) + + hw_if->tx_complete = xgbe_tx_complete; + +- hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; +- hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; +- hw_if->add_mac_addresses = xgbe_add_mac_addresses; + hw_if->set_mac_address = xgbe_set_mac_address; ++ hw_if->config_rx_mode = xgbe_config_rx_mode; + + hw_if->enable_rx_csum = xgbe_enable_rx_csum; + hw_if->disable_rx_csum = xgbe_disable_rx_csum; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index e5ffb2c..343bf6a 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -129,7 +129,6 @@ + + static int xgbe_one_poll(struct napi_struct *, int); + static int xgbe_all_poll(struct napi_struct *, int); +-static void xgbe_set_rx_mode(struct net_device *); + + static int xgbe_alloc_channels(struct xgbe_prv_data *pdata) + { +@@ -225,6 +224,11 @@ static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) + return (ring->rdesc_count - (ring->cur - ring->dirty)); + } + ++static inline unsigned int xgbe_rx_dirty_desc(struct xgbe_ring *ring) ++{ ++ return (ring->cur - ring->dirty); ++} ++ + static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel, + struct xgbe_ring *ring, unsigned int count) + { +@@ -337,12 +341,13 @@ static irqreturn_t xgbe_isr(int irq, void *data) + dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); + DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr); + +- /* If we get a TI or RI interrupt that means per channel DMA +- * interrupts are not enabled, so we use the private data napi +- * structure, not the per channel napi structure ++ /* The TI or RI interrupt bits may still be set even if using ++ * per channel DMA interrupts. Check to be sure those are not ++ * enabled before using the private data napi structure. + */ +- if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || +- XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) { ++ if (!pdata->per_channel_irq && ++ (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || ++ XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) { + if (napi_schedule_prep(&pdata->napi)) { + /* Disable Tx and Rx interrupts */ + xgbe_disable_rx_tx_ints(pdata); +@@ -405,26 +410,20 @@ static irqreturn_t xgbe_dma_isr(int irq, void *data) + return IRQ_HANDLED; + } + +-static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) ++static void xgbe_tx_timer(unsigned long data) + { +- struct xgbe_channel *channel = container_of(timer, +- struct xgbe_channel, +- tx_timer); +- struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_channel *channel = (struct xgbe_channel *)data; + struct xgbe_prv_data *pdata = channel->pdata; + struct napi_struct *napi; +- unsigned long flags; + + DBGPR("-->xgbe_tx_timer\n"); + + napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi; + +- spin_lock_irqsave(&ring->lock, flags); +- + if (napi_schedule_prep(napi)) { + /* Disable Tx and Rx interrupts */ + if (pdata->per_channel_irq) +- disable_irq(channel->dma_irq); ++ disable_irq_nosync(channel->dma_irq); + else + xgbe_disable_rx_tx_ints(pdata); + +@@ -434,11 +433,7 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) + + channel->tx_timer_active = 0; + +- spin_unlock_irqrestore(&ring->lock, flags); +- + DBGPR("<--xgbe_tx_timer\n"); +- +- return HRTIMER_NORESTART; + } + + static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata) +@@ -454,9 +449,8 @@ static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata) + break; + + DBGPR(" %s adding tx timer\n", channel->name); +- hrtimer_init(&channel->tx_timer, CLOCK_MONOTONIC, +- HRTIMER_MODE_REL); +- channel->tx_timer.function = xgbe_tx_timer; ++ setup_timer(&channel->tx_timer, xgbe_tx_timer, ++ (unsigned long)channel); + } + + DBGPR("<--xgbe_init_tx_timers\n"); +@@ -475,8 +469,7 @@ static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata) + break; + + DBGPR(" %s deleting tx timer\n", channel->name); +- channel->tx_timer_active = 0; +- hrtimer_cancel(&channel->tx_timer); ++ del_timer_sync(&channel->tx_timer); + } + + DBGPR("<--xgbe_stop_tx_timers\n"); +@@ -519,6 +512,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) + RXFIFOSIZE); + hw_feat->tx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, + TXFIFOSIZE); ++ hw_feat->dma_width = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ADDR64); + hw_feat->dcb = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN); + hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); + hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); +@@ -553,6 +547,21 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) + break; + } + ++ /* Translate the address width setting into actual number */ ++ switch (hw_feat->dma_width) { ++ case 0: ++ hw_feat->dma_width = 32; ++ break; ++ case 1: ++ hw_feat->dma_width = 40; ++ break; ++ case 2: ++ hw_feat->dma_width = 48; ++ break; ++ default: ++ hw_feat->dma_width = 32; ++ } ++ + /* The Queue, Channel and TC counts are zero based so increment them + * to get the actual number + */ +@@ -609,6 +618,68 @@ static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del) + } + } + ++static int xgbe_request_irqs(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ struct net_device *netdev = pdata->netdev; ++ unsigned int i; ++ int ret; ++ ++ ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, ++ netdev->name, pdata); ++ if (ret) { ++ netdev_alert(netdev, "error requesting irq %d\n", ++ pdata->dev_irq); ++ return ret; ++ } ++ ++ if (!pdata->per_channel_irq) ++ return 0; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ snprintf(channel->dma_irq_name, ++ sizeof(channel->dma_irq_name) - 1, ++ "%s-TxRx-%u", netdev_name(netdev), ++ channel->queue_index); ++ ++ ret = devm_request_irq(pdata->dev, channel->dma_irq, ++ xgbe_dma_isr, 0, ++ channel->dma_irq_name, channel); ++ if (ret) { ++ netdev_alert(netdev, "error requesting irq %d\n", ++ channel->dma_irq); ++ goto err_irq; ++ } ++ } ++ ++ return 0; ++ ++err_irq: ++ /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ ++ for (i--, channel--; i < pdata->channel_count; i--, channel--) ++ devm_free_irq(pdata->dev, channel->dma_irq, channel); ++ ++ devm_free_irq(pdata->dev, pdata->dev_irq, pdata); ++ ++ return ret; ++} ++ ++static void xgbe_free_irqs(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ devm_free_irq(pdata->dev, pdata->dev_irq, pdata); ++ ++ if (!pdata->per_channel_irq) ++ return; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) ++ devm_free_irq(pdata->dev, channel->dma_irq, channel); ++} ++ + void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) + { + struct xgbe_hw_if *hw_if = &pdata->hw_if; +@@ -630,6 +701,7 @@ void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) + DBGPR("-->xgbe_init_rx_coalesce\n"); + + pdata->rx_riwt = hw_if->usec_to_riwt(pdata, XGMAC_INIT_DMA_RX_USECS); ++ pdata->rx_usecs = XGMAC_INIT_DMA_RX_USECS; + pdata->rx_frames = XGMAC_INIT_DMA_RX_FRAMES; + + hw_if->config_rx_coalesce(pdata); +@@ -694,7 +766,7 @@ static void xgbe_adjust_link(struct net_device *netdev) + struct phy_device *phydev = pdata->phydev; + int new_state = 0; + +- if (phydev == NULL) ++ if (!phydev) + return; + + if (phydev->link) { +@@ -810,20 +882,20 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller) + return -EINVAL; + } + +- phy_stop(pdata->phydev); +- + spin_lock_irqsave(&pdata->lock, flags); + + if (caller == XGMAC_DRIVER_CONTEXT) + netif_device_detach(netdev); + + netif_tx_stop_all_queues(netdev); +- xgbe_napi_disable(pdata, 0); + +- /* Powerdown Tx/Rx */ + hw_if->powerdown_tx(pdata); + hw_if->powerdown_rx(pdata); + ++ xgbe_napi_disable(pdata, 0); ++ ++ phy_stop(pdata->phydev); ++ + pdata->power_down = 1; + + spin_unlock_irqrestore(&pdata->lock, flags); +@@ -854,14 +926,14 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller) + + phy_start(pdata->phydev); + +- /* Enable Tx/Rx */ ++ xgbe_napi_enable(pdata, 0); ++ + hw_if->powerup_tx(pdata); + hw_if->powerup_rx(pdata); + + if (caller == XGMAC_DRIVER_CONTEXT) + netif_device_attach(netdev); + +- xgbe_napi_enable(pdata, 0); + netif_tx_start_all_queues(netdev); + + spin_unlock_irqrestore(&pdata->lock, flags); +@@ -875,26 +947,39 @@ static int xgbe_start(struct xgbe_prv_data *pdata) + { + struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct net_device *netdev = pdata->netdev; ++ int ret; + + DBGPR("-->xgbe_start\n"); + +- xgbe_set_rx_mode(netdev); +- + hw_if->init(pdata); + + phy_start(pdata->phydev); + ++ xgbe_napi_enable(pdata, 1); ++ ++ ret = xgbe_request_irqs(pdata); ++ if (ret) ++ goto err_napi; ++ + hw_if->enable_tx(pdata); + hw_if->enable_rx(pdata); + + xgbe_init_tx_timers(pdata); + +- xgbe_napi_enable(pdata, 1); + netif_tx_start_all_queues(netdev); + + DBGPR("<--xgbe_start\n"); + + return 0; ++ ++err_napi: ++ xgbe_napi_disable(pdata, 1); ++ ++ phy_stop(pdata->phydev); ++ ++ hw_if->exit(pdata); ++ ++ return ret; + } + + static void xgbe_stop(struct xgbe_prv_data *pdata) +@@ -907,16 +992,21 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) + + DBGPR("-->xgbe_stop\n"); + +- phy_stop(pdata->phydev); +- + netif_tx_stop_all_queues(netdev); +- xgbe_napi_disable(pdata, 1); + + xgbe_stop_tx_timers(pdata); + + hw_if->disable_tx(pdata); + hw_if->disable_rx(pdata); + ++ xgbe_free_irqs(pdata); ++ ++ xgbe_napi_disable(pdata, 1); ++ ++ phy_stop(pdata->phydev); ++ ++ hw_if->exit(pdata); ++ + channel = pdata->channel; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (!channel->tx_ring) +@@ -929,12 +1019,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) + DBGPR("<--xgbe_stop\n"); + } + +-static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) ++static void xgbe_restart_dev(struct xgbe_prv_data *pdata) + { +- struct xgbe_channel *channel; +- struct xgbe_hw_if *hw_if = &pdata->hw_if; +- unsigned int i; +- + DBGPR("-->xgbe_restart_dev\n"); + + /* If not running, "restart" will happen on open */ +@@ -942,20 +1028,10 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) + return; + + xgbe_stop(pdata); +- synchronize_irq(pdata->dev_irq); +- if (pdata->per_channel_irq) { +- channel = pdata->channel; +- for (i = 0; i < pdata->channel_count; i++, channel++) +- synchronize_irq(channel->dma_irq); +- } + + xgbe_free_tx_data(pdata); + xgbe_free_rx_data(pdata); + +- /* Issue software reset to device if requested */ +- if (reset) +- hw_if->exit(pdata); +- + xgbe_start(pdata); + + DBGPR("<--xgbe_restart_dev\n"); +@@ -969,7 +1045,7 @@ static void xgbe_restart(struct work_struct *work) + + rtnl_lock(); + +- xgbe_restart_dev(pdata, 1); ++ xgbe_restart_dev(pdata); + + rtnl_unlock(); + } +@@ -1284,10 +1360,7 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, + static int xgbe_open(struct net_device *netdev) + { + struct xgbe_prv_data *pdata = netdev_priv(netdev); +- struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_desc_if *desc_if = &pdata->desc_if; +- struct xgbe_channel *channel = NULL; +- unsigned int i = 0; + int ret; + + DBGPR("-->xgbe_open\n"); +@@ -1330,55 +1403,14 @@ static int xgbe_open(struct net_device *netdev) + INIT_WORK(&pdata->restart_work, xgbe_restart); + INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); + +- /* Request interrupts */ +- ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, +- netdev->name, pdata); +- if (ret) { +- netdev_alert(netdev, "error requesting irq %d\n", +- pdata->dev_irq); +- goto err_rings; +- } +- +- if (pdata->per_channel_irq) { +- channel = pdata->channel; +- for (i = 0; i < pdata->channel_count; i++, channel++) { +- snprintf(channel->dma_irq_name, +- sizeof(channel->dma_irq_name) - 1, +- "%s-TxRx-%u", netdev_name(netdev), +- channel->queue_index); +- +- ret = devm_request_irq(pdata->dev, channel->dma_irq, +- xgbe_dma_isr, 0, +- channel->dma_irq_name, channel); +- if (ret) { +- netdev_alert(netdev, +- "error requesting irq %d\n", +- channel->dma_irq); +- goto err_irq; +- } +- } +- } +- + ret = xgbe_start(pdata); + if (ret) +- goto err_start; ++ goto err_rings; + + DBGPR("<--xgbe_open\n"); + + return 0; + +-err_start: +- hw_if->exit(pdata); +- +-err_irq: +- if (pdata->per_channel_irq) { +- /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ +- for (i--, channel--; i < pdata->channel_count; i--, channel--) +- devm_free_irq(pdata->dev, channel->dma_irq, channel); +- } +- +- devm_free_irq(pdata->dev, pdata->dev_irq, pdata); +- + err_rings: + desc_if->free_ring_resources(pdata); + +@@ -1400,30 +1432,16 @@ err_phy_init: + static int xgbe_close(struct net_device *netdev) + { + struct xgbe_prv_data *pdata = netdev_priv(netdev); +- struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_desc_if *desc_if = &pdata->desc_if; +- struct xgbe_channel *channel; +- unsigned int i; + + DBGPR("-->xgbe_close\n"); + + /* Stop the device */ + xgbe_stop(pdata); + +- /* Issue software reset to device */ +- hw_if->exit(pdata); +- + /* Free the ring descriptors and buffers */ + desc_if->free_ring_resources(pdata); + +- /* Release the interrupts */ +- devm_free_irq(pdata->dev, pdata->dev_irq, pdata); +- if (pdata->per_channel_irq) { +- channel = pdata->channel; +- for (i = 0; i < pdata->channel_count; i++, channel++) +- devm_free_irq(pdata->dev, channel->dma_irq, channel); +- } +- + /* Free the channel and ring structures */ + xgbe_free_channels(pdata); + +@@ -1448,7 +1466,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) + struct xgbe_ring *ring; + struct xgbe_packet_data *packet; + struct netdev_queue *txq; +- unsigned long flags; + int ret; + + DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); +@@ -1460,8 +1477,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) + + ret = NETDEV_TX_OK; + +- spin_lock_irqsave(&ring->lock, flags); +- + if (skb->len == 0) { + netdev_err(netdev, "empty skb received from stack\n"); + dev_kfree_skb_any(skb); +@@ -1508,10 +1523,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) + ret = NETDEV_TX_OK; + + tx_netdev_return: +- spin_unlock_irqrestore(&ring->lock, flags); +- +- DBGPR("<--xgbe_xmit\n"); +- + return ret; + } + +@@ -1519,17 +1530,10 @@ static void xgbe_set_rx_mode(struct net_device *netdev) + { + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; +- unsigned int pr_mode, am_mode; + + DBGPR("-->xgbe_set_rx_mode\n"); + +- pr_mode = ((netdev->flags & IFF_PROMISC) != 0); +- am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); +- +- hw_if->set_promiscuous_mode(pdata, pr_mode); +- hw_if->set_all_multicast_mode(pdata, am_mode); +- +- hw_if->add_mac_addresses(pdata); ++ hw_if->config_rx_mode(pdata); + + DBGPR("<--xgbe_set_rx_mode\n"); + } +@@ -1589,13 +1593,21 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu) + pdata->rx_buf_size = ret; + netdev->mtu = mtu; + +- xgbe_restart_dev(pdata, 0); ++ xgbe_restart_dev(pdata); + + DBGPR("<--xgbe_change_mtu\n"); + + return 0; + } + ++static void xgbe_tx_timeout(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ netdev_warn(netdev, "tx timeout, device restarting\n"); ++ schedule_work(&pdata->restart_work); ++} ++ + static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *s) + { +@@ -1760,6 +1772,7 @@ static const struct net_device_ops xgbe_netdev_ops = { + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = xgbe_ioctl, + .ndo_change_mtu = xgbe_change_mtu, ++ .ndo_tx_timeout = xgbe_tx_timeout, + .ndo_get_stats64 = xgbe_get_stats64, + .ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = xgbe_vlan_rx_kill_vid, +@@ -1778,29 +1791,44 @@ struct net_device_ops *xgbe_get_netdev_ops(void) + static void xgbe_rx_refresh(struct xgbe_channel *channel) + { + struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; + struct xgbe_desc_if *desc_if = &pdata->desc_if; + struct xgbe_ring *ring = channel->rx_ring; + struct xgbe_ring_data *rdata; + +- desc_if->realloc_rx_buffer(channel); ++ while (ring->dirty != ring->cur) { ++ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); ++ ++ /* Reset rdata values */ ++ desc_if->unmap_rdata(pdata, rdata); ++ ++ if (desc_if->map_rx_buffer(pdata, ring, rdata)) ++ break; ++ ++ hw_if->rx_desc_reset(pdata, rdata, ring->dirty); ++ ++ ring->dirty++; ++ } ++ ++ /* Make sure everything is written before the register write */ ++ wmb(); + + /* Update the Rx Tail Pointer Register with address of + * the last cleaned entry */ +- rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); ++ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1); + XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, + lower_32_bits(rdata->rdesc_dma)); + } + +-static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata, ++static struct sk_buff *xgbe_create_skb(struct napi_struct *napi, + struct xgbe_ring_data *rdata, + unsigned int *len) + { +- struct net_device *netdev = pdata->netdev; + struct sk_buff *skb; + u8 *packet; + unsigned int copy_len; + +- skb = netdev_alloc_skb_ip_align(netdev, rdata->rx.hdr.dma_len); ++ skb = napi_alloc_skb(napi, rdata->rx.hdr.dma_len); + if (!skb) + return NULL; + +@@ -1826,7 +1854,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) + struct xgbe_ring_desc *rdesc; + struct net_device *netdev = pdata->netdev; + struct netdev_queue *txq; +- unsigned long flags; + int processed = 0; + unsigned int tx_packets = 0, tx_bytes = 0; + +@@ -1838,8 +1865,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) + + txq = netdev_get_tx_queue(netdev, channel->queue_index); + +- spin_lock_irqsave(&ring->lock, flags); +- + while ((processed < XGBE_TX_DESC_MAX_PROC) && + (ring->dirty != ring->cur)) { + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); +@@ -1850,7 +1875,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) + + /* Make sure descriptor fields are read after reading the OWN + * bit */ +- rmb(); ++ dma_rmb(); + + #ifdef XGMAC_ENABLE_TX_DESC_DUMP + xgbe_dump_tx_desc(ring, ring->dirty, 1, 0); +@@ -1870,7 +1895,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) + } + + if (!processed) +- goto unlock; ++ return 0; + + netdev_tx_completed_queue(txq, tx_packets, tx_bytes); + +@@ -1882,9 +1907,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) + + DBGPR("<--xgbe_tx_poll: processed=%d\n", processed); + +-unlock: +- spin_unlock_irqrestore(&ring->lock, flags); +- + return processed; + } + +@@ -1936,7 +1958,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) + read_again: + rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + +- if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) ++ if (xgbe_rx_dirty_desc(ring) > (XGBE_RX_DESC_CNT >> 3)) + xgbe_rx_refresh(channel); + + if (hw_if->dev_read(channel)) +@@ -1944,7 +1966,6 @@ read_again: + + received++; + ring->cur++; +- ring->dirty++; + + incomplete = XGMAC_GET_BITS(packet->attributes, + RX_PACKET_ATTRIBUTES, +@@ -1977,7 +1998,7 @@ read_again: + rdata->rx.hdr.dma_len, + DMA_FROM_DEVICE); + +- skb = xgbe_create_skb(pdata, rdata, &put_len); ++ skb = xgbe_create_skb(napi, rdata, &put_len); + if (!skb) { + error = 1; + goto skip_data; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +index ebf4893..5f149e8 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +@@ -291,7 +291,6 @@ static int xgbe_get_settings(struct net_device *netdev, + return -ENODEV; + + ret = phy_ethtool_gset(pdata->phydev, cmd); +- cmd->transceiver = XCVR_EXTERNAL; + + DBGPR("<--xgbe_get_settings\n"); + +@@ -378,18 +377,14 @@ static int xgbe_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) + { + struct xgbe_prv_data *pdata = netdev_priv(netdev); +- struct xgbe_hw_if *hw_if = &pdata->hw_if; +- unsigned int riwt; + + DBGPR("-->xgbe_get_coalesce\n"); + + memset(ec, 0, sizeof(struct ethtool_coalesce)); + +- riwt = pdata->rx_riwt; +- ec->rx_coalesce_usecs = hw_if->riwt_to_usec(pdata, riwt); ++ ec->rx_coalesce_usecs = pdata->rx_usecs; + ec->rx_max_coalesced_frames = pdata->rx_frames; + +- ec->tx_coalesce_usecs = pdata->tx_usecs; + ec->tx_max_coalesced_frames = pdata->tx_frames; + + DBGPR("<--xgbe_get_coalesce\n"); +@@ -403,13 +398,14 @@ static int xgbe_set_coalesce(struct net_device *netdev, + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_hw_if *hw_if = &pdata->hw_if; + unsigned int rx_frames, rx_riwt, rx_usecs; +- unsigned int tx_frames, tx_usecs; ++ unsigned int tx_frames; + + DBGPR("-->xgbe_set_coalesce\n"); + + /* Check for not supported parameters */ + if ((ec->rx_coalesce_usecs_irq) || + (ec->rx_max_coalesced_frames_irq) || ++ (ec->tx_coalesce_usecs) || + (ec->tx_coalesce_usecs_irq) || + (ec->tx_max_coalesced_frames_irq) || + (ec->stats_block_coalesce_usecs) || +@@ -428,28 +424,18 @@ static int xgbe_set_coalesce(struct net_device *netdev, + (ec->rate_sample_interval)) + return -EOPNOTSUPP; + +- /* Can only change rx-frames when interface is down (see +- * rx_descriptor_init in xgbe-dev.c) +- */ +- rx_frames = pdata->rx_frames; +- if (rx_frames != ec->rx_max_coalesced_frames && netif_running(netdev)) { +- netdev_alert(netdev, +- "interface must be down to change rx-frames\n"); +- return -EINVAL; +- } +- + rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); ++ rx_usecs = ec->rx_coalesce_usecs; + rx_frames = ec->rx_max_coalesced_frames; + + /* Use smallest possible value if conversion resulted in zero */ +- if (ec->rx_coalesce_usecs && !rx_riwt) ++ if (rx_usecs && !rx_riwt) + rx_riwt = 1; + + /* Check the bounds of values for Rx */ + if (rx_riwt > XGMAC_MAX_DMA_RIWT) { +- rx_usecs = hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT); + netdev_alert(netdev, "rx-usec is limited to %d usecs\n", +- rx_usecs); ++ hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT)); + return -EINVAL; + } + if (rx_frames > pdata->rx_desc_count) { +@@ -458,7 +444,6 @@ static int xgbe_set_coalesce(struct net_device *netdev, + return -EINVAL; + } + +- tx_usecs = ec->tx_coalesce_usecs; + tx_frames = ec->tx_max_coalesced_frames; + + /* Check the bounds of values for Tx */ +@@ -469,10 +454,10 @@ static int xgbe_set_coalesce(struct net_device *netdev, + } + + pdata->rx_riwt = rx_riwt; ++ pdata->rx_usecs = rx_usecs; + pdata->rx_frames = rx_frames; + hw_if->config_rx_coalesce(pdata); + +- pdata->tx_usecs = tx_usecs; + pdata->tx_frames = tx_frames; + hw_if->config_tx_coalesce(pdata); + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c +index dbd3850..7149053 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c +@@ -123,7 +123,10 @@ + #include + #include + #include ++#include + #include ++#include ++#include + + #include "xgbe.h" + #include "xgbe-common.h" +@@ -148,6 +151,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) + pdata->pause_autoneg = 1; + pdata->tx_pause = 1; + pdata->rx_pause = 1; ++ pdata->phy_speed = SPEED_UNKNOWN; + pdata->power_down = 0; + pdata->default_autoneg = AUTONEG_ENABLE; + pdata->default_speed = SPEED_10000; +@@ -161,6 +165,96 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) + xgbe_init_function_ptrs_desc(&pdata->desc_if); + } + ++#ifdef CONFIG_ACPI ++static int xgbe_acpi_support(struct xgbe_prv_data *pdata) ++{ ++ struct acpi_device *adev = pdata->adev; ++ struct device *dev = pdata->dev; ++ u32 property; ++ acpi_handle handle; ++ acpi_status status; ++ unsigned long long data; ++ int cca; ++ int ret; ++ ++ /* Obtain the system clock setting */ ++ ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s property\n", ++ XGBE_ACPI_DMA_FREQ); ++ return ret; ++ } ++ pdata->sysclk_rate = property; ++ ++ /* Obtain the PTP clock setting */ ++ ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property); ++ if (ret) { ++ dev_err(dev, "unable to obtain %s property\n", ++ XGBE_ACPI_PTP_FREQ); ++ return ret; ++ } ++ pdata->ptpclk_rate = property; ++ ++ /* Retrieve the device cache coherency value */ ++ handle = adev->handle; ++ do { ++ status = acpi_evaluate_integer(handle, "_CCA", NULL, &data); ++ if (!ACPI_FAILURE(status)) { ++ cca = data; ++ break; ++ } ++ ++ status = acpi_get_parent(handle, &handle); ++ } while (!ACPI_FAILURE(status)); ++ ++ if (ACPI_FAILURE(status)) { ++ dev_err(dev, "error obtaining acpi coherency value\n"); ++ return -EINVAL; ++ } ++ pdata->coherent = !!cca; ++ ++ return 0; ++} ++#else /* CONFIG_ACPI */ ++static int xgbe_acpi_support(struct xgbe_prv_data *pdata) ++{ ++ return -EINVAL; ++} ++#endif /* CONFIG_ACPI */ ++ ++#ifdef CONFIG_OF ++static int xgbe_of_support(struct xgbe_prv_data *pdata) ++{ ++ struct device *dev = pdata->dev; ++ ++ /* Obtain the system clock setting */ ++ pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); ++ if (IS_ERR(pdata->sysclk)) { ++ dev_err(dev, "dma devm_clk_get failed\n"); ++ return PTR_ERR(pdata->sysclk); ++ } ++ pdata->sysclk_rate = clk_get_rate(pdata->sysclk); ++ ++ /* Obtain the PTP clock setting */ ++ pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); ++ if (IS_ERR(pdata->ptpclk)) { ++ dev_err(dev, "ptp devm_clk_get failed\n"); ++ return PTR_ERR(pdata->ptpclk); ++ } ++ pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk); ++ ++ /* Retrieve the device cache coherency value */ ++ pdata->coherent = of_dma_is_coherent(dev->of_node); ++ ++ return 0; ++} ++#else /* CONFIG_OF */ ++static int xgbe_of_support(struct xgbe_prv_data *pdata) ++{ ++ return -EINVAL; ++} ++#endif /*CONFIG_OF */ ++ + static int xgbe_probe(struct platform_device *pdev) + { + struct xgbe_prv_data *pdata; +@@ -169,7 +263,7 @@ static int xgbe_probe(struct platform_device *pdev) + struct net_device *netdev; + struct device *dev = &pdev->dev; + struct resource *res; +- const u8 *mac_addr; ++ const char *phy_mode; + unsigned int i; + int ret; + +@@ -186,6 +280,7 @@ static int xgbe_probe(struct platform_device *pdev) + pdata = netdev_priv(netdev); + pdata->netdev = netdev; + pdata->pdev = pdev; ++ pdata->adev = ACPI_COMPANION(dev); + pdata->dev = dev; + platform_set_drvdata(pdev, netdev); + +@@ -194,6 +289,9 @@ static int xgbe_probe(struct platform_device *pdev) + mutex_init(&pdata->rss_mutex); + spin_lock_init(&pdata->tstamp_lock); + ++ /* Check if we should use ACPI or DT */ ++ pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1; ++ + /* Set and validate the number of descriptors for a ring */ + BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); + pdata->tx_desc_count = XGBE_TX_DESC_CNT; +@@ -212,22 +310,6 @@ static int xgbe_probe(struct platform_device *pdev) + goto err_io; + } + +- /* Obtain the system clock setting */ +- pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); +- if (IS_ERR(pdata->sysclk)) { +- dev_err(dev, "dma devm_clk_get failed\n"); +- ret = PTR_ERR(pdata->sysclk); +- goto err_io; +- } +- +- /* Obtain the PTP clock setting */ +- pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); +- if (IS_ERR(pdata->ptpclk)) { +- dev_err(dev, "ptp devm_clk_get failed\n"); +- ret = PTR_ERR(pdata->ptpclk); +- goto err_io; +- } +- + /* Obtain the mmio areas for the device */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->xgmac_regs = devm_ioremap_resource(dev, res); +@@ -247,16 +329,42 @@ static int xgbe_probe(struct platform_device *pdev) + } + DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); + +- /* Set the DMA mask */ +- if (!dev->dma_mask) +- dev->dma_mask = &dev->coherent_dma_mask; +- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); +- if (ret) { +- dev_err(dev, "dma_set_mask_and_coherent failed\n"); ++ /* Retrieve the MAC address */ ++ ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY, ++ pdata->mac_addr, ++ sizeof(pdata->mac_addr)); ++ if (ret || !is_valid_ether_addr(pdata->mac_addr)) { ++ dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY); ++ if (!ret) ++ ret = -EINVAL; + goto err_io; + } + +- if (of_property_read_bool(dev->of_node, "dma-coherent")) { ++ /* Retrieve the PHY mode - it must be "xgmii" */ ++ ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY, ++ &phy_mode); ++ if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) { ++ dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY); ++ if (!ret) ++ ret = -EINVAL; ++ goto err_io; ++ } ++ pdata->phy_mode = PHY_INTERFACE_MODE_XGMII; ++ ++ /* Check for per channel interrupt support */ ++ if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY)) ++ pdata->per_channel_irq = 1; ++ ++ /* Obtain device settings unique to ACPI/OF */ ++ if (pdata->use_acpi) ++ ret = xgbe_acpi_support(pdata); ++ else ++ ret = xgbe_of_support(pdata); ++ if (ret) ++ goto err_io; ++ ++ /* Set the DMA coherency values */ ++ if (pdata->coherent) { + pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; + pdata->arcache = XGBE_DMA_OS_ARCACHE; + pdata->awcache = XGBE_DMA_OS_AWCACHE; +@@ -266,10 +374,7 @@ static int xgbe_probe(struct platform_device *pdev) + pdata->awcache = XGBE_DMA_SYS_AWCACHE; + } + +- /* Check for per channel interrupt support */ +- if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS)) +- pdata->per_channel_irq = 1; +- ++ /* Get the device interrupt */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "platform_get_irq 0 failed\n"); +@@ -279,6 +384,7 @@ static int xgbe_probe(struct platform_device *pdev) + + netdev->irq = pdata->dev_irq; + netdev->base_addr = (unsigned long)pdata->xgmac_regs; ++ memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); + + /* Set all the function pointers */ + xgbe_init_all_fptrs(pdata); +@@ -291,26 +397,19 @@ static int xgbe_probe(struct platform_device *pdev) + /* Populate the hardware features */ + xgbe_get_all_hw_features(pdata); + +- /* Retrieve the MAC address */ +- mac_addr = of_get_mac_address(dev->of_node); +- if (!mac_addr) { +- dev_err(dev, "invalid mac address for this device\n"); +- ret = -EINVAL; +- goto err_io; +- } +- memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); ++ /* Set default configuration data */ ++ xgbe_default_config(pdata); + +- /* Retrieve the PHY mode - it must be "xgmii" */ +- pdata->phy_mode = of_get_phy_mode(dev->of_node); +- if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { +- dev_err(dev, "invalid phy-mode specified for this device\n"); +- ret = -EINVAL; ++ /* Set the DMA mask */ ++ if (!dev->dma_mask) ++ dev->dma_mask = &dev->coherent_dma_mask; ++ ret = dma_set_mask_and_coherent(dev, ++ DMA_BIT_MASK(pdata->hw_feat.dma_width)); ++ if (ret) { ++ dev_err(dev, "dma_set_mask_and_coherent failed\n"); + goto err_io; + } + +- /* Set default configuration data */ +- xgbe_default_config(pdata); +- + /* Calculate the number of Tx and Rx rings to be created + * -Tx (DMA) Channels map 1-to-1 to Tx Queues so set + * the number of Tx queues to the number of Tx channels +@@ -392,6 +491,9 @@ static int xgbe_probe(struct platform_device *pdev) + + netdev->priv_flags |= IFF_UNICAST_FLT; + ++ /* Use default watchdog timeout */ ++ netdev->watchdog_timeo = 0; ++ + xgbe_init_rx_coalesce(pdata); + xgbe_init_tx_coalesce(pdata); + +@@ -491,18 +593,35 @@ static int xgbe_resume(struct device *dev) + } + #endif /* CONFIG_PM */ + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id xgbe_acpi_match[] = { ++ { "AMDI8001", 0 }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match); ++#endif ++ ++#ifdef CONFIG_OF + static const struct of_device_id xgbe_of_match[] = { + { .compatible = "amd,xgbe-seattle-v1a", }, + {}, + }; + + MODULE_DEVICE_TABLE(of, xgbe_of_match); ++#endif ++ + static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); + + static struct platform_driver xgbe_driver = { + .driver = { + .name = "amd-xgbe", ++#ifdef CONFIG_ACPI ++ .acpi_match_table = xgbe_acpi_match, ++#endif ++#ifdef CONFIG_OF + .of_match_table = xgbe_of_match, ++#endif + .pm = &xgbe_pm_ops, + }, + .probe = xgbe_probe, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index 363b210..59e267f 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -205,25 +205,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) + + int xgbe_mdio_register(struct xgbe_prv_data *pdata) + { +- struct device_node *phy_node; + struct mii_bus *mii; + struct phy_device *phydev; + int ret = 0; + + DBGPR("-->xgbe_mdio_register\n"); + +- /* Retrieve the phy-handle */ +- phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); +- if (!phy_node) { +- dev_err(pdata->dev, "unable to parse phy-handle\n"); +- return -EINVAL; +- } +- + mii = mdiobus_alloc(); +- if (mii == NULL) { ++ if (!mii) { + dev_err(pdata->dev, "mdiobus_alloc failed\n"); +- ret = -ENOMEM; +- goto err_node_get; ++ return -ENOMEM; + } + + /* Register on the MDIO bus (don't probe any PHYs) */ +@@ -252,18 +243,19 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) + request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, + MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS])); + +- of_node_get(phy_node); +- phydev->dev.of_node = phy_node; + ret = phy_device_register(phydev); + if (ret) { + dev_err(pdata->dev, "phy_device_register failed\n"); +- of_node_put(phy_node); ++ goto err_phy_device; ++ } ++ if (!phydev->dev.driver) { ++ dev_err(pdata->dev, "phy driver probe failed\n"); ++ ret = -EIO; + goto err_phy_device; + } + + /* Add a reference to the PHY driver so it can't be unloaded */ +- pdata->phy_module = phydev->dev.driver ? +- phydev->dev.driver->owner : NULL; ++ pdata->phy_module = phydev->dev.driver->owner; + if (!try_module_get(pdata->phy_module)) { + dev_err(pdata->dev, "try_module_get failed\n"); + ret = -EIO; +@@ -283,8 +275,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) + + pdata->phydev = phydev; + +- of_node_put(phy_node); +- + DBGPHY_REGS(pdata); + + DBGPR("<--xgbe_mdio_register\n"); +@@ -300,9 +290,6 @@ err_mdiobus_register: + err_mdiobus_alloc: + mdiobus_free(mii); + +-err_node_get: +- of_node_put(phy_node); +- + return ret; + } + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +index a1bf9d1c..f0d0ac6 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +@@ -171,21 +171,15 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; +- u64 nsec; + + spin_lock_irqsave(&pdata->tstamp_lock, flags); +- +- nsec = timecounter_read(&pdata->tstamp_tc); +- +- nsec += delta; +- timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); +- ++ timecounter_adjtime(&pdata->tstamp_tc, delta); + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + + return 0; + } + +-static int xgbe_gettime(struct ptp_clock_info *info, struct timespec *ts) ++static int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts) + { + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, +@@ -199,12 +193,13 @@ static int xgbe_gettime(struct ptp_clock_info *info, struct timespec *ts) + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + +- *ts = ns_to_timespec(nsec); ++ *ts = ns_to_timespec64(nsec); + + return 0; + } + +-static int xgbe_settime(struct ptp_clock_info *info, const struct timespec *ts) ++static int xgbe_settime(struct ptp_clock_info *info, ++ const struct timespec64 *ts) + { + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, +@@ -212,7 +207,7 @@ static int xgbe_settime(struct ptp_clock_info *info, const struct timespec *ts) + unsigned long flags; + u64 nsec; + +- nsec = timespec_to_ns(ts); ++ nsec = timespec64_to_ns(ts); + + spin_lock_irqsave(&pdata->tstamp_lock, flags); + +@@ -239,7 +234,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) + snprintf(info->name, sizeof(info->name), "%s", + netdev_name(pdata->netdev)); + info->owner = THIS_MODULE; +- info->max_adj = clk_get_rate(pdata->ptpclk); ++ info->max_adj = pdata->ptpclk_rate; + info->adjfreq = xgbe_adjfreq; + info->adjtime = xgbe_adjtime; + info->gettime = xgbe_gettime; +@@ -260,7 +255,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) + */ + dividend = 50000000; + dividend <<= 32; +- pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); ++ pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); + + /* Setup the timecounter */ + cc->read = xgbe_cc_read; +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index f9ec762..2ef3ffb 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -182,10 +182,18 @@ + #define XGBE_PHY_NAME "amd_xgbe_phy" + #define XGBE_PRTAD 0 + ++/* Common property names */ ++#define XGBE_MAC_ADDR_PROPERTY "mac-address" ++#define XGBE_PHY_MODE_PROPERTY "phy-mode" ++#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt" ++ + /* Device-tree clock names */ + #define XGBE_DMA_CLOCK "dma_clk" + #define XGBE_PTP_CLOCK "ptp_clk" +-#define XGBE_DMA_IRQS "amd,per-channel-interrupt" ++ ++/* ACPI property names */ ++#define XGBE_ACPI_DMA_FREQ "amd,dma-freq" ++#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq" + + /* Timestamp support - values based on 50MHz PTP clock + * 50MHz => 20 nsec +@@ -214,7 +222,7 @@ + ((_idx) & ((_ring)->rdesc_count - 1))) + + /* Default coalescing parameters */ +-#define XGMAC_INIT_DMA_TX_USECS 50 ++#define XGMAC_INIT_DMA_TX_USECS 1000 + #define XGMAC_INIT_DMA_TX_FRAMES 25 + + #define XGMAC_MAX_DMA_RIWT 0xff +@@ -317,8 +325,6 @@ struct xgbe_ring_data { + struct xgbe_tx_ring_data tx; /* Tx-related data */ + struct xgbe_rx_ring_data rx; /* Rx-related data */ + +- unsigned int interrupt; /* Interrupt indicator */ +- + unsigned int mapped_as_page; + + /* Incomplete receive save location. If the budget is exhausted +@@ -361,8 +367,7 @@ struct xgbe_ring { + * cur - Tx: index of descriptor to be used for current transfer + * Rx: index of descriptor to check for packet availability + * dirty - Tx: index of descriptor to check for transfer complete +- * Rx: count of descriptors in which a packet has been received +- * (used with skb_realloc_index to refresh the ring) ++ * Rx: index of descriptor to check for buffer reallocation + */ + unsigned int cur; + unsigned int dirty; +@@ -377,11 +382,6 @@ struct xgbe_ring { + unsigned short cur_mss; + unsigned short cur_vlan_ctag; + } tx; +- +- struct { +- unsigned int realloc_index; +- unsigned int realloc_threshold; +- } rx; + }; + } ____cacheline_aligned; + +@@ -408,7 +408,7 @@ struct xgbe_channel { + unsigned int saved_ier; + + unsigned int tx_timer_active; +- struct hrtimer tx_timer; ++ struct timer_list tx_timer; + + struct xgbe_ring *tx_ring; + struct xgbe_ring *rx_ring; +@@ -495,10 +495,8 @@ struct xgbe_mmc_stats { + struct xgbe_hw_if { + int (*tx_complete)(struct xgbe_ring_desc *); + +- int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int); +- int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int); +- int (*add_mac_addresses)(struct xgbe_prv_data *); + int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr); ++ int (*config_rx_mode)(struct xgbe_prv_data *); + + int (*enable_rx_csum)(struct xgbe_prv_data *); + int (*disable_rx_csum)(struct xgbe_prv_data *); +@@ -534,8 +532,9 @@ struct xgbe_hw_if { + int (*dev_read)(struct xgbe_channel *); + void (*tx_desc_init)(struct xgbe_channel *); + void (*rx_desc_init)(struct xgbe_channel *); +- void (*rx_desc_reset)(struct xgbe_ring_data *); + void (*tx_desc_reset)(struct xgbe_ring_data *); ++ void (*rx_desc_reset)(struct xgbe_prv_data *, struct xgbe_ring_data *, ++ unsigned int); + int (*is_last_desc)(struct xgbe_ring_desc *); + int (*is_context_desc)(struct xgbe_ring_desc *); + void (*tx_start_xmit)(struct xgbe_channel *, struct xgbe_ring *); +@@ -596,7 +595,8 @@ struct xgbe_desc_if { + int (*alloc_ring_resources)(struct xgbe_prv_data *); + void (*free_ring_resources)(struct xgbe_prv_data *); + int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *); +- void (*realloc_rx_buffer)(struct xgbe_channel *); ++ int (*map_rx_buffer)(struct xgbe_prv_data *, struct xgbe_ring *, ++ struct xgbe_ring_data *); + void (*unmap_rdata)(struct xgbe_prv_data *, struct xgbe_ring_data *); + void (*wrapper_tx_desc_init)(struct xgbe_prv_data *); + void (*wrapper_rx_desc_init)(struct xgbe_prv_data *); +@@ -617,7 +617,7 @@ struct xgbe_hw_features { + unsigned int mgk; /* PMT magic packet */ + unsigned int mmc; /* RMON module */ + unsigned int aoe; /* ARP Offload */ +- unsigned int ts; /* IEEE 1588-2008 Adavanced Timestamp */ ++ unsigned int ts; /* IEEE 1588-2008 Advanced Timestamp */ + unsigned int eee; /* Energy Efficient Ethernet */ + unsigned int tx_coe; /* Tx Checksum Offload */ + unsigned int rx_coe; /* Rx Checksum Offload */ +@@ -629,6 +629,7 @@ struct xgbe_hw_features { + unsigned int rx_fifo_size; /* MTL Receive FIFO Size */ + unsigned int tx_fifo_size; /* MTL Transmit FIFO Size */ + unsigned int adv_ts_hi; /* Advance Timestamping High Word */ ++ unsigned int dma_width; /* DMA width */ + unsigned int dcb; /* DCB Feature */ + unsigned int sph; /* Split Header Feature */ + unsigned int tso; /* TCP Segmentation Offload */ +@@ -650,8 +651,12 @@ struct xgbe_hw_features { + struct xgbe_prv_data { + struct net_device *netdev; + struct platform_device *pdev; ++ struct acpi_device *adev; + struct device *dev; + ++ /* ACPI or DT flag */ ++ unsigned int use_acpi; ++ + /* XGMAC/XPCS related mmio registers */ + void __iomem *xgmac_regs; /* XGMAC CSRs */ + void __iomem *xpcs_regs; /* XPCS MMD registers */ +@@ -672,6 +677,7 @@ struct xgbe_prv_data { + struct xgbe_desc_if desc_if; + + /* AXI DMA settings */ ++ unsigned int coherent; + unsigned int axdomain; + unsigned int arcache; + unsigned int awcache; +@@ -707,6 +713,7 @@ struct xgbe_prv_data { + + /* Rx coalescing settings */ + unsigned int rx_riwt; ++ unsigned int rx_usecs; + unsigned int rx_frames; + + /* Current Rx buffer size */ +@@ -739,6 +746,7 @@ struct xgbe_prv_data { + unsigned int phy_rx_pause; + + /* Netdev related settings */ ++ unsigned char mac_addr[ETH_ALEN]; + netdev_features_t netdev_features; + struct napi_struct napi; + struct xgbe_mmc_stats mmc_stats; +@@ -748,7 +756,9 @@ struct xgbe_prv_data { + + /* Device clocks */ + struct clk *sysclk; ++ unsigned long sysclk_rate; + struct clk *ptpclk; ++ unsigned long ptpclk_rate; + + /* Timestamp support */ + spinlock_t tstamp_lock; +diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c +index 903dc3d..34a75cb 100644 +--- a/drivers/net/phy/amd-xgbe-phy.c ++++ b/drivers/net/phy/amd-xgbe-phy.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -74,6 +75,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + MODULE_AUTHOR("Tom Lendacky "); + MODULE_LICENSE("Dual BSD/GPL"); +@@ -84,22 +89,47 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); + #define XGBE_PHY_MASK 0xfffffff0 + + #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" ++#define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc" ++#define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" ++#define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" ++#define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp" ++#define XGBE_PHY_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config" ++#define XGBE_PHY_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable" ++ ++#define XGBE_PHY_SPEEDS 3 ++#define XGBE_PHY_SPEED_1000 0 ++#define XGBE_PHY_SPEED_2500 1 ++#define XGBE_PHY_SPEED_10000 2 ++ ++#define XGBE_AN_MS_TIMEOUT 500 + + #define XGBE_AN_INT_CMPLT 0x01 + #define XGBE_AN_INC_LINK 0x02 + #define XGBE_AN_PG_RCV 0x04 ++#define XGBE_AN_INT_MASK 0x07 + + #define XNP_MCF_NULL_MESSAGE 0x001 +-#define XNP_ACK_PROCESSED (1 << 12) +-#define XNP_MP_FORMATTED (1 << 13) +-#define XNP_NP_EXCHANGE (1 << 15) ++#define XNP_ACK_PROCESSED BIT(12) ++#define XNP_MP_FORMATTED BIT(13) ++#define XNP_NP_EXCHANGE BIT(15) + + #define XGBE_PHY_RATECHANGE_COUNT 500 + ++#define XGBE_PHY_KR_TRAINING_START 0x01 ++#define XGBE_PHY_KR_TRAINING_ENABLE 0x02 ++ ++#define XGBE_PHY_FEC_ENABLE 0x01 ++#define XGBE_PHY_FEC_FORWARD 0x02 ++#define XGBE_PHY_FEC_MASK 0x03 ++ + #ifndef MDIO_PMA_10GBR_PMD_CTRL + #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 + #endif + ++#ifndef MDIO_PMA_10GBR_FEC_ABILITY ++#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa ++#endif ++ + #ifndef MDIO_PMA_10GBR_FEC_CTRL + #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab + #endif +@@ -108,6 +138,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); + #define MDIO_AN_XNP 0x0016 + #endif + ++#ifndef MDIO_AN_LPX ++#define MDIO_AN_LPX 0x0019 ++#endif ++ + #ifndef MDIO_AN_INTMASK + #define MDIO_AN_INTMASK 0x8001 + #endif +@@ -116,18 +150,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); + #define MDIO_AN_INT 0x8002 + #endif + +-#ifndef MDIO_AN_KR_CTRL +-#define MDIO_AN_KR_CTRL 0x8003 +-#endif +- + #ifndef MDIO_CTRL1_SPEED1G + #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) + #endif + +-#ifndef MDIO_KR_CTRL_PDETECT +-#define MDIO_KR_CTRL_PDETECT 0x01 +-#endif +- + /* SerDes integration register offsets */ + #define SIR0_KR_RT_1 0x002c + #define SIR0_STATUS 0x0040 +@@ -140,10 +166,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); + #define SIR0_STATUS_RX_READY_WIDTH 1 + #define SIR0_STATUS_TX_READY_INDEX 8 + #define SIR0_STATUS_TX_READY_WIDTH 1 ++#define SIR1_SPEED_CDR_RATE_INDEX 12 ++#define SIR1_SPEED_CDR_RATE_WIDTH 4 + #define SIR1_SPEED_DATARATE_INDEX 4 + #define SIR1_SPEED_DATARATE_WIDTH 2 +-#define SIR1_SPEED_PI_SPD_SEL_INDEX 12 +-#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4 + #define SIR1_SPEED_PLLSEL_INDEX 3 + #define SIR1_SPEED_PLLSEL_WIDTH 1 + #define SIR1_SPEED_RATECHANGE_INDEX 6 +@@ -153,42 +179,52 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); + #define SIR1_SPEED_WORDMODE_INDEX 0 + #define SIR1_SPEED_WORDMODE_WIDTH 3 + ++#define SPEED_10000_BLWC 0 + #define SPEED_10000_CDR 0x7 + #define SPEED_10000_PLL 0x1 ++#define SPEED_10000_PQ 0x12 + #define SPEED_10000_RATE 0x0 + #define SPEED_10000_TXAMP 0xa + #define SPEED_10000_WORD 0x7 ++#define SPEED_10000_DFE_TAP_CONFIG 0x1 ++#define SPEED_10000_DFE_TAP_ENABLE 0x7f + ++#define SPEED_2500_BLWC 1 + #define SPEED_2500_CDR 0x2 + #define SPEED_2500_PLL 0x0 ++#define SPEED_2500_PQ 0xa + #define SPEED_2500_RATE 0x1 + #define SPEED_2500_TXAMP 0xf + #define SPEED_2500_WORD 0x1 ++#define SPEED_2500_DFE_TAP_CONFIG 0x3 ++#define SPEED_2500_DFE_TAP_ENABLE 0x0 + ++#define SPEED_1000_BLWC 1 + #define SPEED_1000_CDR 0x2 + #define SPEED_1000_PLL 0x0 ++#define SPEED_1000_PQ 0xa + #define SPEED_1000_RATE 0x3 + #define SPEED_1000_TXAMP 0xf + #define SPEED_1000_WORD 0x1 ++#define SPEED_1000_DFE_TAP_CONFIG 0x3 ++#define SPEED_1000_DFE_TAP_ENABLE 0x0 + + /* SerDes RxTx register offsets */ ++#define RXTX_REG6 0x0018 + #define RXTX_REG20 0x0050 ++#define RXTX_REG22 0x0058 + #define RXTX_REG114 0x01c8 ++#define RXTX_REG129 0x0204 + + /* SerDes RxTx register entry bit positions and sizes */ ++#define RXTX_REG6_RESETB_RXD_INDEX 8 ++#define RXTX_REG6_RESETB_RXD_WIDTH 1 + #define RXTX_REG20_BLWC_ENA_INDEX 2 + #define RXTX_REG20_BLWC_ENA_WIDTH 1 + #define RXTX_REG114_PQ_REG_INDEX 9 + #define RXTX_REG114_PQ_REG_WIDTH 7 +- +-#define RXTX_10000_BLWC 0 +-#define RXTX_10000_PQ 0x1e +- +-#define RXTX_2500_BLWC 1 +-#define RXTX_2500_PQ 0xa +- +-#define RXTX_1000_BLWC 1 +-#define RXTX_1000_PQ 0xa ++#define RXTX_REG129_RXDFE_CONFIG_INDEX 14 ++#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2 + + /* Bit setting and getting macros + * The get macro will extract the current bit field value from within +@@ -291,23 +327,56 @@ do { \ + XRXTX_IOWRITE((_priv), _reg, reg_val); \ + } while (0) + ++static const u32 amd_xgbe_phy_serdes_blwc[] = { ++ SPEED_1000_BLWC, ++ SPEED_2500_BLWC, ++ SPEED_10000_BLWC, ++}; ++ ++static const u32 amd_xgbe_phy_serdes_cdr_rate[] = { ++ SPEED_1000_CDR, ++ SPEED_2500_CDR, ++ SPEED_10000_CDR, ++}; ++ ++static const u32 amd_xgbe_phy_serdes_pq_skew[] = { ++ SPEED_1000_PQ, ++ SPEED_2500_PQ, ++ SPEED_10000_PQ, ++}; ++ ++static const u32 amd_xgbe_phy_serdes_tx_amp[] = { ++ SPEED_1000_TXAMP, ++ SPEED_2500_TXAMP, ++ SPEED_10000_TXAMP, ++}; ++ ++static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = { ++ SPEED_1000_DFE_TAP_CONFIG, ++ SPEED_2500_DFE_TAP_CONFIG, ++ SPEED_10000_DFE_TAP_CONFIG, ++}; ++ ++static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = { ++ SPEED_1000_DFE_TAP_ENABLE, ++ SPEED_2500_DFE_TAP_ENABLE, ++ SPEED_10000_DFE_TAP_ENABLE, ++}; ++ + enum amd_xgbe_phy_an { + AMD_XGBE_AN_READY = 0, +- AMD_XGBE_AN_START, +- AMD_XGBE_AN_EVENT, + AMD_XGBE_AN_PAGE_RECEIVED, + AMD_XGBE_AN_INCOMPAT_LINK, + AMD_XGBE_AN_COMPLETE, + AMD_XGBE_AN_NO_LINK, +- AMD_XGBE_AN_EXIT, + AMD_XGBE_AN_ERROR, + }; + + enum amd_xgbe_phy_rx { +- AMD_XGBE_RX_READY = 0, +- AMD_XGBE_RX_BPA, ++ AMD_XGBE_RX_BPA = 0, + AMD_XGBE_RX_XNP, + AMD_XGBE_RX_COMPLETE, ++ AMD_XGBE_RX_ERROR, + }; + + enum amd_xgbe_phy_mode { +@@ -316,12 +385,13 @@ enum amd_xgbe_phy_mode { + }; + + enum amd_xgbe_phy_speedset { +- AMD_XGBE_PHY_SPEEDSET_1000_10000, ++ AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, + AMD_XGBE_PHY_SPEEDSET_2500_10000, + }; + + struct amd_xgbe_phy_priv { + struct platform_device *pdev; ++ struct acpi_device *adev; + struct device *dev; + + struct phy_device *phydev; +@@ -336,10 +406,26 @@ struct amd_xgbe_phy_priv { + void __iomem *sir0_regs; /* SerDes integration registers (1/2) */ + void __iomem *sir1_regs; /* SerDes integration registers (2/2) */ + +- /* Maintain link status for re-starting auto-negotiation */ +- unsigned int link; ++ int an_irq; ++ char an_irq_name[IFNAMSIZ + 32]; ++ struct work_struct an_irq_work; ++ unsigned int an_irq_allocated; ++ + unsigned int speed_set; + ++ /* SerDes UEFI configurable settings. ++ * Switching between modes/speeds requires new values for some ++ * SerDes settings. The values can be supplied as device ++ * properties in array format. The first array entry is for ++ * 1GbE, second for 2.5GbE and third for 10GbE ++ */ ++ u32 serdes_blwc[XGBE_PHY_SPEEDS]; ++ u32 serdes_cdr_rate[XGBE_PHY_SPEEDS]; ++ u32 serdes_pq_skew[XGBE_PHY_SPEEDS]; ++ u32 serdes_tx_amp[XGBE_PHY_SPEEDS]; ++ u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS]; ++ u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS]; ++ + /* Auto-negotiation state machine support */ + struct mutex an_mutex; + enum amd_xgbe_phy_an an_result; +@@ -348,7 +434,12 @@ struct amd_xgbe_phy_priv { + enum amd_xgbe_phy_rx kx_state; + struct work_struct an_work; + struct workqueue_struct *an_workqueue; ++ unsigned int an_supported; + unsigned int parallel_detect; ++ unsigned int fec_ability; ++ unsigned long an_start; ++ ++ unsigned int lpm_ctrl; /* CTRL1 for resume */ + }; + + static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) +@@ -359,7 +450,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) + if (ret < 0) + return ret; + +- ret |= 0x02; ++ ret |= XGBE_PHY_KR_TRAINING_ENABLE; + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); + + return 0; +@@ -373,7 +464,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev) + if (ret < 0) + return ret; + +- ret &= ~0x02; ++ ret &= ~XGBE_PHY_KR_TRAINING_ENABLE; + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); + + return 0; +@@ -423,11 +514,16 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) + status = XSIR0_IOREAD(priv, SIR0_STATUS); + if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && + XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) +- return; ++ goto rx_reset; + } + + netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", + status); ++ ++rx_reset: ++ /* Perform Rx reset for the DFE changes */ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1); + } + + static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) +@@ -466,12 +562,20 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) + + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR); + +- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC); +- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, ++ priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, ++ priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, ++ priv->serdes_blwc[XGBE_PHY_SPEED_10000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, ++ priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, ++ priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]); ++ XRXTX_IOWRITE(priv, RXTX_REG22, ++ priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]); + + amd_xgbe_phy_serdes_complete_ratechange(phydev); + +@@ -514,12 +618,20 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) + + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR); + +- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC); +- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, ++ priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, ++ priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, ++ priv->serdes_blwc[XGBE_PHY_SPEED_2500]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, ++ priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, ++ priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]); ++ XRXTX_IOWRITE(priv, RXTX_REG22, ++ priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]); + + amd_xgbe_phy_serdes_complete_ratechange(phydev); + +@@ -562,12 +674,20 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) + + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL); +- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR); + +- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC); +- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, ++ priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]); ++ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, ++ priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, ++ priv->serdes_blwc[XGBE_PHY_SPEED_1000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, ++ priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, ++ priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]); ++ XRXTX_IOWRITE(priv, RXTX_REG22, ++ priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]); + + amd_xgbe_phy_serdes_complete_ratechange(phydev); + +@@ -635,6 +755,77 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev, + return ret; + } + ++static bool amd_xgbe_phy_use_xgmii_mode(struct phy_device *phydev) ++{ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->advertising & ADVERTISED_10000baseKR_Full) ++ return true; ++ } else { ++ if (phydev->speed == SPEED_10000) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool amd_xgbe_phy_use_gmii_2500_mode(struct phy_device *phydev) ++{ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->advertising & ADVERTISED_2500baseX_Full) ++ return true; ++ } else { ++ if (phydev->speed == SPEED_2500) ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool amd_xgbe_phy_use_gmii_mode(struct phy_device *phydev) ++{ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (phydev->advertising & ADVERTISED_1000baseKX_Full) ++ return true; ++ } else { ++ if (phydev->speed == SPEED_1000) ++ return true; ++ } ++ ++ return false; ++} ++ ++static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable, ++ bool restart) ++{ ++ int ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_AN_CTRL1_ENABLE; ++ ++ if (enable) ++ ret |= MDIO_AN_CTRL1_ENABLE; ++ ++ if (restart) ++ ret |= MDIO_AN_CTRL1_RESTART; ++ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_restart_an(struct phy_device *phydev) ++{ ++ return amd_xgbe_phy_set_an(phydev, true, true); ++} ++ ++static int amd_xgbe_phy_disable_an(struct phy_device *phydev) ++{ ++ return amd_xgbe_phy_set_an(phydev, false, false); ++} ++ + static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, + enum amd_xgbe_phy_rx *state) + { +@@ -645,7 +836,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, + + /* If we're not in KR mode then we're done */ + if (!amd_xgbe_phy_in_kr_mode(phydev)) +- return AMD_XGBE_AN_EVENT; ++ return AMD_XGBE_AN_PAGE_RECEIVED; + + /* Enable/Disable FEC */ + ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); +@@ -660,10 +851,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, + if (ret < 0) + return AMD_XGBE_AN_ERROR; + ++ ret &= ~XGBE_PHY_FEC_MASK; + if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) +- ret |= 0x01; +- else +- ret &= ~0x01; ++ ret |= priv->fec_ability; + + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); + +@@ -672,14 +862,17 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, + if (ret < 0) + return AMD_XGBE_AN_ERROR; + +- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); ++ if (ret & XGBE_PHY_KR_TRAINING_ENABLE) { ++ XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); + +- ret |= 0x01; +- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); ++ ret |= XGBE_PHY_KR_TRAINING_START; ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ++ ret); + +- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); ++ XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); ++ } + +- return AMD_XGBE_AN_EVENT; ++ return AMD_XGBE_AN_PAGE_RECEIVED; + } + + static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, +@@ -696,7 +889,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); + +- return AMD_XGBE_AN_EVENT; ++ return AMD_XGBE_AN_PAGE_RECEIVED; + } + + static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, +@@ -735,11 +928,11 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, + int ad_reg, lp_reg; + + /* Check Extended Next Page support */ +- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP); + if (ad_reg < 0) + return AMD_XGBE_AN_ERROR; + +- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); ++ lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX); + if (lp_reg < 0) + return AMD_XGBE_AN_ERROR; + +@@ -748,226 +941,271 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, + amd_xgbe_an_tx_training(phydev, state); + } + +-static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) ++static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv = phydev->priv; ++ enum amd_xgbe_phy_rx *state; ++ unsigned long an_timeout; + int ret; + +- /* Be sure we aren't looping trying to negotiate */ +- if (amd_xgbe_phy_in_kr_mode(phydev)) { +- if (priv->kr_state != AMD_XGBE_RX_READY) +- return AMD_XGBE_AN_NO_LINK; +- priv->kr_state = AMD_XGBE_RX_BPA; ++ if (!priv->an_start) { ++ priv->an_start = jiffies; + } else { +- if (priv->kx_state != AMD_XGBE_RX_READY) +- return AMD_XGBE_AN_NO_LINK; +- priv->kx_state = AMD_XGBE_RX_BPA; ++ an_timeout = priv->an_start + ++ msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); ++ if (time_after(jiffies, an_timeout)) { ++ /* Auto-negotiation timed out, reset state */ ++ priv->kr_state = AMD_XGBE_RX_BPA; ++ priv->kx_state = AMD_XGBE_RX_BPA; ++ ++ priv->an_start = jiffies; ++ } + } + +- /* Set up Advertisement register 3 first */ +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); +- if (ret < 0) +- return AMD_XGBE_AN_ERROR; +- +- if (phydev->supported & SUPPORTED_10000baseR_FEC) +- ret |= 0xc000; +- else +- ret &= ~0xc000; +- +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); ++ state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state ++ : &priv->kx_state; + +- /* Set up Advertisement register 2 next */ +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); +- if (ret < 0) +- return AMD_XGBE_AN_ERROR; ++ switch (*state) { ++ case AMD_XGBE_RX_BPA: ++ ret = amd_xgbe_an_rx_bpa(phydev, state); ++ break; + +- if (phydev->supported & SUPPORTED_10000baseKR_Full) +- ret |= 0x80; +- else +- ret &= ~0x80; ++ case AMD_XGBE_RX_XNP: ++ ret = amd_xgbe_an_rx_xnp(phydev, state); ++ break; + +- if ((phydev->supported & SUPPORTED_1000baseKX_Full) || +- (phydev->supported & SUPPORTED_2500baseX_Full)) +- ret |= 0x20; +- else +- ret &= ~0x20; ++ default: ++ ret = AMD_XGBE_AN_ERROR; ++ } + +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); ++ return ret; ++} + +- /* Set up Advertisement register 1 last */ +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); +- if (ret < 0) +- return AMD_XGBE_AN_ERROR; ++static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; + +- if (phydev->supported & SUPPORTED_Pause) +- ret |= 0x400; +- else +- ret &= ~0x400; ++ /* Be sure we aren't looping trying to negotiate */ ++ if (amd_xgbe_phy_in_kr_mode(phydev)) { ++ priv->kr_state = AMD_XGBE_RX_ERROR; + +- if (phydev->supported & SUPPORTED_Asym_Pause) +- ret |= 0x800; +- else +- ret &= ~0x800; ++ if (!(phydev->advertising & SUPPORTED_1000baseKX_Full) && ++ !(phydev->advertising & SUPPORTED_2500baseX_Full)) ++ return AMD_XGBE_AN_NO_LINK; + +- /* We don't intend to perform XNP */ +- ret &= ~XNP_NP_EXCHANGE; ++ if (priv->kx_state != AMD_XGBE_RX_BPA) ++ return AMD_XGBE_AN_NO_LINK; ++ } else { ++ priv->kx_state = AMD_XGBE_RX_ERROR; + +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); ++ if (!(phydev->advertising & SUPPORTED_10000baseKR_Full)) ++ return AMD_XGBE_AN_NO_LINK; + +- /* Enable and start auto-negotiation */ +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ if (priv->kr_state != AMD_XGBE_RX_BPA) ++ return AMD_XGBE_AN_NO_LINK; ++ } + +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL); +- if (ret < 0) ++ ret = amd_xgbe_phy_disable_an(phydev); ++ if (ret) + return AMD_XGBE_AN_ERROR; + +- ret |= MDIO_KR_CTRL_PDETECT; +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret); +- +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); +- if (ret < 0) ++ ret = amd_xgbe_phy_switch_mode(phydev); ++ if (ret) + return AMD_XGBE_AN_ERROR; + +- ret |= MDIO_AN_CTRL1_ENABLE; +- ret |= MDIO_AN_CTRL1_RESTART; +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); ++ ret = amd_xgbe_phy_restart_an(phydev); ++ if (ret) ++ return AMD_XGBE_AN_ERROR; + +- return AMD_XGBE_AN_EVENT; ++ return AMD_XGBE_AN_INCOMPAT_LINK; + } + +-static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev) ++static irqreturn_t amd_xgbe_an_isr(int irq, void *data) + { +- enum amd_xgbe_phy_an new_state; +- int ret; ++ struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data; + +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); +- if (ret < 0) +- return AMD_XGBE_AN_ERROR; ++ /* Interrupt reason must be read and cleared outside of IRQ context */ ++ disable_irq_nosync(priv->an_irq); + +- new_state = AMD_XGBE_AN_EVENT; +- if (ret & XGBE_AN_PG_RCV) +- new_state = AMD_XGBE_AN_PAGE_RECEIVED; +- else if (ret & XGBE_AN_INC_LINK) +- new_state = AMD_XGBE_AN_INCOMPAT_LINK; +- else if (ret & XGBE_AN_INT_CMPLT) +- new_state = AMD_XGBE_AN_COMPLETE; ++ queue_work(priv->an_workqueue, &priv->an_irq_work); + +- if (new_state != AMD_XGBE_AN_EVENT) +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ return IRQ_HANDLED; ++} ++ ++static void amd_xgbe_an_irq_work(struct work_struct *work) ++{ ++ struct amd_xgbe_phy_priv *priv = container_of(work, ++ struct amd_xgbe_phy_priv, ++ an_irq_work); + +- return new_state; ++ /* Avoid a race between enabling the IRQ and exiting the work by ++ * waiting for the work to finish and then queueing it ++ */ ++ flush_work(&priv->an_work); ++ queue_work(priv->an_workqueue, &priv->an_work); + } + +-static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) ++static void amd_xgbe_an_state_machine(struct work_struct *work) + { +- struct amd_xgbe_phy_priv *priv = phydev->priv; +- enum amd_xgbe_phy_rx *state; +- int ret; ++ struct amd_xgbe_phy_priv *priv = container_of(work, ++ struct amd_xgbe_phy_priv, ++ an_work); ++ struct phy_device *phydev = priv->phydev; ++ enum amd_xgbe_phy_an cur_state = priv->an_state; ++ int int_reg, int_mask; + +- state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state +- : &priv->kx_state; ++ mutex_lock(&priv->an_mutex); + +- switch (*state) { +- case AMD_XGBE_RX_BPA: +- ret = amd_xgbe_an_rx_bpa(phydev, state); ++ /* Read the interrupt */ ++ int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); ++ if (!int_reg) ++ goto out; ++ ++next_int: ++ if (int_reg < 0) { ++ priv->an_state = AMD_XGBE_AN_ERROR; ++ int_mask = XGBE_AN_INT_MASK; ++ } else if (int_reg & XGBE_AN_PG_RCV) { ++ priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED; ++ int_mask = XGBE_AN_PG_RCV; ++ } else if (int_reg & XGBE_AN_INC_LINK) { ++ priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK; ++ int_mask = XGBE_AN_INC_LINK; ++ } else if (int_reg & XGBE_AN_INT_CMPLT) { ++ priv->an_state = AMD_XGBE_AN_COMPLETE; ++ int_mask = XGBE_AN_INT_CMPLT; ++ } else { ++ priv->an_state = AMD_XGBE_AN_ERROR; ++ int_mask = 0; ++ } ++ ++ /* Clear the interrupt to be processed */ ++ int_reg &= ~int_mask; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg); ++ ++ priv->an_result = priv->an_state; ++ ++again: ++ cur_state = priv->an_state; ++ ++ switch (priv->an_state) { ++ case AMD_XGBE_AN_READY: ++ priv->an_supported = 0; + break; + +- case AMD_XGBE_RX_XNP: +- ret = amd_xgbe_an_rx_xnp(phydev, state); ++ case AMD_XGBE_AN_PAGE_RECEIVED: ++ priv->an_state = amd_xgbe_an_page_received(phydev); ++ priv->an_supported++; ++ break; ++ ++ case AMD_XGBE_AN_INCOMPAT_LINK: ++ priv->an_supported = 0; ++ priv->parallel_detect = 0; ++ priv->an_state = amd_xgbe_an_incompat_link(phydev); ++ break; ++ ++ case AMD_XGBE_AN_COMPLETE: ++ priv->parallel_detect = priv->an_supported ? 0 : 1; ++ netdev_dbg(phydev->attached_dev, "%s successful\n", ++ priv->an_supported ? "Auto negotiation" ++ : "Parallel detection"); ++ break; ++ ++ case AMD_XGBE_AN_NO_LINK: + break; + + default: +- ret = AMD_XGBE_AN_ERROR; ++ priv->an_state = AMD_XGBE_AN_ERROR; + } + +- return ret; +-} ++ if (priv->an_state == AMD_XGBE_AN_NO_LINK) { ++ int_reg = 0; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ } else if (priv->an_state == AMD_XGBE_AN_ERROR) { ++ netdev_err(phydev->attached_dev, ++ "error during auto-negotiation, state=%u\n", ++ cur_state); + +-static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) +-{ +- int ret; ++ int_reg = 0; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ } + +- ret = amd_xgbe_phy_switch_mode(phydev); +- if (ret) +- return AMD_XGBE_AN_ERROR; ++ if (priv->an_state >= AMD_XGBE_AN_COMPLETE) { ++ priv->an_result = priv->an_state; ++ priv->an_state = AMD_XGBE_AN_READY; ++ priv->kr_state = AMD_XGBE_RX_BPA; ++ priv->kx_state = AMD_XGBE_RX_BPA; ++ priv->an_start = 0; ++ } + +- return AMD_XGBE_AN_START; +-} ++ if (cur_state != priv->an_state) ++ goto again; + +-static void amd_xgbe_an_state_machine(struct work_struct *work) +-{ +- struct amd_xgbe_phy_priv *priv = container_of(work, +- struct amd_xgbe_phy_priv, +- an_work); +- struct phy_device *phydev = priv->phydev; +- enum amd_xgbe_phy_an cur_state; +- int sleep; +- unsigned int an_supported = 0; ++ if (int_reg) ++ goto next_int; + +- /* Start in KX mode */ +- if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX)) +- priv->an_state = AMD_XGBE_AN_ERROR; ++out: ++ enable_irq(priv->an_irq); + +- while (1) { +- mutex_lock(&priv->an_mutex); ++ mutex_unlock(&priv->an_mutex); ++} + +- cur_state = priv->an_state; ++static int amd_xgbe_an_init(struct phy_device *phydev) ++{ ++ int ret; + +- switch (priv->an_state) { +- case AMD_XGBE_AN_START: +- an_supported = 0; +- priv->parallel_detect = 0; +- priv->an_state = amd_xgbe_an_start(phydev); +- break; ++ /* Set up Advertisement register 3 first */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ++ if (ret < 0) ++ return ret; + +- case AMD_XGBE_AN_EVENT: +- priv->an_state = amd_xgbe_an_event(phydev); +- break; ++ if (phydev->advertising & SUPPORTED_10000baseR_FEC) ++ ret |= 0xc000; ++ else ++ ret &= ~0xc000; + +- case AMD_XGBE_AN_PAGE_RECEIVED: +- priv->an_state = amd_xgbe_an_page_received(phydev); +- an_supported++; +- break; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); + +- case AMD_XGBE_AN_INCOMPAT_LINK: +- priv->an_state = amd_xgbe_an_incompat_link(phydev); +- break; ++ /* Set up Advertisement register 2 next */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ++ if (ret < 0) ++ return ret; + +- case AMD_XGBE_AN_COMPLETE: +- priv->parallel_detect = an_supported ? 0 : 1; +- netdev_info(phydev->attached_dev, "%s successful\n", +- an_supported ? "Auto negotiation" +- : "Parallel detection"); +- /* fall through */ ++ if (phydev->advertising & SUPPORTED_10000baseKR_Full) ++ ret |= 0x80; ++ else ++ ret &= ~0x80; + +- case AMD_XGBE_AN_NO_LINK: +- case AMD_XGBE_AN_EXIT: +- goto exit_unlock; ++ if ((phydev->advertising & SUPPORTED_1000baseKX_Full) || ++ (phydev->advertising & SUPPORTED_2500baseX_Full)) ++ ret |= 0x20; ++ else ++ ret &= ~0x20; + +- default: +- priv->an_state = AMD_XGBE_AN_ERROR; +- } ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); + +- if (priv->an_state == AMD_XGBE_AN_ERROR) { +- netdev_err(phydev->attached_dev, +- "error during auto-negotiation, state=%u\n", +- cur_state); +- goto exit_unlock; +- } ++ /* Set up Advertisement register 1 last */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ if (ret < 0) ++ return ret; + +- sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0; ++ if (phydev->advertising & SUPPORTED_Pause) ++ ret |= 0x400; ++ else ++ ret &= ~0x400; + +- mutex_unlock(&priv->an_mutex); ++ if (phydev->advertising & SUPPORTED_Asym_Pause) ++ ret |= 0x800; ++ else ++ ret &= ~0x800; + +- if (sleep) +- usleep_range(20, 50); +- } ++ /* We don't intend to perform XNP */ ++ ret &= ~XNP_NP_EXCHANGE; + +-exit_unlock: +- priv->an_result = priv->an_state; +- priv->an_state = AMD_XGBE_AN_READY; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); + +- mutex_unlock(&priv->an_mutex); ++ return 0; + } + + static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) +@@ -992,33 +1230,68 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) + if (ret & MDIO_CTRL1_RESET) + return -ETIMEDOUT; + +- /* Make sure the XPCS and SerDes are in compatible states */ +- return amd_xgbe_phy_xgmii_mode(phydev); ++ /* Disable auto-negotiation for now */ ++ ret = amd_xgbe_phy_disable_an(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Clear auto-negotiation interrupts */ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ ++ return 0; + } + + static int amd_xgbe_phy_config_init(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv = phydev->priv; ++ struct net_device *netdev = phydev->attached_dev; ++ int ret; + +- /* Initialize supported features */ +- phydev->supported = SUPPORTED_Autoneg; +- phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; +- phydev->supported |= SUPPORTED_Backplane; +- phydev->supported |= SUPPORTED_10000baseKR_Full | +- SUPPORTED_10000baseR_FEC; +- switch (priv->speed_set) { +- case AMD_XGBE_PHY_SPEEDSET_1000_10000: +- phydev->supported |= SUPPORTED_1000baseKX_Full; +- break; +- case AMD_XGBE_PHY_SPEEDSET_2500_10000: +- phydev->supported |= SUPPORTED_2500baseX_Full; +- break; ++ if (!priv->an_irq_allocated) { ++ /* Allocate the auto-negotiation workqueue and interrupt */ ++ snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1, ++ "%s-pcs", netdev_name(netdev)); ++ ++ priv->an_workqueue = ++ create_singlethread_workqueue(priv->an_irq_name); ++ if (!priv->an_workqueue) { ++ netdev_err(netdev, "phy workqueue creation failed\n"); ++ return -ENOMEM; ++ } ++ ++ ret = devm_request_irq(priv->dev, priv->an_irq, ++ amd_xgbe_an_isr, 0, priv->an_irq_name, ++ priv); ++ if (ret) { ++ netdev_err(netdev, "phy irq request failed\n"); ++ destroy_workqueue(priv->an_workqueue); ++ return ret; ++ } ++ ++ priv->an_irq_allocated = 1; + } +- phydev->advertising = phydev->supported; + +- /* Turn off and clear interrupts */ +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ /* Set initial mode - call the mode setting routines ++ * directly to insure we are properly configured ++ */ ++ if (amd_xgbe_phy_use_xgmii_mode(phydev)) ++ ret = amd_xgbe_phy_xgmii_mode(phydev); ++ else if (amd_xgbe_phy_use_gmii_mode(phydev)) ++ ret = amd_xgbe_phy_gmii_mode(phydev); ++ else if (amd_xgbe_phy_use_gmii_2500_mode(phydev)) ++ ret = amd_xgbe_phy_gmii_2500_mode(phydev); ++ else ++ ret = -EINVAL; ++ if (ret < 0) ++ return ret; ++ ++ /* Set up advertisement registers based on current settings */ ++ ret = amd_xgbe_an_init(phydev); ++ if (ret) ++ return ret; ++ ++ /* Enable auto-negotiation interrupts */ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); + + return 0; + } +@@ -1028,25 +1301,19 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) + int ret; + + /* Disable auto-negotiation */ +- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); ++ ret = amd_xgbe_phy_disable_an(phydev); + if (ret < 0) + return ret; + +- ret &= ~MDIO_AN_CTRL1_ENABLE; +- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); +- + /* Validate/Set specified speed */ + switch (phydev->speed) { + case SPEED_10000: +- ret = amd_xgbe_phy_xgmii_mode(phydev); ++ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); + break; + + case SPEED_2500: +- ret = amd_xgbe_phy_gmii_2500_mode(phydev); +- break; +- + case SPEED_1000: +- ret = amd_xgbe_phy_gmii_mode(phydev); ++ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); + break; + + default: +@@ -1066,10 +1333,11 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) + return 0; + } + +-static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) ++static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv = phydev->priv; + u32 mmd_mask = phydev->c45_ids.devices_in_package; ++ int ret; + + if (phydev->autoneg != AUTONEG_ENABLE) + return amd_xgbe_phy_setup_forced(phydev); +@@ -1078,56 +1346,79 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) + if (!(mmd_mask & MDIO_DEVS_AN)) + return -EINVAL; + +- /* Start/Restart the auto-negotiation state machine */ +- mutex_lock(&priv->an_mutex); ++ /* Disable auto-negotiation interrupt */ ++ disable_irq(priv->an_irq); ++ ++ /* Start auto-negotiation in a supported mode */ ++ if (phydev->advertising & SUPPORTED_10000baseKR_Full) ++ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); ++ else if ((phydev->advertising & SUPPORTED_1000baseKX_Full) || ++ (phydev->advertising & SUPPORTED_2500baseX_Full)) ++ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); ++ else ++ ret = -EINVAL; ++ if (ret < 0) { ++ enable_irq(priv->an_irq); ++ return ret; ++ } ++ ++ /* Disable and stop any in progress auto-negotiation */ ++ ret = amd_xgbe_phy_disable_an(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Clear any auto-negotitation interrupts */ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ + priv->an_result = AMD_XGBE_AN_READY; +- priv->an_state = AMD_XGBE_AN_START; +- priv->kr_state = AMD_XGBE_RX_READY; +- priv->kx_state = AMD_XGBE_RX_READY; +- mutex_unlock(&priv->an_mutex); ++ priv->an_state = AMD_XGBE_AN_READY; ++ priv->kr_state = AMD_XGBE_RX_BPA; ++ priv->kx_state = AMD_XGBE_RX_BPA; + +- queue_work(priv->an_workqueue, &priv->an_work); ++ /* Re-enable auto-negotiation interrupt */ ++ enable_irq(priv->an_irq); + +- return 0; ++ /* Set up advertisement registers based on current settings */ ++ ret = amd_xgbe_an_init(phydev); ++ if (ret) ++ return ret; ++ ++ /* Enable and start auto-negotiation */ ++ return amd_xgbe_phy_restart_an(phydev); + } + +-static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) ++static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv = phydev->priv; +- enum amd_xgbe_phy_an state; ++ int ret; + + mutex_lock(&priv->an_mutex); +- state = priv->an_result; ++ ++ ret = __amd_xgbe_phy_config_aneg(phydev); ++ + mutex_unlock(&priv->an_mutex); + +- return (state == AMD_XGBE_AN_COMPLETE); ++ return ret; ++} ++ ++static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ ++ return (priv->an_result == AMD_XGBE_AN_COMPLETE); + } + + static int amd_xgbe_phy_update_link(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv = phydev->priv; +- enum amd_xgbe_phy_an state; +- unsigned int check_again, autoneg; + int ret; + + /* If we're doing auto-negotiation don't report link down */ +- mutex_lock(&priv->an_mutex); +- state = priv->an_state; +- mutex_unlock(&priv->an_mutex); +- +- if (state != AMD_XGBE_AN_READY) { ++ if (priv->an_state != AMD_XGBE_AN_READY) { + phydev->link = 1; + return 0; + } + +- /* Since the device can be in the wrong mode when a link is +- * (re-)established (cable connected after the interface is +- * up, etc.), the link status may report no link. If there +- * is no link, try switching modes and checking the status +- * again if auto negotiation is enabled. +- */ +- check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; +-again: + /* Link status is latched low, so read once to clear + * and then read again to get current state + */ +@@ -1141,25 +1432,6 @@ again: + + phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; + +- if (!phydev->link) { +- if (check_again) { +- ret = amd_xgbe_phy_switch_mode(phydev); +- if (ret < 0) +- return ret; +- check_again = 0; +- goto again; +- } +- } +- +- autoneg = (phydev->link && !priv->link) ? 1 : 0; +- priv->link = phydev->link; +- if (autoneg) { +- /* Link is (back) up, re-start auto-negotiation */ +- ret = amd_xgbe_phy_config_aneg(phydev); +- if (ret < 0) +- return ret; +- } +- + return 0; + } + +@@ -1249,6 +1521,7 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) + + static int amd_xgbe_phy_suspend(struct phy_device *phydev) + { ++ struct amd_xgbe_phy_priv *priv = phydev->priv; + int ret; + + mutex_lock(&phydev->lock); +@@ -1257,6 +1530,8 @@ static int amd_xgbe_phy_suspend(struct phy_device *phydev) + if (ret < 0) + goto unlock; + ++ priv->lpm_ctrl = ret; ++ + ret |= MDIO_CTRL1_LPOWER; + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); + +@@ -1270,69 +1545,106 @@ unlock: + + static int amd_xgbe_phy_resume(struct phy_device *phydev) + { +- int ret; ++ struct amd_xgbe_phy_priv *priv = phydev->priv; + + mutex_lock(&phydev->lock); + +- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); +- if (ret < 0) +- goto unlock; ++ priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl); + +- ret &= ~MDIO_CTRL1_LPOWER; +- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ mutex_unlock(&phydev->lock); + +- ret = 0; ++ return 0; ++} + +-unlock: +- mutex_unlock(&phydev->lock); ++static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev, ++ unsigned int type) ++{ ++ unsigned int count; ++ int i; + +- return ret; ++ for (i = 0, count = 0; i < pdev->num_resources; i++) { ++ struct resource *r = &pdev->resource[i]; ++ ++ if (type == resource_type(r)) ++ count++; ++ } ++ ++ return count; + } + + static int amd_xgbe_phy_probe(struct phy_device *phydev) + { + struct amd_xgbe_phy_priv *priv; +- struct platform_device *pdev; +- struct device *dev; +- char *wq_name; +- const __be32 *property; +- unsigned int speed_set; ++ struct platform_device *phy_pdev; ++ struct device *dev, *phy_dev; ++ unsigned int phy_resnum, phy_irqnum; + int ret; + +- if (!phydev->dev.of_node) ++ if (!phydev->bus || !phydev->bus->parent) + return -EINVAL; + +- pdev = of_find_device_by_node(phydev->dev.of_node); +- if (!pdev) +- return -EINVAL; +- dev = &pdev->dev; +- +- wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); +- if (!wq_name) { +- ret = -ENOMEM; +- goto err_pdev; +- } ++ dev = phydev->bus->parent; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) { +- ret = -ENOMEM; +- goto err_name; +- } ++ if (!priv) ++ return -ENOMEM; + +- priv->pdev = pdev; ++ priv->pdev = to_platform_device(dev); ++ priv->adev = ACPI_COMPANION(dev); + priv->dev = dev; + priv->phydev = phydev; ++ mutex_init(&priv->an_mutex); ++ INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work); ++ INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); ++ ++ if (!priv->adev || acpi_disabled) { ++ struct device_node *bus_node; ++ struct device_node *phy_node; ++ ++ bus_node = priv->dev->of_node; ++ phy_node = of_parse_phandle(bus_node, "phy-handle", 0); ++ if (!phy_node) { ++ dev_err(dev, "unable to parse phy-handle\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ phy_pdev = of_find_device_by_node(phy_node); ++ of_node_put(phy_node); ++ ++ if (!phy_pdev) { ++ dev_err(dev, "unable to obtain phy device\n"); ++ ret = -EINVAL; ++ goto err_priv; ++ } ++ ++ phy_resnum = 0; ++ phy_irqnum = 0; ++ } else { ++ /* In ACPI, the XGBE and PHY resources are the grouped ++ * together with the PHY resources at the end ++ */ ++ phy_pdev = priv->pdev; ++ phy_resnum = amd_xgbe_phy_resource_count(phy_pdev, ++ IORESOURCE_MEM) - 3; ++ phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev, ++ IORESOURCE_IRQ) - 1; ++ } ++ phy_dev = &phy_pdev->dev; + + /* Get the device mmio areas */ +- priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, ++ phy_resnum++); + priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); + if (IS_ERR(priv->rxtx_regs)) { + dev_err(dev, "rxtx ioremap failed\n"); + ret = PTR_ERR(priv->rxtx_regs); +- goto err_priv; ++ goto err_put; + } + +- priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, ++ phy_resnum++); + priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); + if (IS_ERR(priv->sir0_regs)) { + dev_err(dev, "sir0 ioremap failed\n"); +@@ -1340,7 +1652,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) + goto err_rxtx; + } + +- priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, ++ phy_resnum++); + priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); + if (IS_ERR(priv->sir1_regs)) { + dev_err(dev, "sir1 ioremap failed\n"); +@@ -1348,40 +1661,153 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) + goto err_sir0; + } + ++ /* Get the auto-negotiation interrupt */ ++ ret = platform_get_irq(phy_pdev, phy_irqnum); ++ if (ret < 0) { ++ dev_err(dev, "platform_get_irq failed\n"); ++ goto err_sir1; ++ } ++ priv->an_irq = ret; ++ + /* Get the device speed set property */ +- speed_set = 0; +- property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, +- NULL); +- if (property) +- speed_set = be32_to_cpu(*property); +- +- switch (speed_set) { +- case 0: +- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; +- break; +- case 1: +- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; ++ ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY, ++ &priv->speed_set); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_SPEEDSET_PROPERTY); ++ goto err_sir1; ++ } ++ ++ switch (priv->speed_set) { ++ case AMD_XGBE_PHY_SPEEDSET_1000_10000: ++ case AMD_XGBE_PHY_SPEEDSET_2500_10000: + break; + default: +- dev_err(dev, "invalid amd,speed-set property\n"); ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_SPEEDSET_PROPERTY); + ret = -EINVAL; + goto err_sir1; + } + +- priv->link = 1; ++ if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_BLWC_PROPERTY, ++ priv->serdes_blwc, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_BLWC_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc, ++ sizeof(priv->serdes_blwc)); ++ } + +- mutex_init(&priv->an_mutex); +- INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); +- priv->an_workqueue = create_singlethread_workqueue(wq_name); +- if (!priv->an_workqueue) { +- ret = -ENOMEM; +- goto err_sir1; ++ if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_CDR_RATE_PROPERTY, ++ priv->serdes_cdr_rate, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_CDR_RATE_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate, ++ sizeof(priv->serdes_cdr_rate)); ++ } ++ ++ if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_PQ_SKEW_PROPERTY, ++ priv->serdes_pq_skew, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_PQ_SKEW_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew, ++ sizeof(priv->serdes_pq_skew)); ++ } ++ ++ if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_TX_AMP_PROPERTY, ++ priv->serdes_tx_amp, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_TX_AMP_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp, ++ sizeof(priv->serdes_tx_amp)); ++ } ++ ++ if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_DFE_CFG_PROPERTY, ++ priv->serdes_dfe_tap_cfg, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_DFE_CFG_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_dfe_tap_cfg, ++ amd_xgbe_phy_serdes_dfe_tap_cfg, ++ sizeof(priv->serdes_dfe_tap_cfg)); + } + ++ if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) { ++ ret = device_property_read_u32_array(phy_dev, ++ XGBE_PHY_DFE_ENA_PROPERTY, ++ priv->serdes_dfe_tap_ena, ++ XGBE_PHY_SPEEDS); ++ if (ret) { ++ dev_err(dev, "invalid %s property\n", ++ XGBE_PHY_DFE_ENA_PROPERTY); ++ goto err_sir1; ++ } ++ } else { ++ memcpy(priv->serdes_dfe_tap_ena, ++ amd_xgbe_phy_serdes_dfe_tap_ena, ++ sizeof(priv->serdes_dfe_tap_ena)); ++ } ++ ++ /* Initialize supported features */ ++ phydev->supported = SUPPORTED_Autoneg; ++ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; ++ phydev->supported |= SUPPORTED_Backplane; ++ phydev->supported |= SUPPORTED_10000baseKR_Full; ++ switch (priv->speed_set) { ++ case AMD_XGBE_PHY_SPEEDSET_1000_10000: ++ phydev->supported |= SUPPORTED_1000baseKX_Full; ++ break; ++ case AMD_XGBE_PHY_SPEEDSET_2500_10000: ++ phydev->supported |= SUPPORTED_2500baseX_Full; ++ break; ++ } ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY); ++ if (ret < 0) ++ return ret; ++ priv->fec_ability = ret & XGBE_PHY_FEC_MASK; ++ if (priv->fec_ability & XGBE_PHY_FEC_ENABLE) ++ phydev->supported |= SUPPORTED_10000baseR_FEC; ++ ++ phydev->advertising = phydev->supported; ++ + phydev->priv = priv; + +- kfree(wq_name); +- of_dev_put(pdev); ++ if (!priv->adev || acpi_disabled) ++ platform_device_put(phy_pdev); + + return 0; + +@@ -1400,15 +1826,13 @@ err_rxtx: + devm_release_mem_region(dev, priv->rxtx_res->start, + resource_size(priv->rxtx_res)); + ++err_put: ++ if (!priv->adev || acpi_disabled) ++ platform_device_put(phy_pdev); ++ + err_priv: + devm_kfree(dev, priv); + +-err_name: +- kfree(wq_name); +- +-err_pdev: +- of_dev_put(pdev); +- + return ret; + } + +@@ -1417,13 +1841,12 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) + struct amd_xgbe_phy_priv *priv = phydev->priv; + struct device *dev = priv->dev; + +- /* Stop any in process auto-negotiation */ +- mutex_lock(&priv->an_mutex); +- priv->an_state = AMD_XGBE_AN_EXIT; +- mutex_unlock(&priv->an_mutex); ++ if (priv->an_irq_allocated) { ++ devm_free_irq(dev, priv->an_irq, priv); + +- flush_workqueue(priv->an_workqueue); +- destroy_workqueue(priv->an_workqueue); ++ flush_workqueue(priv->an_workqueue); ++ destroy_workqueue(priv->an_workqueue); ++ } + + /* Release resources */ + devm_iounmap(dev, priv->sir1_regs); +@@ -1452,6 +1875,7 @@ static struct phy_driver amd_xgbe_phy_driver[] = { + .phy_id_mask = XGBE_PHY_MASK, + .name = "AMD XGBE PHY", + .features = 0, ++ .flags = PHY_IS_INTERNAL, + .probe = amd_xgbe_phy_probe, + .remove = amd_xgbe_phy_remove, + .soft_reset = amd_xgbe_phy_soft_reset, +diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h +index abcafaa..6bdf476 100644 +--- a/include/linux/clocksource.h ++++ b/include/linux/clocksource.h +@@ -87,6 +87,15 @@ static inline u64 cyclecounter_cyc2ns(const struct cyclecounter *cc, + } + + /** ++ * timecounter_adjtime - Shifts the time of the clock. ++ * @delta: Desired change in nanoseconds. ++ */ ++static inline void timecounter_adjtime(struct timecounter *tc, s64 delta) ++{ ++ tc->nsec += delta; ++} ++ ++/** + * timecounter_init - initialize a time counter + * @tc: Pointer to time counter which is to be initialized/reset + * @cc: A cycle counter, ready to be used. +-- +1.9.1 + -- cgit v1.2.3-54-g00ecf