mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-08 13:44:01 +08:00
Merge branch 'amd-xgbe'
Tom Lendacky says: ==================== amd-xgbe: AMD XGBE driver updates 2015-01-16 The following series of patches includes functional updates to the driver as well as some trivial changes. - Fix checks/warnings from checkpatch in the amd-xgbe driver - Fix checks/warnings from checkpatch in the amd-xgbe-phy driver - Add a check to be sure that the amd-xgbe driver is using the amd-xgbe-phy driver - Use a saved control register value when bringing the PCS out of suspend - Clear all device state during a device restart - Simplify the Rx descriptor ring tracking - Remove the need for Tx path spinlocks - Update the auto-negotiation logic to make use of the auto-negotiation interrupt - Properly support/advertise the FEC capability of the device - Use the proper page registers during auto-negotiation extended next page exchange - Add ACPI support to the amd-xgbe and amd-xgbe-phy drivers - Allow platform specific phy settings to be supplied by UEFI This patch series is based on net-next. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
93d62ef97d
@ -7,17 +7,38 @@ Required properties:
|
||||
- SerDes Rx/Tx registers
|
||||
- SerDes integration registers (1/2)
|
||||
- SerDes integration registers (2/2)
|
||||
- interrupt-parent: Should be the phandle for the interrupt controller
|
||||
that services interrupts for this device
|
||||
- interrupts: Should contain the amd-xgbe-phy interrupt.
|
||||
|
||||
Optional properties:
|
||||
- amd,speed-set: Speed capabilities of the device
|
||||
0 - 1GbE and 10GbE (default)
|
||||
1 - 2.5GbE and 10GbE
|
||||
|
||||
The following optional properties are represented by an array with each
|
||||
value corresponding to a particular speed. The first array value represents
|
||||
the setting for the 1GbE speed, the second value for the 2.5GbE speed and
|
||||
the third value for the 10GbE speed. All three values are required if the
|
||||
property is used.
|
||||
- amd,serdes-blwc: Baseline wandering correction enablement
|
||||
0 - Off
|
||||
1 - On
|
||||
- amd,serdes-cdr-rate: CDR rate speed selection
|
||||
- amd,serdes-pq-skew: PQ (data sampling) skew
|
||||
- amd,serdes-tx-amp: TX amplitude boost
|
||||
|
||||
Example:
|
||||
xgbe_phy@e1240800 {
|
||||
compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45";
|
||||
reg = <0 0xe1240800 0 0x00400>,
|
||||
<0 0xe1250000 0 0x00060>,
|
||||
<0 0xe1250080 0 0x00004>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 323 4>;
|
||||
amd,speed-set = <0>;
|
||||
amd,serdes-blwc = <1>, <1>, <0>;
|
||||
amd,serdes-cdr-rate = <2>, <2>, <7>;
|
||||
amd,serdes-pq-skew = <10>, <10>, <30>;
|
||||
amd,serdes-tx-amp = <15>, <15>, <10>;
|
||||
};
|
||||
|
@ -179,7 +179,7 @@ config SUNLANCE
|
||||
|
||||
config AMD_XGBE
|
||||
tristate "AMD 10GbE Ethernet driver"
|
||||
depends on OF_NET && HAS_IOMEM
|
||||
depends on (OF_NET || ACPI) && HAS_IOMEM
|
||||
select PHYLIB
|
||||
select AMD_XGBE_PHY
|
||||
select BITREVERSE
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
@ -410,17 +415,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 +435,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;
|
||||
@ -692,7 +691,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) {
|
||||
@ -927,7 +926,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;
|
||||
@ -950,9 +949,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);
|
||||
|
||||
@ -967,7 +965,7 @@ static void xgbe_restart(struct work_struct *work)
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
xgbe_restart_dev(pdata, 1);
|
||||
xgbe_restart_dev(pdata);
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
@ -1446,7 +1444,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);
|
||||
@ -1458,8 +1455,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);
|
||||
@ -1506,10 +1501,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;
|
||||
}
|
||||
|
||||
@ -1587,7 +1578,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");
|
||||
|
||||
@ -1776,15 +1767,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));
|
||||
}
|
||||
@ -1824,7 +1828,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;
|
||||
|
||||
@ -1836,8 +1839,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);
|
||||
@ -1868,7 +1869,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);
|
||||
|
||||
@ -1880,9 +1881,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;
|
||||
}
|
||||
|
||||
@ -1934,7 +1932,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))
|
||||
@ -1942,7 +1940,6 @@ read_again:
|
||||
|
||||
received++;
|
||||
ring->cur++;
|
||||
ring->dirty++;
|
||||
|
||||
incomplete = XGMAC_GET_BITS(packet->attributes,
|
||||
RX_PACKET_ATTRIBUTES,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -233,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;
|
||||
@ -254,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;
|
||||
|
@ -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;
|
||||
|
@ -26,7 +26,7 @@ config AMD_PHY
|
||||
|
||||
config AMD_XGBE_PHY
|
||||
tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
|
||||
depends on OF && HAS_IOMEM
|
||||
depends on (OF || ACPI) && HAS_IOMEM
|
||||
---help---
|
||||
Currently supports the AMD 10GbE PHY
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user