diff options
Diffstat (limited to 'drivers/net/ethernet/amd/xgbe')
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 32 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 66 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 78 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-main.c | 203 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe.h | 31 |
8 files changed, 287 insertions, 166 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 76479d04b903..2c063b60db4b 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 a50891f52197..d81fc6bd4759 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -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 4c66cd1d1e60..400757b49872 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -115,6 +115,7 @@ */ #include <linux/phy.h> +#include <linux/mdio.h> #include <linux/clk.h> #include <linux/bitrev.h> #include <linux/crc32.h> @@ -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; @@ -881,6 +891,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 @@ -1359,6 +1386,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 +1429,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 +1472,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 +1501,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 +1525,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 */ @@ -1551,7 +1579,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) /* Make sure ownership is written to the descriptor */ 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))) @@ -2107,6 +2135,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) @@ -2757,6 +2802,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_mac_address(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); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index e5ffb2ccb67d..b93d4404d975 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -225,6 +225,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 +342,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); @@ -410,17 +416,13 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) struct xgbe_channel *channel = container_of(timer, struct xgbe_channel, tx_timer); - struct xgbe_ring *ring = channel->tx_ring; 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) @@ -434,8 +436,6 @@ 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; @@ -694,7 +694,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) { @@ -929,7 +929,7 @@ 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; @@ -952,9 +952,8 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) xgbe_free_tx_data(pdata); xgbe_free_rx_data(pdata); - /* Issue software reset to device if requested */ - if (reset) - hw_if->exit(pdata); + /* Issue software reset to device */ + hw_if->exit(pdata); xgbe_start(pdata); @@ -969,7 +968,7 @@ static void xgbe_restart(struct work_struct *work) rtnl_lock(); - xgbe_restart_dev(pdata, 1); + xgbe_restart_dev(pdata); rtnl_unlock(); } @@ -1167,8 +1166,8 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) { - if (vlan_tx_tag_present(skb)) - packet->vlan_ctag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + packet->vlan_ctag = skb_vlan_tag_get(skb); } static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) @@ -1249,9 +1248,9 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, CSUM_ENABLE, 1); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* VLAN requires an extra descriptor if tag is different */ - if (vlan_tx_tag_get(skb) != ring->tx.cur_vlan_ctag) + if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag) /* We can share with the TSO context descriptor */ if (!context_desc) { context_desc = 1; @@ -1448,7 +1447,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 +1458,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 +1504,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; } @@ -1589,7 +1581,7 @@ 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"); @@ -1778,15 +1770,28 @@ 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(rdata); + + ring->dirty++; + } /* 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)); } @@ -1826,7 +1831,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 +1842,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); @@ -1870,7 +1872,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 +1884,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 +1935,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 +1943,6 @@ read_again: received++; ring->cur++; - ring->dirty++; incomplete = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index dbd3850b8b0a..32dd65137051 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -123,7 +123,10 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_net.h> +#include <linux/of_address.h> #include <linux/clk.h> +#include <linux/property.h> +#include <linux/acpi.h> #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,16 @@ 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; + /* 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"); + goto err_io; + } + /* Get the device interrupt */ ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "platform_get_irq 0 failed\n"); @@ -279,6 +393,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,23 +406,6 @@ 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); - - /* 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; - goto err_io; - } - /* Set default configuration data */ xgbe_default_config(pdata); @@ -491,18 +589,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 363b210560f3..59e267f3f1b7 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 a1bf9d1cdae1..f326178ef376 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -171,15 +171,9 @@ 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; @@ -239,7 +233,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 +254,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 f9ec762ac3f0..13e8f95c077c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -124,7 +124,7 @@ #include <linux/if_vlan.h> #include <linux/bitops.h> #include <linux/ptp_clock_kernel.h> -#include <linux/clocksource.h> +#include <linux/timecounter.h> #include <linux/net_tstamp.h> #include <net/dcbnl.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 @@ -361,8 +369,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 +384,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; @@ -596,7 +598,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 *); @@ -650,8 +653,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 +679,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; @@ -739,6 +747,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 +757,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; |