Commit 01d300c5 authored by David S. Miller's avatar David S. Miller

Merge branch 'amd-xgbe-next'

Tom Lendacky says:

====================
amd-xgbe: AMD XGBE driver updates 2017-08-17

The following updates are included in this driver update series:

- Set the MDIO mode to clause 45 for the 10GBase-T configuration
- Set the MII control width to 8-bits for speeds less than 1Gbps
- Fix an issue to related to module removal when the devices are up
- Fix ethtool statistics related to packet counting of TSO packets
- Add support for device renaming
- Add additional dynamic debug output for the PCS window calculation
- Optimize reading of DMA channel interrupt enablement register
- Add additional dynamic debug output about the hardware features
- Add per queue Tx and Rx ethtool statistics
- Add a macro to clear ethtool_link_ksettings modes
- Convert the driver to use the ethtool_link_ksettings
- Add support for VXLAN offload capabilities
- Add additional ethtool statistics related to VXLAN

This patch series is based on net-next.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1547f538 3010608d
...@@ -298,6 +298,7 @@ ...@@ -298,6 +298,7 @@
#define MAC_RWKPFR 0x00c4 #define MAC_RWKPFR 0x00c4
#define MAC_LPICSR 0x00d0 #define MAC_LPICSR 0x00d0
#define MAC_LPITCR 0x00d4 #define MAC_LPITCR 0x00d4
#define MAC_TIR 0x00e0
#define MAC_VR 0x0110 #define MAC_VR 0x0110
#define MAC_DR 0x0114 #define MAC_DR 0x0114
#define MAC_HWF0R 0x011c #define MAC_HWF0R 0x011c
...@@ -364,6 +365,8 @@ ...@@ -364,6 +365,8 @@
#define MAC_HWF0R_TXCOESEL_WIDTH 1 #define MAC_HWF0R_TXCOESEL_WIDTH 1
#define MAC_HWF0R_VLHASH_INDEX 4 #define MAC_HWF0R_VLHASH_INDEX 4
#define MAC_HWF0R_VLHASH_WIDTH 1 #define MAC_HWF0R_VLHASH_WIDTH 1
#define MAC_HWF0R_VXN_INDEX 29
#define MAC_HWF0R_VXN_WIDTH 1
#define MAC_HWF1R_ADDR64_INDEX 14 #define MAC_HWF1R_ADDR64_INDEX 14
#define MAC_HWF1R_ADDR64_WIDTH 2 #define MAC_HWF1R_ADDR64_WIDTH 2
#define MAC_HWF1R_ADVTHWORD_INDEX 13 #define MAC_HWF1R_ADVTHWORD_INDEX 13
...@@ -448,6 +451,8 @@ ...@@ -448,6 +451,8 @@
#define MAC_PFR_PR_WIDTH 1 #define MAC_PFR_PR_WIDTH 1
#define MAC_PFR_VTFE_INDEX 16 #define MAC_PFR_VTFE_INDEX 16
#define MAC_PFR_VTFE_WIDTH 1 #define MAC_PFR_VTFE_WIDTH 1
#define MAC_PFR_VUCC_INDEX 22
#define MAC_PFR_VUCC_WIDTH 1
#define MAC_PMTCSR_MGKPKTEN_INDEX 1 #define MAC_PMTCSR_MGKPKTEN_INDEX 1
#define MAC_PMTCSR_MGKPKTEN_WIDTH 1 #define MAC_PMTCSR_MGKPKTEN_WIDTH 1
#define MAC_PMTCSR_PWRDWN_INDEX 0 #define MAC_PMTCSR_PWRDWN_INDEX 0
...@@ -510,6 +515,12 @@ ...@@ -510,6 +515,12 @@
#define MAC_TCR_SS_WIDTH 2 #define MAC_TCR_SS_WIDTH 2
#define MAC_TCR_TE_INDEX 0 #define MAC_TCR_TE_INDEX 0
#define MAC_TCR_TE_WIDTH 1 #define MAC_TCR_TE_WIDTH 1
#define MAC_TCR_VNE_INDEX 24
#define MAC_TCR_VNE_WIDTH 1
#define MAC_TCR_VNM_INDEX 25
#define MAC_TCR_VNM_WIDTH 1
#define MAC_TIR_TNID_INDEX 0
#define MAC_TIR_TNID_WIDTH 16
#define MAC_TSCR_AV8021ASMEN_INDEX 28 #define MAC_TSCR_AV8021ASMEN_INDEX 28
#define MAC_TSCR_AV8021ASMEN_WIDTH 1 #define MAC_TSCR_AV8021ASMEN_WIDTH 1
#define MAC_TSCR_SNAPTYPSEL_INDEX 16 #define MAC_TSCR_SNAPTYPSEL_INDEX 16
...@@ -1153,11 +1164,17 @@ ...@@ -1153,11 +1164,17 @@
#define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH 1 #define RX_PACKET_ATTRIBUTES_RSS_HASH_WIDTH 1
#define RX_PACKET_ATTRIBUTES_FIRST_INDEX 7 #define RX_PACKET_ATTRIBUTES_FIRST_INDEX 7
#define RX_PACKET_ATTRIBUTES_FIRST_WIDTH 1 #define RX_PACKET_ATTRIBUTES_FIRST_WIDTH 1
#define RX_PACKET_ATTRIBUTES_TNP_INDEX 8
#define RX_PACKET_ATTRIBUTES_TNP_WIDTH 1
#define RX_PACKET_ATTRIBUTES_TNPCSUM_DONE_INDEX 9
#define RX_PACKET_ATTRIBUTES_TNPCSUM_DONE_WIDTH 1
#define RX_NORMAL_DESC0_OVT_INDEX 0 #define RX_NORMAL_DESC0_OVT_INDEX 0
#define RX_NORMAL_DESC0_OVT_WIDTH 16 #define RX_NORMAL_DESC0_OVT_WIDTH 16
#define RX_NORMAL_DESC2_HL_INDEX 0 #define RX_NORMAL_DESC2_HL_INDEX 0
#define RX_NORMAL_DESC2_HL_WIDTH 10 #define RX_NORMAL_DESC2_HL_WIDTH 10
#define RX_NORMAL_DESC2_TNP_INDEX 11
#define RX_NORMAL_DESC2_TNP_WIDTH 1
#define RX_NORMAL_DESC3_CDA_INDEX 27 #define RX_NORMAL_DESC3_CDA_INDEX 27
#define RX_NORMAL_DESC3_CDA_WIDTH 1 #define RX_NORMAL_DESC3_CDA_WIDTH 1
#define RX_NORMAL_DESC3_CTXT_INDEX 30 #define RX_NORMAL_DESC3_CTXT_INDEX 30
...@@ -1184,9 +1201,11 @@ ...@@ -1184,9 +1201,11 @@
#define RX_DESC3_L34T_IPV4_TCP 1 #define RX_DESC3_L34T_IPV4_TCP 1
#define RX_DESC3_L34T_IPV4_UDP 2 #define RX_DESC3_L34T_IPV4_UDP 2
#define RX_DESC3_L34T_IPV4_ICMP 3 #define RX_DESC3_L34T_IPV4_ICMP 3
#define RX_DESC3_L34T_IPV4_UNKNOWN 7
#define RX_DESC3_L34T_IPV6_TCP 9 #define RX_DESC3_L34T_IPV6_TCP 9
#define RX_DESC3_L34T_IPV6_UDP 10 #define RX_DESC3_L34T_IPV6_UDP 10
#define RX_DESC3_L34T_IPV6_ICMP 11 #define RX_DESC3_L34T_IPV6_ICMP 11
#define RX_DESC3_L34T_IPV6_UNKNOWN 15
#define RX_CONTEXT_DESC3_TSA_INDEX 4 #define RX_CONTEXT_DESC3_TSA_INDEX 4
#define RX_CONTEXT_DESC3_TSA_WIDTH 1 #define RX_CONTEXT_DESC3_TSA_WIDTH 1
...@@ -1201,6 +1220,8 @@ ...@@ -1201,6 +1220,8 @@
#define TX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1 #define TX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1
#define TX_PACKET_ATTRIBUTES_PTP_INDEX 3 #define TX_PACKET_ATTRIBUTES_PTP_INDEX 3
#define TX_PACKET_ATTRIBUTES_PTP_WIDTH 1 #define TX_PACKET_ATTRIBUTES_PTP_WIDTH 1
#define TX_PACKET_ATTRIBUTES_VXLAN_INDEX 4
#define TX_PACKET_ATTRIBUTES_VXLAN_WIDTH 1
#define TX_CONTEXT_DESC2_MSS_INDEX 0 #define TX_CONTEXT_DESC2_MSS_INDEX 0
#define TX_CONTEXT_DESC2_MSS_WIDTH 15 #define TX_CONTEXT_DESC2_MSS_WIDTH 15
...@@ -1241,8 +1262,11 @@ ...@@ -1241,8 +1262,11 @@
#define TX_NORMAL_DESC3_TCPPL_WIDTH 18 #define TX_NORMAL_DESC3_TCPPL_WIDTH 18
#define TX_NORMAL_DESC3_TSE_INDEX 18 #define TX_NORMAL_DESC3_TSE_INDEX 18
#define TX_NORMAL_DESC3_TSE_WIDTH 1 #define TX_NORMAL_DESC3_TSE_WIDTH 1
#define TX_NORMAL_DESC3_VNP_INDEX 23
#define TX_NORMAL_DESC3_VNP_WIDTH 3
#define TX_NORMAL_DESC2_VLAN_INSERT 0x2 #define TX_NORMAL_DESC2_VLAN_INSERT 0x2
#define TX_NORMAL_DESC3_VXLAN_PACKET 0x3
/* MDIO undefined or vendor specific registers */ /* MDIO undefined or vendor specific registers */
#ifndef MDIO_PMA_10GBR_PMD_CTRL #ifndef MDIO_PMA_10GBR_PMD_CTRL
...@@ -1339,6 +1363,7 @@ ...@@ -1339,6 +1363,7 @@
#define XGBE_AN_CL37_PCS_MODE_BASEX 0x00 #define XGBE_AN_CL37_PCS_MODE_BASEX 0x00
#define XGBE_AN_CL37_PCS_MODE_SGMII 0x04 #define XGBE_AN_CL37_PCS_MODE_SGMII 0x04
#define XGBE_AN_CL37_TX_CONFIG_MASK 0x08 #define XGBE_AN_CL37_TX_CONFIG_MASK 0x08
#define XGBE_AN_CL37_MII_CTRL_8BIT 0x0100
/* Bit setting and getting macros /* Bit setting and getting macros
* The get macro will extract the current bit field value from within * The get macro will extract the current bit field value from within
......
...@@ -527,3 +527,28 @@ void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) ...@@ -527,3 +527,28 @@ void xgbe_debugfs_exit(struct xgbe_prv_data *pdata)
debugfs_remove_recursive(pdata->xgbe_debugfs); debugfs_remove_recursive(pdata->xgbe_debugfs);
pdata->xgbe_debugfs = NULL; pdata->xgbe_debugfs = NULL;
} }
void xgbe_debugfs_rename(struct xgbe_prv_data *pdata)
{
struct dentry *pfile;
char *buf;
if (!pdata->xgbe_debugfs)
return;
buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
if (!buf)
return;
if (!strcmp(pdata->xgbe_debugfs->d_name.name, buf))
goto out;
pfile = debugfs_rename(pdata->xgbe_debugfs->d_parent,
pdata->xgbe_debugfs,
pdata->xgbe_debugfs->d_parent, buf);
if (!pfile)
netdev_err(pdata->netdev, "debugfs_rename failed\n");
out:
kfree(buf);
}
...@@ -479,6 +479,50 @@ static bool xgbe_is_pfc_queue(struct xgbe_prv_data *pdata, ...@@ -479,6 +479,50 @@ static bool xgbe_is_pfc_queue(struct xgbe_prv_data *pdata,
return false; return false;
} }
static void xgbe_set_vxlan_id(struct xgbe_prv_data *pdata)
{
/* Program the VXLAN port */
XGMAC_IOWRITE_BITS(pdata, MAC_TIR, TNID, pdata->vxlan_port);
netif_dbg(pdata, drv, pdata->netdev, "VXLAN tunnel id set to %hx\n",
pdata->vxlan_port);
}
static void xgbe_enable_vxlan(struct xgbe_prv_data *pdata)
{
if (!pdata->hw_feat.vxn)
return;
/* Program the VXLAN port */
xgbe_set_vxlan_id(pdata);
/* Allow for IPv6/UDP zero-checksum VXLAN packets */
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VUCC, 1);
/* Enable VXLAN tunneling mode */
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNM, 0);
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNE, 1);
netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration enabled\n");
}
static void xgbe_disable_vxlan(struct xgbe_prv_data *pdata)
{
if (!pdata->hw_feat.vxn)
return;
/* Disable tunneling mode */
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, VNE, 0);
/* Clear IPv6/UDP zero-checksum VXLAN packets setting */
XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VUCC, 0);
/* Clear the VXLAN port */
XGMAC_IOWRITE_BITS(pdata, MAC_TIR, TNID, 0);
netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n");
}
static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata) static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
{ {
unsigned int max_q_count, q_count; unsigned int max_q_count, q_count;
...@@ -605,7 +649,6 @@ static void xgbe_config_flow_control(struct xgbe_prv_data *pdata) ...@@ -605,7 +649,6 @@ static void xgbe_config_flow_control(struct xgbe_prv_data *pdata)
static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
{ {
struct xgbe_channel *channel; struct xgbe_channel *channel;
unsigned int dma_ch_isr, dma_ch_ier;
unsigned int i; unsigned int i;
/* Set the interrupt mode if supported */ /* Set the interrupt mode if supported */
...@@ -617,20 +660,20 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) ...@@ -617,20 +660,20 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
channel = pdata->channel[i]; channel = pdata->channel[i];
/* Clear all the interrupts which are set */ /* Clear all the interrupts which are set */
dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); XGMAC_DMA_IOWRITE(channel, DMA_CH_SR,
XGMAC_DMA_IOWRITE(channel, DMA_CH_SR, dma_ch_isr); XGMAC_DMA_IOREAD(channel, DMA_CH_SR));
/* Clear all interrupt enable bits */ /* Clear all interrupt enable bits */
dma_ch_ier = 0; channel->curr_ier = 0;
/* Enable following interrupts /* Enable following interrupts
* NIE - Normal Interrupt Summary Enable * NIE - Normal Interrupt Summary Enable
* AIE - Abnormal Interrupt Summary Enable * AIE - Abnormal Interrupt Summary Enable
* FBEE - Fatal Bus Error Enable * FBEE - Fatal Bus Error Enable
*/ */
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, NIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, NIE, 1);
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, AIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, AIE, 1);
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 1);
if (channel->tx_ring) { if (channel->tx_ring) {
/* Enable the following Tx interrupts /* Enable the following Tx interrupts
...@@ -639,7 +682,8 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) ...@@ -639,7 +682,8 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
* mode) * mode)
*/ */
if (!pdata->per_channel_irq || pdata->channel_irq_mode) if (!pdata->per_channel_irq || pdata->channel_irq_mode)
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); XGMAC_SET_BITS(channel->curr_ier,
DMA_CH_IER, TIE, 1);
} }
if (channel->rx_ring) { if (channel->rx_ring) {
/* Enable following Rx interrupts /* Enable following Rx interrupts
...@@ -648,12 +692,13 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) ...@@ -648,12 +692,13 @@ static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata)
* per channel interrupts in edge triggered * per channel interrupts in edge triggered
* mode) * mode)
*/ */
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 1);
if (!pdata->per_channel_irq || pdata->channel_irq_mode) if (!pdata->per_channel_irq || pdata->channel_irq_mode)
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); XGMAC_SET_BITS(channel->curr_ier,
DMA_CH_IER, RIE, 1);
} }
XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
} }
} }
...@@ -1608,7 +1653,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1608,7 +1653,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
struct xgbe_ring_data *rdata; struct xgbe_ring_data *rdata;
struct xgbe_ring_desc *rdesc; struct xgbe_ring_desc *rdesc;
struct xgbe_packet_data *packet = &ring->packet_data; struct xgbe_packet_data *packet = &ring->packet_data;
unsigned int csum, tso, vlan; unsigned int tx_packets, tx_bytes;
unsigned int csum, tso, vlan, vxlan;
unsigned int tso_context, vlan_context; unsigned int tso_context, vlan_context;
unsigned int tx_set_ic; unsigned int tx_set_ic;
int start_index = ring->cur; int start_index = ring->cur;
...@@ -1617,12 +1663,17 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1617,12 +1663,17 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
DBGPR("-->xgbe_dev_xmit\n"); DBGPR("-->xgbe_dev_xmit\n");
tx_packets = packet->tx_packets;
tx_bytes = packet->tx_bytes;
csum = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, csum = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
CSUM_ENABLE); CSUM_ENABLE);
tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
TSO_ENABLE); TSO_ENABLE);
vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
VLAN_CTAG); VLAN_CTAG);
vxlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
VXLAN);
if (tso && (packet->mss != ring->tx.cur_mss)) if (tso && (packet->mss != ring->tx.cur_mss))
tso_context = 1; tso_context = 1;
...@@ -1644,13 +1695,12 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1644,13 +1695,12 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
* - Addition of Tx frame count to the frame count since the * - Addition of Tx frame count to the frame count since the
* last interrupt was set does not exceed the frame count setting * last interrupt was set does not exceed the frame count setting
*/ */
ring->coalesce_count += packet->tx_packets; ring->coalesce_count += tx_packets;
if (!pdata->tx_frames) if (!pdata->tx_frames)
tx_set_ic = 0; tx_set_ic = 0;
else if (packet->tx_packets > pdata->tx_frames) else if (tx_packets > pdata->tx_frames)
tx_set_ic = 1; tx_set_ic = 1;
else if ((ring->coalesce_count % pdata->tx_frames) < else if ((ring->coalesce_count % pdata->tx_frames) < tx_packets)
packet->tx_packets)
tx_set_ic = 1; tx_set_ic = 1;
else else
tx_set_ic = 0; tx_set_ic = 0;
...@@ -1740,7 +1790,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1740,7 +1790,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPHDRLEN, XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPHDRLEN,
packet->tcp_header_len / 4); packet->tcp_header_len / 4);
pdata->ext_stats.tx_tso_packets++; pdata->ext_stats.tx_tso_packets += tx_packets;
} else { } else {
/* Enable CRC and Pad Insertion */ /* Enable CRC and Pad Insertion */
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CPC, 0); XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CPC, 0);
...@@ -1755,6 +1805,13 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1755,6 +1805,13 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
packet->length); packet->length);
} }
if (vxlan) {
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, VNP,
TX_NORMAL_DESC3_VXLAN_PACKET);
pdata->ext_stats.tx_vxlan_packets += packet->tx_packets;
}
for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) { for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) {
cur_index++; cur_index++;
rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdata = XGBE_GET_DESC_DATA(ring, cur_index);
...@@ -1788,8 +1845,11 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ...@@ -1788,8 +1845,11 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1); XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1);
/* Save the Tx info to report back during cleanup */ /* Save the Tx info to report back during cleanup */
rdata->tx.packets = packet->tx_packets; rdata->tx.packets = tx_packets;
rdata->tx.bytes = packet->tx_bytes; rdata->tx.bytes = tx_bytes;
pdata->ext_stats.txq_packets[channel->queue_index] += tx_packets;
pdata->ext_stats.txq_bytes[channel->queue_index] += tx_bytes;
/* In case the Tx DMA engine is running, make sure everything /* In case the Tx DMA engine is running, make sure everything
* is written to the descriptor(s) before setting the OWN bit * is written to the descriptor(s) before setting the OWN bit
...@@ -1913,9 +1973,28 @@ static int xgbe_dev_read(struct xgbe_channel *channel) ...@@ -1913,9 +1973,28 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL); rdata->rx.len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL);
/* Set checksum done indicator as appropriate */ /* Set checksum done indicator as appropriate */
if (netdev->features & NETIF_F_RXCSUM) if (netdev->features & NETIF_F_RXCSUM) {
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
CSUM_DONE, 1); CSUM_DONE, 1);
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
TNPCSUM_DONE, 1);
}
/* Set the tunneled packet indicator */
if (XGMAC_GET_BITS_LE(rdesc->desc2, RX_NORMAL_DESC2, TNP)) {
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
TNP, 1);
pdata->ext_stats.rx_vxlan_packets++;
l34t = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, L34T);
switch (l34t) {
case RX_DESC3_L34T_IPV4_UNKNOWN:
case RX_DESC3_L34T_IPV6_UNKNOWN:
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
TNPCSUM_DONE, 0);
break;
}
}
/* Check for errors (only valid in last descriptor) */ /* Check for errors (only valid in last descriptor) */
err = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ES); err = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ES);
...@@ -1935,14 +2014,30 @@ static int xgbe_dev_read(struct xgbe_channel *channel) ...@@ -1935,14 +2014,30 @@ static int xgbe_dev_read(struct xgbe_channel *channel)
packet->vlan_ctag); packet->vlan_ctag);
} }
} else { } else {
if ((etlt == 0x05) || (etlt == 0x06)) unsigned int tnp = XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES, TNP);
if ((etlt == 0x05) || (etlt == 0x06)) {
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
CSUM_DONE, 0); CSUM_DONE, 0);
else XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
TNPCSUM_DONE, 0);
pdata->ext_stats.rx_csum_errors++;
} else if (tnp && ((etlt == 0x09) || (etlt == 0x0a))) {
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
CSUM_DONE, 0);
XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES,
TNPCSUM_DONE, 0);
pdata->ext_stats.rx_vxlan_csum_errors++;
} else {
XGMAC_SET_BITS(packet->errors, RX_PACKET_ERRORS, XGMAC_SET_BITS(packet->errors, RX_PACKET_ERRORS,
FRAME, 1); FRAME, 1);
}
} }
pdata->ext_stats.rxq_packets[channel->queue_index]++;
pdata->ext_stats.rxq_bytes[channel->queue_index] += rdata->rx.len;
DBGPR("<--xgbe_dev_read: %s - descriptor=%u (cur=%d)\n", channel->name, DBGPR("<--xgbe_dev_read: %s - descriptor=%u (cur=%d)\n", channel->name,
ring->cur & (ring->rdesc_count - 1), ring->cur); ring->cur & (ring->rdesc_count - 1), ring->cur);
...@@ -1964,44 +2059,40 @@ static int xgbe_is_last_desc(struct xgbe_ring_desc *rdesc) ...@@ -1964,44 +2059,40 @@ static int xgbe_is_last_desc(struct xgbe_ring_desc *rdesc)
static int xgbe_enable_int(struct xgbe_channel *channel, static int xgbe_enable_int(struct xgbe_channel *channel,
enum xgbe_int int_id) enum xgbe_int int_id)
{ {
unsigned int dma_ch_ier;
dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER);
switch (int_id) { switch (int_id) {
case XGMAC_INT_DMA_CH_SR_TI: case XGMAC_INT_DMA_CH_SR_TI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_TPS: case XGMAC_INT_DMA_CH_SR_TPS:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TXSE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_TBU: case XGMAC_INT_DMA_CH_SR_TBU:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TBUE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_RI: case XGMAC_INT_DMA_CH_SR_RI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_RBU: case XGMAC_INT_DMA_CH_SR_RBU:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_RPS: case XGMAC_INT_DMA_CH_SR_RPS:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RSE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_TI_RI: case XGMAC_INT_DMA_CH_SR_TI_RI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 1);
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 1);
break; break;
case XGMAC_INT_DMA_CH_SR_FBE: case XGMAC_INT_DMA_CH_SR_FBE:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 1);
break; break;
case XGMAC_INT_DMA_ALL: case XGMAC_INT_DMA_ALL:
dma_ch_ier |= channel->saved_ier; channel->curr_ier |= channel->saved_ier;
break; break;
default: default:
return -1; return -1;
} }
XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
return 0; return 0;
} }
...@@ -2009,45 +2100,41 @@ static int xgbe_enable_int(struct xgbe_channel *channel, ...@@ -2009,45 +2100,41 @@ static int xgbe_enable_int(struct xgbe_channel *channel,
static int xgbe_disable_int(struct xgbe_channel *channel, static int xgbe_disable_int(struct xgbe_channel *channel,
enum xgbe_int int_id) enum xgbe_int int_id)
{ {
unsigned int dma_ch_ier;
dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER);
switch (int_id) { switch (int_id) {
case XGMAC_INT_DMA_CH_SR_TI: case XGMAC_INT_DMA_CH_SR_TI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_TPS: case XGMAC_INT_DMA_CH_SR_TPS:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TXSE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_TBU: case XGMAC_INT_DMA_CH_SR_TBU:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TBUE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_RI: case XGMAC_INT_DMA_CH_SR_RI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_RBU: case XGMAC_INT_DMA_CH_SR_RBU:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RBUE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_RPS: case XGMAC_INT_DMA_CH_SR_RPS:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RSE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_TI_RI: case XGMAC_INT_DMA_CH_SR_TI_RI:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, TIE, 0);
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, RIE, 0);
break; break;
case XGMAC_INT_DMA_CH_SR_FBE: case XGMAC_INT_DMA_CH_SR_FBE:
XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 0); XGMAC_SET_BITS(channel->curr_ier, DMA_CH_IER, FBEE, 0);
break; break;
case XGMAC_INT_DMA_ALL: case XGMAC_INT_DMA_ALL:
channel->saved_ier = dma_ch_ier & XGBE_DMA_INTERRUPT_MASK; channel->saved_ier = channel->curr_ier;
dma_ch_ier &= ~XGBE_DMA_INTERRUPT_MASK; channel->curr_ier = 0;
break; break;
default: default:
return -1; return -1;
} }
XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, channel->curr_ier);
return 0; return 0;
} }
...@@ -3534,5 +3621,10 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) ...@@ -3534,5 +3621,10 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
hw_if->disable_ecc_ded = xgbe_disable_ecc_ded; hw_if->disable_ecc_ded = xgbe_disable_ecc_ded;
hw_if->disable_ecc_sec = xgbe_disable_ecc_sec; hw_if->disable_ecc_sec = xgbe_disable_ecc_sec;
/* For VXLAN */
hw_if->enable_vxlan = xgbe_enable_vxlan;
hw_if->disable_vxlan = xgbe_disable_vxlan;
hw_if->set_vxlan_id = xgbe_set_vxlan_id;
DBGPR("<--xgbe_init_function_ptrs\n"); DBGPR("<--xgbe_init_function_ptrs\n");
} }
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <net/vxlan.h>
#include "xgbe.h" #include "xgbe.h"
#include "xgbe-common.h" #include "xgbe-common.h"
...@@ -732,8 +733,6 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) ...@@ -732,8 +733,6 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
unsigned int mac_hfr0, mac_hfr1, mac_hfr2; unsigned int mac_hfr0, mac_hfr1, mac_hfr2;
struct xgbe_hw_features *hw_feat = &pdata->hw_feat; struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
DBGPR("-->xgbe_get_all_hw_features\n");
mac_hfr0 = XGMAC_IOREAD(pdata, MAC_HWF0R); mac_hfr0 = XGMAC_IOREAD(pdata, MAC_HWF0R);
mac_hfr1 = XGMAC_IOREAD(pdata, MAC_HWF1R); mac_hfr1 = XGMAC_IOREAD(pdata, MAC_HWF1R);
mac_hfr2 = XGMAC_IOREAD(pdata, MAC_HWF2R); mac_hfr2 = XGMAC_IOREAD(pdata, MAC_HWF2R);
...@@ -758,6 +757,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) ...@@ -758,6 +757,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
ADDMACADRSEL); ADDMACADRSEL);
hw_feat->ts_src = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSTSSEL); hw_feat->ts_src = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSTSSEL);
hw_feat->sa_vlan_ins = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SAVLANINS); hw_feat->sa_vlan_ins = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SAVLANINS);
hw_feat->vxn = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VXN);
/* Hardware feature register 1 */ /* Hardware feature register 1 */
hw_feat->rx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, hw_feat->rx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
...@@ -828,7 +828,193 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) ...@@ -828,7 +828,193 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
hw_feat->rx_fifo_size = 1 << (hw_feat->rx_fifo_size + 7); hw_feat->rx_fifo_size = 1 << (hw_feat->rx_fifo_size + 7);
hw_feat->tx_fifo_size = 1 << (hw_feat->tx_fifo_size + 7); hw_feat->tx_fifo_size = 1 << (hw_feat->tx_fifo_size + 7);
DBGPR("<--xgbe_get_all_hw_features\n"); if (netif_msg_probe(pdata)) {
dev_dbg(pdata->dev, "Hardware features:\n");
/* Hardware feature register 0 */
dev_dbg(pdata->dev, " 1GbE support : %s\n",
hw_feat->gmii ? "yes" : "no");
dev_dbg(pdata->dev, " VLAN hash filter : %s\n",
hw_feat->vlhash ? "yes" : "no");
dev_dbg(pdata->dev, " MDIO interface : %s\n",
hw_feat->sma ? "yes" : "no");
dev_dbg(pdata->dev, " Wake-up packet support : %s\n",
hw_feat->rwk ? "yes" : "no");
dev_dbg(pdata->dev, " Magic packet support : %s\n",
hw_feat->mgk ? "yes" : "no");
dev_dbg(pdata->dev, " Management counters : %s\n",
hw_feat->mmc ? "yes" : "no");
dev_dbg(pdata->dev, " ARP offload : %s\n",
hw_feat->aoe ? "yes" : "no");
dev_dbg(pdata->dev, " IEEE 1588-2008 Timestamp : %s\n",
hw_feat->ts ? "yes" : "no");
dev_dbg(pdata->dev, " Energy Efficient Ethernet : %s\n",
hw_feat->eee ? "yes" : "no");
dev_dbg(pdata->dev, " TX checksum offload : %s\n",
hw_feat->tx_coe ? "yes" : "no");
dev_dbg(pdata->dev, " RX checksum offload : %s\n",
hw_feat->rx_coe ? "yes" : "no");
dev_dbg(pdata->dev, " Additional MAC addresses : %u\n",
hw_feat->addn_mac);
dev_dbg(pdata->dev, " Timestamp source : %s\n",
(hw_feat->ts_src == 1) ? "internal" :
(hw_feat->ts_src == 2) ? "external" :
(hw_feat->ts_src == 3) ? "internal/external" : "n/a");
dev_dbg(pdata->dev, " SA/VLAN insertion : %s\n",
hw_feat->sa_vlan_ins ? "yes" : "no");
dev_dbg(pdata->dev, " VXLAN/NVGRE support : %s\n",
hw_feat->vxn ? "yes" : "no");
/* Hardware feature register 1 */
dev_dbg(pdata->dev, " RX fifo size : %u\n",
hw_feat->rx_fifo_size);
dev_dbg(pdata->dev, " TX fifo size : %u\n",
hw_feat->tx_fifo_size);
dev_dbg(pdata->dev, " IEEE 1588 high word : %s\n",
hw_feat->adv_ts_hi ? "yes" : "no");
dev_dbg(pdata->dev, " DMA width : %u\n",
hw_feat->dma_width);
dev_dbg(pdata->dev, " Data Center Bridging : %s\n",
hw_feat->dcb ? "yes" : "no");
dev_dbg(pdata->dev, " Split header : %s\n",
hw_feat->sph ? "yes" : "no");
dev_dbg(pdata->dev, " TCP Segmentation Offload : %s\n",
hw_feat->tso ? "yes" : "no");
dev_dbg(pdata->dev, " Debug memory interface : %s\n",
hw_feat->dma_debug ? "yes" : "no");
dev_dbg(pdata->dev, " Receive Side Scaling : %s\n",
hw_feat->rss ? "yes" : "no");
dev_dbg(pdata->dev, " Traffic Class count : %u\n",
hw_feat->tc_cnt);
dev_dbg(pdata->dev, " Hash table size : %u\n",
hw_feat->hash_table_size);
dev_dbg(pdata->dev, " L3/L4 Filters : %u\n",
hw_feat->l3l4_filter_num);
/* Hardware feature register 2 */
dev_dbg(pdata->dev, " RX queue count : %u\n",
hw_feat->rx_q_cnt);
dev_dbg(pdata->dev, " TX queue count : %u\n",
hw_feat->tx_q_cnt);
dev_dbg(pdata->dev, " RX DMA channel count : %u\n",
hw_feat->rx_ch_cnt);
dev_dbg(pdata->dev, " TX DMA channel count : %u\n",
hw_feat->rx_ch_cnt);
dev_dbg(pdata->dev, " PPS outputs : %u\n",
hw_feat->pps_out_num);
dev_dbg(pdata->dev, " Auxiliary snapshot inputs : %u\n",
hw_feat->aux_snap_num);
}
}
static void xgbe_disable_vxlan_offloads(struct xgbe_prv_data *pdata)
{
struct net_device *netdev = pdata->netdev;
if (!pdata->vxlan_offloads_set)
return;
netdev_info(netdev, "disabling VXLAN offloads\n");
netdev->hw_enc_features &= ~(NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_GRO |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM);
netdev->features &= ~(NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM);
pdata->vxlan_offloads_set = 0;
}
static void xgbe_disable_vxlan_hw(struct xgbe_prv_data *pdata)
{
if (!pdata->vxlan_port_set)
return;
pdata->hw_if.disable_vxlan(pdata);
pdata->vxlan_port_set = 0;
pdata->vxlan_port = 0;
}
static void xgbe_disable_vxlan_accel(struct xgbe_prv_data *pdata)
{
xgbe_disable_vxlan_offloads(pdata);
xgbe_disable_vxlan_hw(pdata);
}
static void xgbe_enable_vxlan_offloads(struct xgbe_prv_data *pdata)
{
struct net_device *netdev = pdata->netdev;
if (pdata->vxlan_offloads_set)
return;
netdev_info(netdev, "enabling VXLAN offloads\n");
netdev->hw_enc_features |= NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_GRO |
pdata->vxlan_features;
netdev->features |= pdata->vxlan_features;
pdata->vxlan_offloads_set = 1;
}
static void xgbe_enable_vxlan_hw(struct xgbe_prv_data *pdata)
{
struct xgbe_vxlan_data *vdata;
if (pdata->vxlan_port_set)
return;
if (list_empty(&pdata->vxlan_ports))
return;
vdata = list_first_entry(&pdata->vxlan_ports,
struct xgbe_vxlan_data, list);
pdata->vxlan_port_set = 1;
pdata->vxlan_port = be16_to_cpu(vdata->port);
pdata->hw_if.enable_vxlan(pdata);
}
static void xgbe_enable_vxlan_accel(struct xgbe_prv_data *pdata)
{
/* VXLAN acceleration desired? */
if (!pdata->vxlan_features)
return;
/* VXLAN acceleration possible? */
if (pdata->vxlan_force_disable)
return;
xgbe_enable_vxlan_hw(pdata);
xgbe_enable_vxlan_offloads(pdata);
}
static void xgbe_reset_vxlan_accel(struct xgbe_prv_data *pdata)
{
xgbe_disable_vxlan_hw(pdata);
if (pdata->vxlan_features)
xgbe_enable_vxlan_offloads(pdata);
pdata->vxlan_force_disable = 0;
} }
static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add) static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add)
...@@ -887,7 +1073,7 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata) ...@@ -887,7 +1073,7 @@ static int xgbe_request_irqs(struct xgbe_prv_data *pdata)
(unsigned long)pdata); (unsigned long)pdata);
ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0, ret = devm_request_irq(pdata->dev, pdata->dev_irq, xgbe_isr, 0,
netdev->name, pdata); netdev_name(netdev), pdata);
if (ret) { if (ret) {
netdev_alert(netdev, "error requesting irq %d\n", netdev_alert(netdev, "error requesting irq %d\n",
pdata->dev_irq); pdata->dev_irq);
...@@ -1154,6 +1340,8 @@ static int xgbe_start(struct xgbe_prv_data *pdata) ...@@ -1154,6 +1340,8 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
hw_if->enable_tx(pdata); hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata); hw_if->enable_rx(pdata);
udp_tunnel_get_rx_info(netdev);
netif_tx_start_all_queues(netdev); netif_tx_start_all_queues(netdev);
xgbe_start_timers(pdata); xgbe_start_timers(pdata);
...@@ -1195,6 +1383,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) ...@@ -1195,6 +1383,8 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
xgbe_stop_timers(pdata); xgbe_stop_timers(pdata);
flush_workqueue(pdata->dev_workqueue); flush_workqueue(pdata->dev_workqueue);
xgbe_reset_vxlan_accel(pdata);
hw_if->disable_tx(pdata); hw_if->disable_tx(pdata);
hw_if->disable_rx(pdata); hw_if->disable_rx(pdata);
...@@ -1483,10 +1673,18 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) ...@@ -1483,10 +1673,18 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet)
if (ret) if (ret)
return ret; return ret;
packet->header_len = skb_transport_offset(skb) + tcp_hdrlen(skb); if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, VXLAN)) {
packet->tcp_header_len = tcp_hdrlen(skb); packet->header_len = skb_inner_transport_offset(skb) +
inner_tcp_hdrlen(skb);
packet->tcp_header_len = inner_tcp_hdrlen(skb);
} else {
packet->header_len = skb_transport_offset(skb) +
tcp_hdrlen(skb);
packet->tcp_header_len = tcp_hdrlen(skb);
}
packet->tcp_payload_len = skb->len - packet->header_len; packet->tcp_payload_len = skb->len - packet->header_len;
packet->mss = skb_shinfo(skb)->gso_size; packet->mss = skb_shinfo(skb)->gso_size;
DBGPR(" packet->header_len=%u\n", packet->header_len); DBGPR(" packet->header_len=%u\n", packet->header_len);
DBGPR(" packet->tcp_header_len=%u, packet->tcp_payload_len=%u\n", DBGPR(" packet->tcp_header_len=%u, packet->tcp_payload_len=%u\n",
packet->tcp_header_len, packet->tcp_payload_len); packet->tcp_header_len, packet->tcp_payload_len);
...@@ -1501,6 +1699,49 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) ...@@ -1501,6 +1699,49 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet)
return 0; return 0;
} }
static bool xgbe_is_vxlan(struct xgbe_prv_data *pdata, struct sk_buff *skb)
{
struct xgbe_vxlan_data *vdata;
if (pdata->vxlan_force_disable)
return false;
if (!skb->encapsulation)
return false;
if (skb->ip_summed != CHECKSUM_PARTIAL)
return false;
switch (skb->protocol) {
case htons(ETH_P_IP):
if (ip_hdr(skb)->protocol != IPPROTO_UDP)
return false;
break;
case htons(ETH_P_IPV6):
if (ipv6_hdr(skb)->nexthdr != IPPROTO_UDP)
return false;
break;
default:
return false;
}
/* See if we have the UDP port in our list */
list_for_each_entry(vdata, &pdata->vxlan_ports, list) {
if ((skb->protocol == htons(ETH_P_IP)) &&
(vdata->sa_family == AF_INET) &&
(vdata->port == udp_hdr(skb)->dest))
return true;
else if ((skb->protocol == htons(ETH_P_IPV6)) &&
(vdata->sa_family == AF_INET6) &&
(vdata->port == udp_hdr(skb)->dest))
return true;
}
return false;
}
static int xgbe_is_tso(struct sk_buff *skb) static int xgbe_is_tso(struct sk_buff *skb)
{ {
if (skb->ip_summed != CHECKSUM_PARTIAL) if (skb->ip_summed != CHECKSUM_PARTIAL)
...@@ -1549,6 +1790,10 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, ...@@ -1549,6 +1790,10 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
CSUM_ENABLE, 1); CSUM_ENABLE, 1);
if (xgbe_is_vxlan(pdata, skb))
XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
VXLAN, 1);
if (skb_vlan_tag_present(skb)) { if (skb_vlan_tag_present(skb)) {
/* VLAN requires an extra descriptor if tag is different */ /* VLAN requires an extra descriptor if tag is different */
if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag) if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag)
...@@ -1589,16 +1834,42 @@ static int xgbe_open(struct net_device *netdev) ...@@ -1589,16 +1834,42 @@ static int xgbe_open(struct net_device *netdev)
DBGPR("-->xgbe_open\n"); DBGPR("-->xgbe_open\n");
/* Create the various names based on netdev name */
snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
netdev_name(netdev));
snprintf(pdata->ecc_name, sizeof(pdata->ecc_name) - 1, "%s-ecc",
netdev_name(netdev));
snprintf(pdata->i2c_name, sizeof(pdata->i2c_name) - 1, "%s-i2c",
netdev_name(netdev));
/* Create workqueues */
pdata->dev_workqueue =
create_singlethread_workqueue(netdev_name(netdev));
if (!pdata->dev_workqueue) {
netdev_err(netdev, "device workqueue creation failed\n");
return -ENOMEM;
}
pdata->an_workqueue =
create_singlethread_workqueue(pdata->an_name);
if (!pdata->an_workqueue) {
netdev_err(netdev, "phy workqueue creation failed\n");
ret = -ENOMEM;
goto err_dev_wq;
}
/* Reset the phy settings */ /* Reset the phy settings */
ret = xgbe_phy_reset(pdata); ret = xgbe_phy_reset(pdata);
if (ret) if (ret)
return ret; goto err_an_wq;
/* Enable the clocks */ /* Enable the clocks */
ret = clk_prepare_enable(pdata->sysclk); ret = clk_prepare_enable(pdata->sysclk);
if (ret) { if (ret) {
netdev_alert(netdev, "dma clk_prepare_enable failed\n"); netdev_alert(netdev, "dma clk_prepare_enable failed\n");
return ret; goto err_an_wq;
} }
ret = clk_prepare_enable(pdata->ptpclk); ret = clk_prepare_enable(pdata->ptpclk);
...@@ -1651,6 +1922,12 @@ static int xgbe_open(struct net_device *netdev) ...@@ -1651,6 +1922,12 @@ static int xgbe_open(struct net_device *netdev)
err_sysclk: err_sysclk:
clk_disable_unprepare(pdata->sysclk); clk_disable_unprepare(pdata->sysclk);
err_an_wq:
destroy_workqueue(pdata->an_workqueue);
err_dev_wq:
destroy_workqueue(pdata->dev_workqueue);
return ret; return ret;
} }
...@@ -1674,6 +1951,12 @@ static int xgbe_close(struct net_device *netdev) ...@@ -1674,6 +1951,12 @@ static int xgbe_close(struct net_device *netdev)
clk_disable_unprepare(pdata->ptpclk); clk_disable_unprepare(pdata->ptpclk);
clk_disable_unprepare(pdata->sysclk); clk_disable_unprepare(pdata->sysclk);
flush_workqueue(pdata->an_workqueue);
destroy_workqueue(pdata->an_workqueue);
flush_workqueue(pdata->dev_workqueue);
destroy_workqueue(pdata->dev_workqueue);
set_bit(XGBE_DOWN, &pdata->dev_state); set_bit(XGBE_DOWN, &pdata->dev_state);
DBGPR("<--xgbe_close\n"); DBGPR("<--xgbe_close\n");
...@@ -1940,18 +2223,83 @@ static int xgbe_setup_tc(struct net_device *netdev, enum tc_setup_type type, ...@@ -1940,18 +2223,83 @@ static int xgbe_setup_tc(struct net_device *netdev, enum tc_setup_type type,
return 0; return 0;
} }
static netdev_features_t xgbe_fix_features(struct net_device *netdev,
netdev_features_t features)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
netdev_features_t vxlan_base, vxlan_mask;
vxlan_base = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_RX_UDP_TUNNEL_PORT;
vxlan_mask = vxlan_base | NETIF_F_GSO_UDP_TUNNEL_CSUM;
pdata->vxlan_features = features & vxlan_mask;
/* Only fix VXLAN-related features */
if (!pdata->vxlan_features)
return features;
/* If VXLAN isn't supported then clear any features:
* This is needed because NETIF_F_RX_UDP_TUNNEL_PORT gets
* automatically set if ndo_udp_tunnel_add is set.
*/
if (!pdata->hw_feat.vxn)
return features & ~vxlan_mask;
/* VXLAN CSUM requires VXLAN base */
if ((features & NETIF_F_GSO_UDP_TUNNEL_CSUM) &&
!(features & NETIF_F_GSO_UDP_TUNNEL)) {
netdev_notice(netdev,
"forcing tx udp tunnel support\n");
features |= NETIF_F_GSO_UDP_TUNNEL;
}
/* Can't do one without doing the other */
if ((features & vxlan_base) != vxlan_base) {
netdev_notice(netdev,
"forcing both tx and rx udp tunnel support\n");
features |= vxlan_base;
}
if (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) {
if (!(features & NETIF_F_GSO_UDP_TUNNEL_CSUM)) {
netdev_notice(netdev,
"forcing tx udp tunnel checksumming on\n");
features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
}
} else {
if (features & NETIF_F_GSO_UDP_TUNNEL_CSUM) {
netdev_notice(netdev,
"forcing tx udp tunnel checksumming off\n");
features &= ~NETIF_F_GSO_UDP_TUNNEL_CSUM;
}
}
pdata->vxlan_features = features & vxlan_mask;
/* Adjust UDP Tunnel based on current state */
if (pdata->vxlan_force_disable) {
netdev_notice(netdev,
"VXLAN acceleration disabled, turning off udp tunnel features\n");
features &= ~vxlan_mask;
}
return features;
}
static int xgbe_set_features(struct net_device *netdev, static int xgbe_set_features(struct net_device *netdev,
netdev_features_t features) netdev_features_t features)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_hw_if *hw_if = &pdata->hw_if;
netdev_features_t rxhash, rxcsum, rxvlan, rxvlan_filter; netdev_features_t rxhash, rxcsum, rxvlan, rxvlan_filter;
netdev_features_t udp_tunnel;
int ret = 0; int ret = 0;
rxhash = pdata->netdev_features & NETIF_F_RXHASH; rxhash = pdata->netdev_features & NETIF_F_RXHASH;
rxcsum = pdata->netdev_features & NETIF_F_RXCSUM; rxcsum = pdata->netdev_features & NETIF_F_RXCSUM;
rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX; rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX;
rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER; rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER;
udp_tunnel = pdata->netdev_features & NETIF_F_GSO_UDP_TUNNEL;
if ((features & NETIF_F_RXHASH) && !rxhash) if ((features & NETIF_F_RXHASH) && !rxhash)
ret = hw_if->enable_rss(pdata); ret = hw_if->enable_rss(pdata);
...@@ -1975,6 +2323,11 @@ static int xgbe_set_features(struct net_device *netdev, ...@@ -1975,6 +2323,11 @@ static int xgbe_set_features(struct net_device *netdev,
else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter) else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter)
hw_if->disable_rx_vlan_filtering(pdata); hw_if->disable_rx_vlan_filtering(pdata);
if ((features & NETIF_F_GSO_UDP_TUNNEL) && !udp_tunnel)
xgbe_enable_vxlan_accel(pdata);
else if (!(features & NETIF_F_GSO_UDP_TUNNEL) && udp_tunnel)
xgbe_disable_vxlan_accel(pdata);
pdata->netdev_features = features; pdata->netdev_features = features;
DBGPR("<--xgbe_set_features\n"); DBGPR("<--xgbe_set_features\n");
...@@ -1982,6 +2335,111 @@ static int xgbe_set_features(struct net_device *netdev, ...@@ -1982,6 +2335,111 @@ static int xgbe_set_features(struct net_device *netdev,
return 0; return 0;
} }
static void xgbe_udp_tunnel_add(struct net_device *netdev,
struct udp_tunnel_info *ti)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_vxlan_data *vdata;
if (!pdata->hw_feat.vxn)
return;
if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
return;
pdata->vxlan_port_count++;
netif_dbg(pdata, drv, netdev,
"adding VXLAN tunnel, family=%hx/port=%hx\n",
ti->sa_family, be16_to_cpu(ti->port));
if (pdata->vxlan_force_disable)
return;
vdata = kzalloc(sizeof(*vdata), GFP_ATOMIC);
if (!vdata) {
/* Can no longer properly track VXLAN ports */
pdata->vxlan_force_disable = 1;
netif_dbg(pdata, drv, netdev,
"internal error, disabling VXLAN accelerations\n");
xgbe_disable_vxlan_accel(pdata);
return;
}
vdata->sa_family = ti->sa_family;
vdata->port = ti->port;
list_add_tail(&vdata->list, &pdata->vxlan_ports);
/* First port added? */
if (pdata->vxlan_port_count == 1) {
xgbe_enable_vxlan_accel(pdata);
return;
}
}
static void xgbe_udp_tunnel_del(struct net_device *netdev,
struct udp_tunnel_info *ti)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_vxlan_data *vdata;
if (!pdata->hw_feat.vxn)
return;
if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
return;
netif_dbg(pdata, drv, netdev,
"deleting VXLAN tunnel, family=%hx/port=%hx\n",
ti->sa_family, be16_to_cpu(ti->port));
/* Don't need safe version since loop terminates with deletion */
list_for_each_entry(vdata, &pdata->vxlan_ports, list) {
if (vdata->sa_family != ti->sa_family)
continue;
if (vdata->port != ti->port)
continue;
list_del(&vdata->list);
kfree(vdata);
break;
}
pdata->vxlan_port_count--;
if (!pdata->vxlan_port_count) {
xgbe_reset_vxlan_accel(pdata);
return;
}
if (pdata->vxlan_force_disable)
return;
/* See if VXLAN tunnel id needs to be changed */
vdata = list_first_entry(&pdata->vxlan_ports,
struct xgbe_vxlan_data, list);
if (pdata->vxlan_port == be16_to_cpu(vdata->port))
return;
pdata->vxlan_port = be16_to_cpu(vdata->port);
pdata->hw_if.set_vxlan_id(pdata);
}
static netdev_features_t xgbe_features_check(struct sk_buff *skb,
struct net_device *netdev,
netdev_features_t features)
{
features = vlan_features_check(skb, features);
features = vxlan_features_check(skb, features);
return features;
}
static const struct net_device_ops xgbe_netdev_ops = { static const struct net_device_ops xgbe_netdev_ops = {
.ndo_open = xgbe_open, .ndo_open = xgbe_open,
.ndo_stop = xgbe_close, .ndo_stop = xgbe_close,
...@@ -1999,7 +2457,11 @@ static const struct net_device_ops xgbe_netdev_ops = { ...@@ -1999,7 +2457,11 @@ static const struct net_device_ops xgbe_netdev_ops = {
.ndo_poll_controller = xgbe_poll_controller, .ndo_poll_controller = xgbe_poll_controller,
#endif #endif
.ndo_setup_tc = xgbe_setup_tc, .ndo_setup_tc = xgbe_setup_tc,
.ndo_fix_features = xgbe_fix_features,
.ndo_set_features = xgbe_set_features, .ndo_set_features = xgbe_set_features,
.ndo_udp_tunnel_add = xgbe_udp_tunnel_add,
.ndo_udp_tunnel_del = xgbe_udp_tunnel_del,
.ndo_features_check = xgbe_features_check,
}; };
const struct net_device_ops *xgbe_get_netdev_ops(void) const struct net_device_ops *xgbe_get_netdev_ops(void)
...@@ -2311,6 +2773,15 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) ...@@ -2311,6 +2773,15 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget)
RX_PACKET_ATTRIBUTES, CSUM_DONE)) RX_PACKET_ATTRIBUTES, CSUM_DONE))
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
if (XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES, TNP)) {
skb->encapsulation = 1;
if (XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES, TNPCSUM_DONE))
skb->csum_level = 1;
}
if (XGMAC_GET_BITS(packet->attributes, if (XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES, VLAN_CTAG)) RX_PACKET_ATTRIBUTES, VLAN_CTAG))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
......
...@@ -146,6 +146,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = { ...@@ -146,6 +146,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb), XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb),
XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb), XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb),
XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g), XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g),
XGMAC_EXT_STAT("tx_vxlan_packets", tx_vxlan_packets),
XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets), XGMAC_EXT_STAT("tx_tso_packets", tx_tso_packets),
XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb), XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb),
XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb), XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb),
...@@ -162,6 +163,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = { ...@@ -162,6 +163,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g), XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g),
XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g), XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g),
XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb), XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb),
XGMAC_EXT_STAT("rx_vxlan_packets", rx_vxlan_packets),
XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb), XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb),
XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb), XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb),
XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb), XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb),
...@@ -177,6 +179,8 @@ static const struct xgbe_stats xgbe_gstring_stats[] = { ...@@ -177,6 +179,8 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype), XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype),
XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow), XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow),
XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror), XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
XGMAC_EXT_STAT("rx_csum_errors", rx_csum_errors),
XGMAC_EXT_STAT("rx_vxlan_csum_errors", rx_vxlan_csum_errors),
XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes), XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets), XGMAC_EXT_STAT("rx_split_header_packets", rx_split_header_packets),
XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable), XGMAC_EXT_STAT("rx_buffer_unavailable", rx_buffer_unavailable),
...@@ -186,6 +190,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = { ...@@ -186,6 +190,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev);
int i; int i;
switch (stringset) { switch (stringset) {
...@@ -195,6 +200,18 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) ...@@ -195,6 +200,18 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN; data += ETH_GSTRING_LEN;
} }
for (i = 0; i < pdata->tx_ring_count; i++) {
sprintf(data, "txq_%u_packets", i);
data += ETH_GSTRING_LEN;
sprintf(data, "txq_%u_bytes", i);
data += ETH_GSTRING_LEN;
}
for (i = 0; i < pdata->rx_ring_count; i++) {
sprintf(data, "rxq_%u_packets", i);
data += ETH_GSTRING_LEN;
sprintf(data, "rxq_%u_bytes", i);
data += ETH_GSTRING_LEN;
}
break; break;
} }
} }
...@@ -211,15 +228,26 @@ static void xgbe_get_ethtool_stats(struct net_device *netdev, ...@@ -211,15 +228,26 @@ static void xgbe_get_ethtool_stats(struct net_device *netdev,
stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset; stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset;
*data++ = *(u64 *)stat; *data++ = *(u64 *)stat;
} }
for (i = 0; i < pdata->tx_ring_count; i++) {
*data++ = pdata->ext_stats.txq_packets[i];
*data++ = pdata->ext_stats.txq_bytes[i];
}
for (i = 0; i < pdata->rx_ring_count; i++) {
*data++ = pdata->ext_stats.rxq_packets[i];
*data++ = pdata->ext_stats.rxq_bytes[i];
}
} }
static int xgbe_get_sset_count(struct net_device *netdev, int stringset) static int xgbe_get_sset_count(struct net_device *netdev, int stringset)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev);
int ret; int ret;
switch (stringset) { switch (stringset) {
case ETH_SS_STATS: case ETH_SS_STATS:
ret = XGBE_STATS_COUNT; ret = XGBE_STATS_COUNT +
(pdata->tx_ring_count * 2) +
(pdata->rx_ring_count * 2);
break; break;
default: default:
...@@ -243,6 +271,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev, ...@@ -243,6 +271,7 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause) struct ethtool_pauseparam *pause)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
int ret = 0; int ret = 0;
if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) { if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE)) {
...@@ -255,16 +284,21 @@ static int xgbe_set_pauseparam(struct net_device *netdev, ...@@ -255,16 +284,21 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
pdata->phy.tx_pause = pause->tx_pause; pdata->phy.tx_pause = pause->tx_pause;
pdata->phy.rx_pause = pause->rx_pause; pdata->phy.rx_pause = pause->rx_pause;
pdata->phy.advertising &= ~ADVERTISED_Pause; XGBE_CLR_ADV(lks, Pause);
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; XGBE_CLR_ADV(lks, Asym_Pause);
if (pause->rx_pause) { if (pause->rx_pause) {
pdata->phy.advertising |= ADVERTISED_Pause; XGBE_SET_ADV(lks, Pause);
pdata->phy.advertising |= ADVERTISED_Asym_Pause; XGBE_SET_ADV(lks, Asym_Pause);
} }
if (pause->tx_pause) if (pause->tx_pause) {
pdata->phy.advertising ^= ADVERTISED_Asym_Pause; /* Equivalent to XOR of Asym_Pause */
if (XGBE_ADV(lks, Asym_Pause))
XGBE_CLR_ADV(lks, Asym_Pause);
else
XGBE_SET_ADV(lks, Asym_Pause);
}
if (netif_running(netdev)) if (netif_running(netdev))
ret = pdata->phy_if.phy_config_aneg(pdata); ret = pdata->phy_if.phy_config_aneg(pdata);
...@@ -276,22 +310,20 @@ static int xgbe_get_link_ksettings(struct net_device *netdev, ...@@ -276,22 +310,20 @@ static int xgbe_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd) struct ethtool_link_ksettings *cmd)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
cmd->base.phy_address = pdata->phy.address; cmd->base.phy_address = pdata->phy.address;
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
pdata->phy.supported);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
pdata->phy.advertising);
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
pdata->phy.lp_advertising);
cmd->base.autoneg = pdata->phy.autoneg; cmd->base.autoneg = pdata->phy.autoneg;
cmd->base.speed = pdata->phy.speed; cmd->base.speed = pdata->phy.speed;
cmd->base.duplex = pdata->phy.duplex; cmd->base.duplex = pdata->phy.duplex;
cmd->base.port = PORT_NONE; cmd->base.port = PORT_NONE;
XGBE_LM_COPY(cmd, supported, lks, supported);
XGBE_LM_COPY(cmd, advertising, lks, advertising);
XGBE_LM_COPY(cmd, lp_advertising, lks, lp_advertising);
return 0; return 0;
} }
...@@ -299,7 +331,8 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -299,7 +331,8 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd) const struct ethtool_link_ksettings *cmd)
{ {
struct xgbe_prv_data *pdata = netdev_priv(netdev); struct xgbe_prv_data *pdata = netdev_priv(netdev);
u32 advertising; struct ethtool_link_ksettings *lks = &pdata->phy.lks;
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
u32 speed; u32 speed;
int ret; int ret;
...@@ -331,15 +364,17 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -331,15 +364,17 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
} }
} }
ethtool_convert_link_mode_to_legacy_u32(&advertising,
cmd->link_modes.advertising);
netif_dbg(pdata, link, netdev, netif_dbg(pdata, link, netdev,
"requested advertisement %#x, phy supported %#x\n", "requested advertisement 0x%*pb, phy supported 0x%*pb\n",
advertising, pdata->phy.supported); __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising,
__ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported);
bitmap_and(advertising,
cmd->link_modes.advertising, lks->link_modes.supported,
__ETHTOOL_LINK_MODE_MASK_NBITS);
advertising &= pdata->phy.supported; if ((cmd->base.autoneg == AUTONEG_ENABLE) &&
if ((cmd->base.autoneg == AUTONEG_ENABLE) && !advertising) { bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
netdev_err(netdev, netdev_err(netdev,
"unsupported requested advertisement\n"); "unsupported requested advertisement\n");
return -EINVAL; return -EINVAL;
...@@ -349,12 +384,13 @@ static int xgbe_set_link_ksettings(struct net_device *netdev, ...@@ -349,12 +384,13 @@ static int xgbe_set_link_ksettings(struct net_device *netdev,
pdata->phy.autoneg = cmd->base.autoneg; pdata->phy.autoneg = cmd->base.autoneg;
pdata->phy.speed = speed; pdata->phy.speed = speed;
pdata->phy.duplex = cmd->base.duplex; pdata->phy.duplex = cmd->base.duplex;
pdata->phy.advertising = advertising; bitmap_copy(lks->link_modes.advertising, advertising,
__ETHTOOL_LINK_MODE_MASK_NBITS);
if (cmd->base.autoneg == AUTONEG_ENABLE) if (cmd->base.autoneg == AUTONEG_ENABLE)
pdata->phy.advertising |= ADVERTISED_Autoneg; XGBE_SET_ADV(lks, Autoneg);
else else
pdata->phy.advertising &= ~ADVERTISED_Autoneg; XGBE_CLR_ADV(lks, Autoneg);
if (netif_running(netdev)) if (netif_running(netdev))
ret = pdata->phy_if.phy_config_aneg(pdata); ret = pdata->phy_if.phy_config_aneg(pdata);
......
...@@ -120,6 +120,7 @@ ...@@ -120,6 +120,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/notifier.h>
#include "xgbe.h" #include "xgbe.h"
#include "xgbe-common.h" #include "xgbe-common.h"
...@@ -192,6 +193,7 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev) ...@@ -192,6 +193,7 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
mutex_init(&pdata->i2c_mutex); mutex_init(&pdata->i2c_mutex);
init_completion(&pdata->i2c_complete); init_completion(&pdata->i2c_complete);
init_completion(&pdata->mdio_complete); init_completion(&pdata->mdio_complete);
INIT_LIST_HEAD(&pdata->vxlan_ports);
pdata->msg_enable = netif_msg_init(debug, default_msg_level); pdata->msg_enable = netif_msg_init(debug, default_msg_level);
...@@ -373,6 +375,28 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) ...@@ -373,6 +375,28 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
if (pdata->hw_feat.rss) if (pdata->hw_feat.rss)
netdev->hw_features |= NETIF_F_RXHASH; netdev->hw_features |= NETIF_F_RXHASH;
if (pdata->hw_feat.vxn) {
netdev->hw_enc_features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_GRO |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_RX_UDP_TUNNEL_PORT;
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_RX_UDP_TUNNEL_PORT;
pdata->vxlan_offloads_set = 1;
pdata->vxlan_features = NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_RX_UDP_TUNNEL_PORT;
}
netdev->vlan_features |= NETIF_F_SG | netdev->vlan_features |= NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM | NETIF_F_IPV6_CSUM |
...@@ -399,35 +423,6 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) ...@@ -399,35 +423,6 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
return ret; return ret;
} }
/* Create the PHY/ANEG name based on netdev name */
snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
netdev_name(netdev));
/* Create the ECC name based on netdev name */
snprintf(pdata->ecc_name, sizeof(pdata->ecc_name) - 1, "%s-ecc",
netdev_name(netdev));
/* Create the I2C name based on netdev name */
snprintf(pdata->i2c_name, sizeof(pdata->i2c_name) - 1, "%s-i2c",
netdev_name(netdev));
/* Create workqueues */
pdata->dev_workqueue =
create_singlethread_workqueue(netdev_name(netdev));
if (!pdata->dev_workqueue) {
netdev_err(netdev, "device workqueue creation failed\n");
ret = -ENOMEM;
goto err_netdev;
}
pdata->an_workqueue =
create_singlethread_workqueue(pdata->an_name);
if (!pdata->an_workqueue) {
netdev_err(netdev, "phy workqueue creation failed\n");
ret = -ENOMEM;
goto err_wq;
}
if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK)) if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK))
xgbe_ptp_register(pdata); xgbe_ptp_register(pdata);
...@@ -439,14 +434,6 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) ...@@ -439,14 +434,6 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
pdata->rx_ring_count); pdata->rx_ring_count);
return 0; return 0;
err_wq:
destroy_workqueue(pdata->dev_workqueue);
err_netdev:
unregister_netdev(netdev);
return ret;
} }
void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata) void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata)
...@@ -458,21 +445,45 @@ void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata) ...@@ -458,21 +445,45 @@ void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata)
if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK)) if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK))
xgbe_ptp_unregister(pdata); xgbe_ptp_unregister(pdata);
unregister_netdev(netdev);
pdata->phy_if.phy_exit(pdata); pdata->phy_if.phy_exit(pdata);
}
flush_workqueue(pdata->an_workqueue); static int xgbe_netdev_event(struct notifier_block *nb, unsigned long event,
destroy_workqueue(pdata->an_workqueue); void *data)
{
struct net_device *netdev = netdev_notifier_info_to_dev(data);
struct xgbe_prv_data *pdata = netdev_priv(netdev);
flush_workqueue(pdata->dev_workqueue); if (netdev->netdev_ops != xgbe_get_netdev_ops())
destroy_workqueue(pdata->dev_workqueue); goto out;
unregister_netdev(netdev); switch (event) {
case NETDEV_CHANGENAME:
xgbe_debugfs_rename(pdata);
break;
default:
break;
}
out:
return NOTIFY_DONE;
} }
static struct notifier_block xgbe_netdev_notifier = {
.notifier_call = xgbe_netdev_event,
};
static int __init xgbe_mod_init(void) static int __init xgbe_mod_init(void)
{ {
int ret; int ret;
ret = register_netdevice_notifier(&xgbe_netdev_notifier);
if (ret)
return ret;
ret = xgbe_platform_init(); ret = xgbe_platform_init();
if (ret) if (ret)
return ret; return ret;
...@@ -489,6 +500,8 @@ static void __exit xgbe_mod_exit(void) ...@@ -489,6 +500,8 @@ static void __exit xgbe_mod_exit(void)
xgbe_pci_exit(); xgbe_pci_exit();
xgbe_platform_exit(); xgbe_platform_exit();
unregister_netdevice_notifier(&xgbe_netdev_notifier);
} }
module_init(xgbe_mod_init); module_init(xgbe_mod_init);
......
...@@ -615,12 +615,14 @@ static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata) ...@@ -615,12 +615,14 @@ static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata)
static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
/* Be sure we aren't looping trying to negotiate */ /* Be sure we aren't looping trying to negotiate */
if (xgbe_in_kr_mode(pdata)) { if (xgbe_in_kr_mode(pdata)) {
pdata->kr_state = XGBE_RX_ERROR; pdata->kr_state = XGBE_RX_ERROR;
if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) && if (!XGBE_ADV(lks, 1000baseKX_Full) &&
!(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) !XGBE_ADV(lks, 2500baseX_Full))
return XGBE_AN_NO_LINK; return XGBE_AN_NO_LINK;
if (pdata->kx_state != XGBE_RX_BPA) if (pdata->kx_state != XGBE_RX_BPA)
...@@ -628,7 +630,7 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) ...@@ -628,7 +630,7 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
} else { } else {
pdata->kx_state = XGBE_RX_ERROR; pdata->kx_state = XGBE_RX_ERROR;
if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full)) if (!XGBE_ADV(lks, 10000baseKR_Full))
return XGBE_AN_NO_LINK; return XGBE_AN_NO_LINK;
if (pdata->kr_state != XGBE_RX_BPA) if (pdata->kr_state != XGBE_RX_BPA)
...@@ -944,18 +946,19 @@ static void xgbe_an_state_machine(struct work_struct *work) ...@@ -944,18 +946,19 @@ static void xgbe_an_state_machine(struct work_struct *work)
static void xgbe_an37_init(struct xgbe_prv_data *pdata) static void xgbe_an37_init(struct xgbe_prv_data *pdata)
{ {
unsigned int advertising, reg; struct ethtool_link_ksettings lks;
unsigned int reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata); pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
/* Set up Advertisement register */ /* Set up Advertisement register */
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
if (advertising & ADVERTISED_Pause) if (XGBE_ADV(&lks, Pause))
reg |= 0x100; reg |= 0x100;
else else
reg &= ~0x100; reg &= ~0x100;
if (advertising & ADVERTISED_Asym_Pause) if (XGBE_ADV(&lks, Asym_Pause))
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
...@@ -982,6 +985,8 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata) ...@@ -982,6 +985,8 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata)
break; break;
} }
reg |= XGBE_AN_CL37_MII_CTRL_8BIT;
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n", netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n",
...@@ -990,13 +995,14 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata) ...@@ -990,13 +995,14 @@ static void xgbe_an37_init(struct xgbe_prv_data *pdata)
static void xgbe_an73_init(struct xgbe_prv_data *pdata) static void xgbe_an73_init(struct xgbe_prv_data *pdata)
{ {
unsigned int advertising, reg; struct ethtool_link_ksettings lks;
unsigned int reg;
advertising = pdata->phy_if.phy_impl.an_advertising(pdata); pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
/* Set up Advertisement register 3 first */ /* Set up Advertisement register 3 first */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
if (advertising & ADVERTISED_10000baseR_FEC) if (XGBE_ADV(&lks, 10000baseR_FEC))
reg |= 0xc000; reg |= 0xc000;
else else
reg &= ~0xc000; reg &= ~0xc000;
...@@ -1005,13 +1011,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -1005,13 +1011,13 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 2 next */ /* Set up Advertisement register 2 next */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
if (advertising & ADVERTISED_10000baseKR_Full) if (XGBE_ADV(&lks, 10000baseKR_Full))
reg |= 0x80; reg |= 0x80;
else else
reg &= ~0x80; reg &= ~0x80;
if ((advertising & ADVERTISED_1000baseKX_Full) || if (XGBE_ADV(&lks, 1000baseKX_Full) ||
(advertising & ADVERTISED_2500baseX_Full)) XGBE_ADV(&lks, 2500baseX_Full))
reg |= 0x20; reg |= 0x20;
else else
reg &= ~0x20; reg &= ~0x20;
...@@ -1020,12 +1026,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata) ...@@ -1020,12 +1026,12 @@ static void xgbe_an73_init(struct xgbe_prv_data *pdata)
/* Set up Advertisement register 1 last */ /* Set up Advertisement register 1 last */
reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
if (advertising & ADVERTISED_Pause) if (XGBE_ADV(&lks, Pause))
reg |= 0x400; reg |= 0x400;
else else
reg &= ~0x400; reg &= ~0x400;
if (advertising & ADVERTISED_Asym_Pause) if (XGBE_ADV(&lks, Asym_Pause))
reg |= 0x800; reg |= 0x800;
else else
reg &= ~0x800; reg &= ~0x800;
...@@ -1281,9 +1287,10 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) ...@@ -1281,9 +1287,10 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
pdata->phy.lp_advertising = 0; XGBE_ZERO_LP_ADV(lks);
if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
mode = xgbe_cur_mode(pdata); mode = xgbe_cur_mode(pdata);
...@@ -1513,17 +1520,21 @@ static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) ...@@ -1513,17 +1520,21 @@ static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
{ {
if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) struct ethtool_link_ksettings *lks = &pdata->phy.lks;
if (XGBE_ADV(lks, 10000baseKR_Full))
return SPEED_10000; return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_10000baseT_Full) else if (XGBE_ADV(lks, 10000baseT_Full))
return SPEED_10000; return SPEED_10000;
else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full) else if (XGBE_ADV(lks, 2500baseX_Full))
return SPEED_2500; return SPEED_2500;
else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full) else if (XGBE_ADV(lks, 2500baseT_Full))
return SPEED_2500;
else if (XGBE_ADV(lks, 1000baseKX_Full))
return SPEED_1000; return SPEED_1000;
else if (pdata->phy.advertising & ADVERTISED_1000baseT_Full) else if (XGBE_ADV(lks, 1000baseT_Full))
return SPEED_1000; return SPEED_1000;
else if (pdata->phy.advertising & ADVERTISED_100baseT_Full) else if (XGBE_ADV(lks, 100baseT_Full))
return SPEED_100; return SPEED_100;
return SPEED_UNKNOWN; return SPEED_UNKNOWN;
...@@ -1531,13 +1542,12 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata) ...@@ -1531,13 +1542,12 @@ static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
static void xgbe_phy_exit(struct xgbe_prv_data *pdata) static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
{ {
xgbe_phy_stop(pdata);
pdata->phy_if.phy_impl.exit(pdata); pdata->phy_if.phy_impl.exit(pdata);
} }
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
int ret; int ret;
mutex_init(&pdata->an_mutex); mutex_init(&pdata->an_mutex);
...@@ -1555,11 +1565,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -1555,11 +1565,13 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
ret = pdata->phy_if.phy_impl.init(pdata); ret = pdata->phy_if.phy_impl.init(pdata);
if (ret) if (ret)
return ret; return ret;
pdata->phy.advertising = pdata->phy.supported;
/* Copy supported link modes to advertising link modes */
XGBE_LM_COPY(lks, advertising, lks, supported);
pdata->phy.address = 0; pdata->phy.address = 0;
if (pdata->phy.advertising & ADVERTISED_Autoneg) { if (XGBE_ADV(lks, Autoneg)) {
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN;
...@@ -1576,16 +1588,21 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -1576,16 +1588,21 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
pdata->phy.rx_pause = pdata->rx_pause; pdata->phy.rx_pause = pdata->rx_pause;
/* Fix up Flow Control advertising */ /* Fix up Flow Control advertising */
pdata->phy.advertising &= ~ADVERTISED_Pause; XGBE_CLR_ADV(lks, Pause);
pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; XGBE_CLR_ADV(lks, Asym_Pause);
if (pdata->rx_pause) { if (pdata->rx_pause) {
pdata->phy.advertising |= ADVERTISED_Pause; XGBE_SET_ADV(lks, Pause);
pdata->phy.advertising |= ADVERTISED_Asym_Pause; XGBE_SET_ADV(lks, Asym_Pause);
} }
if (pdata->tx_pause) if (pdata->tx_pause) {
pdata->phy.advertising ^= ADVERTISED_Asym_Pause; /* Equivalent to XOR of Asym_Pause */
if (XGBE_ADV(lks, Asym_Pause))
XGBE_CLR_ADV(lks, Asym_Pause);
else
XGBE_SET_ADV(lks, Asym_Pause);
}
if (netif_msg_drv(pdata)) if (netif_msg_drv(pdata))
xgbe_dump_phy_registers(pdata); xgbe_dump_phy_registers(pdata);
......
...@@ -292,6 +292,10 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -292,6 +292,10 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pdata->xpcs_window_size = 1 << (pdata->xpcs_window_size + 7); pdata->xpcs_window_size = 1 << (pdata->xpcs_window_size + 7);
pdata->xpcs_window_mask = pdata->xpcs_window_size - 1; pdata->xpcs_window_mask = pdata->xpcs_window_size - 1;
if (netif_msg_probe(pdata)) { if (netif_msg_probe(pdata)) {
dev_dbg(dev, "xpcs window def = %#010x\n",
pdata->xpcs_window_def_reg);
dev_dbg(dev, "xpcs window sel = %#010x\n",
pdata->xpcs_window_sel_reg);
dev_dbg(dev, "xpcs window = %#010x\n", dev_dbg(dev, "xpcs window = %#010x\n",
pdata->xpcs_window); pdata->xpcs_window);
dev_dbg(dev, "xpcs window size = %#010x\n", dev_dbg(dev, "xpcs window size = %#010x\n",
......
...@@ -231,20 +231,21 @@ static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) ...@@ -231,20 +231,21 @@ static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Compare Advertisement and Link Partner register 1 */ /* Compare Advertisement and Link Partner register 1 */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
if (lp_reg & 0x400) if (lp_reg & 0x400)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x800) if (lp_reg & 0x800)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -266,12 +267,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -266,12 +267,12 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) { if (lp_reg & 0x20) {
if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000) if (phy_data->speed_set == XGBE_SPEEDSET_2500_10000)
pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full; XGBE_SET_LP_ADV(lks, 2500baseX_Full);
else else
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
} }
ad_reg &= lp_reg; ad_reg &= lp_reg;
...@@ -290,14 +291,17 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -290,14 +291,17 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
struct ethtool_link_ksettings *dlks)
{ {
return pdata->phy.advertising; struct ethtool_link_ksettings *slks = &pdata->phy.lks;
XGBE_LM_COPY(dlks, advertising, slks, advertising);
} }
static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
...@@ -565,11 +569,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) ...@@ -565,11 +569,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
} }
static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode, u32 advert) enum xgbe_mode mode, bool advert)
{ {
if (pdata->phy.autoneg == AUTONEG_ENABLE) { if (pdata->phy.autoneg == AUTONEG_ENABLE) {
if (pdata->phy.advertising & advert) return advert;
return true;
} else { } else {
enum xgbe_mode cur_mode; enum xgbe_mode cur_mode;
...@@ -583,16 +586,18 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, ...@@ -583,16 +586,18 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) static bool xgbe_phy_use_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_1000: case XGBE_MODE_KX_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseKX_Full); XGBE_ADV(lks, 1000baseKX_Full));
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseKR_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -672,6 +677,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ...@@ -672,6 +677,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data; struct xgbe_phy_data *phy_data;
int ret; int ret;
...@@ -790,21 +796,23 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -790,21 +796,23 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
} }
/* Initialize supported features */ /* Initialize supported features */
pdata->phy.supported = SUPPORTED_Autoneg; XGBE_ZERO_SUP(lks);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_10000baseKR_Full; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, Backplane);
XGBE_SET_SUP(lks, 10000baseKR_Full);
switch (phy_data->speed_set) { switch (phy_data->speed_set) {
case XGBE_SPEEDSET_1000_10000: case XGBE_SPEEDSET_1000_10000:
pdata->phy.supported |= SUPPORTED_1000baseKX_Full; XGBE_SET_SUP(lks, 1000baseKX_Full);
break; break;
case XGBE_SPEEDSET_2500_10000: case XGBE_SPEEDSET_2500_10000:
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, 2500baseX_Full);
break; break;
} }
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= SUPPORTED_10000baseR_FEC; XGBE_SET_SUP(lks, 10000baseR_FEC);
pdata->phy_data = phy_data; pdata->phy_data = phy_data;
......
...@@ -709,18 +709,13 @@ static int xgbe_phy_mii_read(struct mii_bus *mii, int addr, int reg) ...@@ -709,18 +709,13 @@ static int xgbe_phy_mii_read(struct mii_bus *mii, int addr, int reg)
static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed) if (!phy_data->sfp_mod_absent && !phy_data->sfp_changed)
return; return;
pdata->phy.supported &= ~SUPPORTED_Autoneg; XGBE_ZERO_SUP(lks);
pdata->phy.supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
pdata->phy.supported &= ~SUPPORTED_TP;
pdata->phy.supported &= ~SUPPORTED_FIBRE;
pdata->phy.supported &= ~SUPPORTED_100baseT_Full;
pdata->phy.supported &= ~SUPPORTED_1000baseT_Full;
pdata->phy.supported &= ~SUPPORTED_10000baseT_Full;
if (phy_data->sfp_mod_absent) { if (phy_data->sfp_mod_absent) {
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
...@@ -728,18 +723,13 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -728,18 +723,13 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.pause_autoneg = AUTONEG_ENABLE; pdata->phy.pause_autoneg = AUTONEG_ENABLE;
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) XGBE_SET_SUP(lks, FIBRE);
pdata->phy.supported |= SUPPORTED_100baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
pdata->phy.advertising = pdata->phy.supported; XGBE_LM_COPY(lks, advertising, lks, supported);
return; return;
} }
...@@ -753,8 +743,18 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -753,8 +743,18 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN;
pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.autoneg = AUTONEG_ENABLE;
pdata->phy.pause_autoneg = AUTONEG_ENABLE; pdata->phy.pause_autoneg = AUTONEG_ENABLE;
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
XGBE_SET_SUP(lks, Asym_Pause);
if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) {
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
XGBE_SET_SUP(lks, 100baseT_Full);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
XGBE_SET_SUP(lks, 1000baseT_Full);
} else {
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
XGBE_SET_SUP(lks, 1000baseX_Full);
}
break; break;
case XGBE_SFP_BASE_10000_SR: case XGBE_SFP_BASE_10000_SR:
case XGBE_SFP_BASE_10000_LR: case XGBE_SFP_BASE_10000_LR:
...@@ -765,6 +765,27 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -765,6 +765,27 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
pdata->phy.duplex = DUPLEX_FULL; pdata->phy.duplex = DUPLEX_FULL;
pdata->phy.autoneg = AUTONEG_DISABLE; pdata->phy.autoneg = AUTONEG_DISABLE;
pdata->phy.pause_autoneg = AUTONEG_DISABLE; pdata->phy.pause_autoneg = AUTONEG_DISABLE;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
switch (phy_data->sfp_base) {
case XGBE_SFP_BASE_10000_SR:
XGBE_SET_SUP(lks, 10000baseSR_Full);
break;
case XGBE_SFP_BASE_10000_LR:
XGBE_SET_SUP(lks, 10000baseLR_Full);
break;
case XGBE_SFP_BASE_10000_LRM:
XGBE_SET_SUP(lks, 10000baseLRM_Full);
break;
case XGBE_SFP_BASE_10000_ER:
XGBE_SET_SUP(lks, 10000baseER_Full);
break;
case XGBE_SFP_BASE_10000_CR:
XGBE_SET_SUP(lks, 10000baseCR_Full);
break;
default:
break;
}
}
break; break;
default: default:
pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.speed = SPEED_UNKNOWN;
...@@ -778,38 +799,14 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata) ...@@ -778,38 +799,14 @@ static void xgbe_phy_sfp_phy_settings(struct xgbe_prv_data *pdata)
case XGBE_SFP_BASE_1000_T: case XGBE_SFP_BASE_1000_T:
case XGBE_SFP_BASE_1000_CX: case XGBE_SFP_BASE_1000_CX:
case XGBE_SFP_BASE_10000_CR: case XGBE_SFP_BASE_10000_CR:
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, TP);
break; break;
default: default:
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, FIBRE);
}
switch (phy_data->sfp_speed) {
case XGBE_SFP_SPEED_100_1000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
pdata->phy.supported |= SUPPORTED_100baseT_Full;
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
break;
case XGBE_SFP_SPEED_1000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
break; break;
case XGBE_SFP_SPEED_10000:
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
break;
default:
/* Choose the fastest supported speed */
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
else if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
pdata->phy.supported |= SUPPORTED_100baseT_Full;
} }
pdata->phy.advertising = pdata->phy.supported; XGBE_LM_COPY(lks, advertising, lks, supported);
} }
static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom, static bool xgbe_phy_sfp_bit_rate(struct xgbe_sfp_eeprom *sfp_eeprom,
...@@ -886,8 +883,10 @@ static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata) ...@@ -886,8 +883,10 @@ static void xgbe_phy_external_phy_quirks(struct xgbe_prv_data *pdata)
static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
struct phy_device *phydev; struct phy_device *phydev;
u32 advertising;
int ret; int ret;
/* If we already have a PHY, just return */ /* If we already have a PHY, just return */
...@@ -943,7 +942,10 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) ...@@ -943,7 +942,10 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata)
phy_data->phydev = phydev; phy_data->phydev = phydev;
xgbe_phy_external_phy_quirks(pdata); xgbe_phy_external_phy_quirks(pdata);
phydev->advertising &= pdata->phy.advertising;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
lks->link_modes.advertising);
phydev->advertising &= advertising;
phy_start_aneg(phy_data->phydev); phy_start_aneg(phy_data->phydev);
...@@ -1277,6 +1279,7 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata) ...@@ -1277,6 +1279,7 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
u16 lcl_adv = 0, rmt_adv = 0; u16 lcl_adv = 0, rmt_adv = 0;
u8 fc; u8 fc;
...@@ -1293,11 +1296,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) ...@@ -1293,11 +1296,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
lcl_adv |= ADVERTISE_PAUSE_ASYM; lcl_adv |= ADVERTISE_PAUSE_ASYM;
if (phy_data->phydev->pause) { if (phy_data->phydev->pause) {
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
rmt_adv |= LPA_PAUSE_CAP; rmt_adv |= LPA_PAUSE_CAP;
} }
if (phy_data->phydev->asym_pause) { if (phy_data->phydev->asym_pause) {
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
rmt_adv |= LPA_PAUSE_ASYM; rmt_adv |= LPA_PAUSE_ASYM;
} }
...@@ -1310,10 +1313,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata) ...@@ -1310,10 +1313,11 @@ static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_TP; XGBE_SET_LP_ADV(lks, TP);
/* Use external PHY to determine flow control */ /* Use external PHY to determine flow control */
if (pdata->phy.pause_autoneg) if (pdata->phy.pause_autoneg)
...@@ -1322,21 +1326,21 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) ...@@ -1322,21 +1326,21 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) { switch (pdata->an_status & XGBE_SGMII_AN_LINK_SPEED) {
case XGBE_SGMII_AN_LINK_SPEED_100: case XGBE_SGMII_AN_LINK_SPEED_100:
if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_100baseT_Full; XGBE_SET_LP_ADV(lks, 100baseT_Full);
mode = XGBE_MODE_SGMII_100; mode = XGBE_MODE_SGMII_100;
} else { } else {
/* Half-duplex not supported */ /* Half-duplex not supported */
pdata->phy.lp_advertising |= ADVERTISED_100baseT_Half; XGBE_SET_LP_ADV(lks, 100baseT_Half);
mode = XGBE_MODE_UNKNOWN; mode = XGBE_MODE_UNKNOWN;
} }
break; break;
case XGBE_SGMII_AN_LINK_SPEED_1000: case XGBE_SGMII_AN_LINK_SPEED_1000:
if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) { if (pdata->an_status & XGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full; XGBE_SET_LP_ADV(lks, 1000baseT_Full);
mode = XGBE_MODE_SGMII_1000; mode = XGBE_MODE_SGMII_1000;
} else { } else {
/* Half-duplex not supported */ /* Half-duplex not supported */
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half; XGBE_SET_LP_ADV(lks, 1000baseT_Half);
mode = XGBE_MODE_UNKNOWN; mode = XGBE_MODE_UNKNOWN;
} }
break; break;
...@@ -1349,19 +1353,20 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata) ...@@ -1349,19 +1353,20 @@ static enum xgbe_mode xgbe_phy_an37_sgmii_outcome(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_FIBRE; XGBE_SET_LP_ADV(lks, FIBRE);
/* Compare Advertisement and Link Partner register */ /* Compare Advertisement and Link Partner register */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY); lp_reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_LP_ABILITY);
if (lp_reg & 0x100) if (lp_reg & 0x100)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -1379,10 +1384,8 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) ...@@ -1379,10 +1384,8 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
} }
} }
if (lp_reg & 0x40)
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Half;
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full; XGBE_SET_LP_ADV(lks, 1000baseX_Full);
/* Half duplex is not supported */ /* Half duplex is not supported */
ad_reg &= lp_reg; ad_reg &= lp_reg;
...@@ -1393,12 +1396,13 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata) ...@@ -1393,12 +1396,13 @@ static enum xgbe_mode xgbe_phy_an37_outcome(struct xgbe_prv_data *pdata)
static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Use external PHY to determine flow control */ /* Use external PHY to determine flow control */
if (pdata->phy.pause_autoneg) if (pdata->phy.pause_autoneg)
...@@ -1408,9 +1412,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) ...@@ -1408,9 +1412,9 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
ad_reg &= lp_reg; ad_reg &= lp_reg;
if (ad_reg & 0x80) { if (ad_reg & 0x80) {
...@@ -1463,26 +1467,27 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata) ...@@ -1463,26 +1467,27 @@ static enum xgbe_mode xgbe_phy_an73_redrv_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
enum xgbe_mode mode; enum xgbe_mode mode;
unsigned int ad_reg, lp_reg; unsigned int ad_reg, lp_reg;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg; XGBE_SET_LP_ADV(lks, Autoneg);
pdata->phy.lp_advertising |= ADVERTISED_Backplane; XGBE_SET_LP_ADV(lks, Backplane);
/* Compare Advertisement and Link Partner register 1 */ /* Compare Advertisement and Link Partner register 1 */
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
if (lp_reg & 0x400) if (lp_reg & 0x400)
pdata->phy.lp_advertising |= ADVERTISED_Pause; XGBE_SET_LP_ADV(lks, Pause);
if (lp_reg & 0x800) if (lp_reg & 0x800)
pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; XGBE_SET_LP_ADV(lks, Asym_Pause);
if (pdata->phy.pause_autoneg) { if (pdata->phy.pause_autoneg) {
/* Set flow control based on auto-negotiation result */ /* Set flow control based on auto-negotiation result */
...@@ -1504,9 +1509,9 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) ...@@ -1504,9 +1509,9 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
if (lp_reg & 0x80) if (lp_reg & 0x80)
pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_LP_ADV(lks, 10000baseKR_Full);
if (lp_reg & 0x20) if (lp_reg & 0x20)
pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_LP_ADV(lks, 1000baseKX_Full);
ad_reg &= lp_reg; ad_reg &= lp_reg;
if (ad_reg & 0x80) if (ad_reg & 0x80)
...@@ -1520,7 +1525,7 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata) ...@@ -1520,7 +1525,7 @@ static enum xgbe_mode xgbe_phy_an73_outcome(struct xgbe_prv_data *pdata)
ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
if (lp_reg & 0xc000) if (lp_reg & 0xc000)
pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; XGBE_SET_LP_ADV(lks, 10000baseR_FEC);
return mode; return mode;
} }
...@@ -1541,41 +1546,43 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata) ...@@ -1541,41 +1546,43 @@ static enum xgbe_mode xgbe_phy_an_outcome(struct xgbe_prv_data *pdata)
} }
} }
static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) static void xgbe_phy_an_advertising(struct xgbe_prv_data *pdata,
struct ethtool_link_ksettings *dlks)
{ {
struct ethtool_link_ksettings *slks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
unsigned int advertising;
XGBE_LM_COPY(dlks, advertising, slks, advertising);
/* Without a re-driver, just return current advertising */ /* Without a re-driver, just return current advertising */
if (!phy_data->redrv) if (!phy_data->redrv)
return pdata->phy.advertising; return;
/* With the KR re-driver we need to advertise a single speed */ /* With the KR re-driver we need to advertise a single speed */
advertising = pdata->phy.advertising; XGBE_CLR_ADV(dlks, 1000baseKX_Full);
advertising &= ~ADVERTISED_1000baseKX_Full; XGBE_CLR_ADV(dlks, 10000baseKR_Full);
advertising &= ~ADVERTISED_10000baseKR_Full;
switch (phy_data->port_mode) { switch (phy_data->port_mode) {
case XGBE_PORT_MODE_BACKPLANE: case XGBE_PORT_MODE_BACKPLANE:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
case XGBE_PORT_MODE_BACKPLANE_2500: case XGBE_PORT_MODE_BACKPLANE_2500:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_1000BASE_T: case XGBE_PORT_MODE_1000BASE_T:
case XGBE_PORT_MODE_1000BASE_X: case XGBE_PORT_MODE_1000BASE_X:
case XGBE_PORT_MODE_NBASE_T: case XGBE_PORT_MODE_NBASE_T:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_10GBASE_T: case XGBE_PORT_MODE_10GBASE_T:
if (phy_data->phydev && if (phy_data->phydev &&
(phy_data->phydev->speed == SPEED_10000)) (phy_data->phydev->speed == SPEED_10000))
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
else else
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
case XGBE_PORT_MODE_10GBASE_R: case XGBE_PORT_MODE_10GBASE_R:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
case XGBE_PORT_MODE_SFP: case XGBE_PORT_MODE_SFP:
switch (phy_data->sfp_base) { switch (phy_data->sfp_base) {
...@@ -1583,24 +1590,24 @@ static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata) ...@@ -1583,24 +1590,24 @@ static unsigned int xgbe_phy_an_advertising(struct xgbe_prv_data *pdata)
case XGBE_SFP_BASE_1000_SX: case XGBE_SFP_BASE_1000_SX:
case XGBE_SFP_BASE_1000_LX: case XGBE_SFP_BASE_1000_LX:
case XGBE_SFP_BASE_1000_CX: case XGBE_SFP_BASE_1000_CX:
advertising |= ADVERTISED_1000baseKX_Full; XGBE_SET_ADV(dlks, 1000baseKX_Full);
break; break;
default: default:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
} }
break; break;
default: default:
advertising |= ADVERTISED_10000baseKR_Full; XGBE_SET_ADV(dlks, 10000baseKR_Full);
break; break;
} }
return advertising;
} }
static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
u32 advertising;
int ret; int ret;
ret = xgbe_phy_find_phy_device(pdata); ret = xgbe_phy_find_phy_device(pdata);
...@@ -1610,9 +1617,12 @@ static int xgbe_phy_an_config(struct xgbe_prv_data *pdata) ...@@ -1610,9 +1617,12 @@ static int xgbe_phy_an_config(struct xgbe_prv_data *pdata)
if (!phy_data->phydev) if (!phy_data->phydev)
return 0; return 0;
ethtool_convert_link_mode_to_legacy_u32(&advertising,
lks->link_modes.advertising);
phy_data->phydev->autoneg = pdata->phy.autoneg; phy_data->phydev->autoneg = pdata->phy.autoneg;
phy_data->phydev->advertising = phy_data->phydev->supported & phy_data->phydev->advertising = phy_data->phydev->supported &
pdata->phy.advertising; advertising;
if (pdata->phy.autoneg != AUTONEG_ENABLE) { if (pdata->phy.autoneg != AUTONEG_ENABLE) {
phy_data->phydev->speed = pdata->phy.speed; phy_data->phydev->speed = pdata->phy.speed;
...@@ -2073,11 +2083,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode) ...@@ -2073,11 +2083,10 @@ static void xgbe_phy_set_mode(struct xgbe_prv_data *pdata, enum xgbe_mode mode)
} }
static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode, u32 advert) enum xgbe_mode mode, bool advert)
{ {
if (pdata->phy.autoneg == AUTONEG_ENABLE) { if (pdata->phy.autoneg == AUTONEG_ENABLE) {
if (pdata->phy.advertising & advert) return advert;
return true;
} else { } else {
enum xgbe_mode cur_mode; enum xgbe_mode cur_mode;
...@@ -2092,13 +2101,15 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata, ...@@ -2092,13 +2101,15 @@ static bool xgbe_phy_check_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_X: case XGBE_MODE_X:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -2107,19 +2118,21 @@ static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata, ...@@ -2107,19 +2118,21 @@ static bool xgbe_phy_use_basex_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_100:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_100baseT_Full); XGBE_ADV(lks, 100baseT_Full));
case XGBE_MODE_SGMII_1000: case XGBE_MODE_SGMII_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseT_Full));
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseT_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseT_Full));
default: default:
return false; return false;
} }
...@@ -2128,6 +2141,7 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata, ...@@ -2128,6 +2141,7 @@ static bool xgbe_phy_use_baset_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data = pdata->phy_data; struct xgbe_phy_data *phy_data = pdata->phy_data;
switch (mode) { switch (mode) {
...@@ -2135,22 +2149,26 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, ...@@ -2135,22 +2149,26 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base == XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseX_Full));
case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_100:
if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_100baseT_Full); XGBE_ADV(lks, 100baseT_Full));
case XGBE_MODE_SGMII_1000: case XGBE_MODE_SGMII_1000:
if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T) if (phy_data->sfp_base != XGBE_SFP_BASE_1000_T)
return false; return false;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseT_Full); XGBE_ADV(lks, 1000baseT_Full));
case XGBE_MODE_SFI: case XGBE_MODE_SFI:
if (phy_data->sfp_mod_absent) if (phy_data->sfp_mod_absent)
return true; return true;
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseT_Full); XGBE_ADV(lks, 10000baseSR_Full) ||
XGBE_ADV(lks, 10000baseLR_Full) ||
XGBE_ADV(lks, 10000baseLRM_Full) ||
XGBE_ADV(lks, 10000baseER_Full) ||
XGBE_ADV(lks, 10000baseCR_Full));
default: default:
return false; return false;
} }
...@@ -2159,10 +2177,12 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata, ...@@ -2159,10 +2177,12 @@ static bool xgbe_phy_use_sfp_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_2500: case XGBE_MODE_KX_2500:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_2500baseX_Full); XGBE_ADV(lks, 2500baseX_Full));
default: default:
return false; return false;
} }
...@@ -2171,13 +2191,15 @@ static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata, ...@@ -2171,13 +2191,15 @@ static bool xgbe_phy_use_bp_2500_mode(struct xgbe_prv_data *pdata,
static bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata, static bool xgbe_phy_use_bp_mode(struct xgbe_prv_data *pdata,
enum xgbe_mode mode) enum xgbe_mode mode)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
switch (mode) { switch (mode) {
case XGBE_MODE_KX_1000: case XGBE_MODE_KX_1000:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_1000baseKX_Full); XGBE_ADV(lks, 1000baseKX_Full));
case XGBE_MODE_KR: case XGBE_MODE_KR:
return xgbe_phy_check_mode(pdata, mode, return xgbe_phy_check_mode(pdata, mode,
ADVERTISED_10000baseKR_Full); XGBE_ADV(lks, 10000baseKR_Full));
default: default:
return false; return false;
} }
...@@ -2744,6 +2766,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ...@@ -2744,6 +2766,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
static int xgbe_phy_init(struct xgbe_prv_data *pdata) static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{ {
struct ethtool_link_ksettings *lks = &pdata->phy.lks;
struct xgbe_phy_data *phy_data; struct xgbe_phy_data *phy_data;
struct mii_bus *mii; struct mii_bus *mii;
unsigned int reg; unsigned int reg;
...@@ -2823,32 +2846,33 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2823,32 +2846,33 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
phy_data->cur_mode = XGBE_MODE_UNKNOWN; phy_data->cur_mode = XGBE_MODE_UNKNOWN;
/* Initialize supported features */ /* Initialize supported features */
pdata->phy.supported = 0; XGBE_ZERO_SUP(lks);
switch (phy_data->port_mode) { switch (phy_data->port_mode) {
/* Backplane support */ /* Backplane support */
case XGBE_PORT_MODE_BACKPLANE: case XGBE_PORT_MODE_BACKPLANE:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, Backplane);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseKX_Full; XGBE_SET_SUP(lks, 1000baseKX_Full);
phy_data->start_mode = XGBE_MODE_KX_1000; phy_data->start_mode = XGBE_MODE_KX_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseKR_Full; XGBE_SET_SUP(lks, 10000baseKR_Full);
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= XGBE_SET_SUP(lks, 10000baseR_FEC);
SUPPORTED_10000baseR_FEC;
phy_data->start_mode = XGBE_MODE_KR; phy_data->start_mode = XGBE_MODE_KR;
} }
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
break; break;
case XGBE_PORT_MODE_BACKPLANE_2500: case XGBE_PORT_MODE_BACKPLANE_2500:
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_Backplane; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, Backplane);
XGBE_SET_SUP(lks, 2500baseX_Full);
phy_data->start_mode = XGBE_MODE_KX_2500; phy_data->start_mode = XGBE_MODE_KX_2500;
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
...@@ -2856,15 +2880,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2856,15 +2880,16 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO 1GBase-T support */ /* MDIO 1GBase-T support */
case XGBE_PORT_MODE_1000BASE_T: case XGBE_PORT_MODE_1000BASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
...@@ -2873,10 +2898,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2873,10 +2898,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO Base-X support */ /* MDIO Base-X support */
case XGBE_PORT_MODE_1000BASE_X: case XGBE_PORT_MODE_1000BASE_X:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, FIBRE);
XGBE_SET_SUP(lks, 1000baseX_Full);
phy_data->start_mode = XGBE_MODE_X; phy_data->start_mode = XGBE_MODE_X;
phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
...@@ -2884,19 +2910,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2884,19 +2910,20 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* MDIO NBase-T support */ /* MDIO NBase-T support */
case XGBE_PORT_MODE_NBASE_T: case XGBE_PORT_MODE_NBASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_2500) {
pdata->phy.supported |= SUPPORTED_2500baseX_Full; XGBE_SET_SUP(lks, 2500baseT_Full);
phy_data->start_mode = XGBE_MODE_KX_2500; phy_data->start_mode = XGBE_MODE_KX_2500;
} }
...@@ -2905,33 +2932,38 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2905,33 +2932,38 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* 10GBase-T support */ /* 10GBase-T support */
case XGBE_PORT_MODE_10GBASE_T: case XGBE_PORT_MODE_10GBASE_T:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) {
pdata->phy.supported |= SUPPORTED_100baseT_Full; XGBE_SET_SUP(lks, 100baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full; XGBE_SET_SUP(lks, 1000baseT_Full);
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} }
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) { if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseT_Full; XGBE_SET_SUP(lks, 10000baseT_Full);
phy_data->start_mode = XGBE_MODE_KR; phy_data->start_mode = XGBE_MODE_KR;
} }
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_CL45;
break; break;
/* 10GBase-R support */ /* 10GBase-R support */
case XGBE_PORT_MODE_10GBASE_R: case XGBE_PORT_MODE_10GBASE_R:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_10000baseT_Full; XGBE_SET_SUP(lks, FIBRE);
XGBE_SET_SUP(lks, 10000baseSR_Full);
XGBE_SET_SUP(lks, 10000baseLR_Full);
XGBE_SET_SUP(lks, 10000baseLRM_Full);
XGBE_SET_SUP(lks, 10000baseER_Full);
if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE)
pdata->phy.supported |= SUPPORTED_10000baseR_FEC; XGBE_SET_SUP(lks, 10000baseR_FEC);
phy_data->start_mode = XGBE_MODE_SFI; phy_data->start_mode = XGBE_MODE_SFI;
phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; phy_data->phydev_mode = XGBE_MDIO_MODE_NONE;
...@@ -2939,22 +2971,17 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2939,22 +2971,17 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
/* SFP support */ /* SFP support */
case XGBE_PORT_MODE_SFP: case XGBE_PORT_MODE_SFP:
pdata->phy.supported |= SUPPORTED_Autoneg; XGBE_SET_SUP(lks, Autoneg);
pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; XGBE_SET_SUP(lks, Pause);
pdata->phy.supported |= SUPPORTED_TP; XGBE_SET_SUP(lks, Asym_Pause);
pdata->phy.supported |= SUPPORTED_FIBRE; XGBE_SET_SUP(lks, TP);
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100) { XGBE_SET_SUP(lks, FIBRE);
pdata->phy.supported |= SUPPORTED_100baseT_Full; if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_100)
phy_data->start_mode = XGBE_MODE_SGMII_100; phy_data->start_mode = XGBE_MODE_SGMII_100;
} if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000)
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_1000) {
pdata->phy.supported |= SUPPORTED_1000baseT_Full;
phy_data->start_mode = XGBE_MODE_SGMII_1000; phy_data->start_mode = XGBE_MODE_SGMII_1000;
} if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000)
if (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10000) {
pdata->phy.supported |= SUPPORTED_10000baseT_Full;
phy_data->start_mode = XGBE_MODE_SFI; phy_data->start_mode = XGBE_MODE_SFI;
}
phy_data->phydev_mode = XGBE_MDIO_MODE_CL22; phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
...@@ -2965,8 +2992,9 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) ...@@ -2965,8 +2992,9 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
} }
if (netif_msg_probe(pdata)) if (netif_msg_probe(pdata))
dev_dbg(pdata->dev, "phy supported=%#x\n", dev_dbg(pdata->dev, "phy supported=0x%*pb\n",
pdata->phy.supported); __ETHTOOL_LINK_MODE_MASK_NBITS,
lks->link_modes.supported);
if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) && if ((phy_data->conn_type & XGBE_CONN_TYPE_MDIO) &&
(phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) { (phy_data->phydev_mode != XGBE_MDIO_MODE_NONE)) {
......
...@@ -130,6 +130,9 @@ ...@@ -130,6 +130,9 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/dcache.h>
#include <linux/ethtool.h>
#include <linux/list.h>
#define XGBE_DRV_NAME "amd-xgbe" #define XGBE_DRV_NAME "amd-xgbe"
#define XGBE_DRV_VERSION "1.0.3" #define XGBE_DRV_VERSION "1.0.3"
...@@ -181,8 +184,6 @@ ...@@ -181,8 +184,6 @@
#define XGBE_IRQ_MODE_EDGE 0 #define XGBE_IRQ_MODE_EDGE 0
#define XGBE_IRQ_MODE_LEVEL 1 #define XGBE_IRQ_MODE_LEVEL 1
#define XGBE_DMA_INTERRUPT_MASK 0x31c7
#define XGMAC_MIN_PACKET 60 #define XGMAC_MIN_PACKET 60
#define XGMAC_STD_PACKET_MTU 1500 #define XGMAC_STD_PACKET_MTU 1500
#define XGMAC_MAX_STD_PACKET 1518 #define XGMAC_MAX_STD_PACKET 1518
...@@ -297,6 +298,48 @@ ...@@ -297,6 +298,48 @@
/* MDIO port types */ /* MDIO port types */
#define XGMAC_MAX_C22_PORT 3 #define XGMAC_MAX_C22_PORT 3
/* Link mode bit operations */
#define XGBE_ZERO_SUP(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), supported)
#define XGBE_SET_SUP(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), supported, _mode)
#define XGBE_CLR_SUP(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), supported, _mode)
#define XGBE_IS_SUP(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), supported, _mode)
#define XGBE_ZERO_ADV(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), advertising)
#define XGBE_SET_ADV(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), advertising, _mode)
#define XGBE_CLR_ADV(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), advertising, _mode)
#define XGBE_ADV(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), advertising, _mode)
#define XGBE_ZERO_LP_ADV(_ls) \
ethtool_link_ksettings_zero_link_mode((_ls), lp_advertising)
#define XGBE_SET_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_add_link_mode((_ls), lp_advertising, _mode)
#define XGBE_CLR_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_del_link_mode((_ls), lp_advertising, _mode)
#define XGBE_LP_ADV(_ls, _mode) \
ethtool_link_ksettings_test_link_mode((_ls), lp_advertising, _mode)
#define XGBE_LM_COPY(_dst, _dname, _src, _sname) \
bitmap_copy((_dst)->link_modes._dname, \
(_src)->link_modes._sname, \
__ETHTOOL_LINK_MODE_MASK_NBITS)
struct xgbe_prv_data; struct xgbe_prv_data;
struct xgbe_packet_data { struct xgbe_packet_data {
...@@ -461,6 +504,8 @@ struct xgbe_channel { ...@@ -461,6 +504,8 @@ struct xgbe_channel {
/* Netdev related settings */ /* Netdev related settings */
struct napi_struct napi; struct napi_struct napi;
/* Per channel interrupt enablement tracker */
unsigned int curr_ier;
unsigned int saved_ier; unsigned int saved_ier;
unsigned int tx_timer_active; unsigned int tx_timer_active;
...@@ -562,9 +607,7 @@ enum xgbe_mdio_mode { ...@@ -562,9 +607,7 @@ enum xgbe_mdio_mode {
}; };
struct xgbe_phy { struct xgbe_phy {
u32 supported; struct ethtool_link_ksettings lks;
u32 advertising;
u32 lp_advertising;
int address; int address;
...@@ -667,6 +710,16 @@ struct xgbe_ext_stats { ...@@ -667,6 +710,16 @@ struct xgbe_ext_stats {
u64 tx_tso_packets; u64 tx_tso_packets;
u64 rx_split_header_packets; u64 rx_split_header_packets;
u64 rx_buffer_unavailable; u64 rx_buffer_unavailable;
u64 txq_packets[XGBE_MAX_DMA_CHANNELS];
u64 txq_bytes[XGBE_MAX_DMA_CHANNELS];
u64 rxq_packets[XGBE_MAX_DMA_CHANNELS];
u64 rxq_bytes[XGBE_MAX_DMA_CHANNELS];
u64 tx_vxlan_packets;
u64 rx_vxlan_packets;
u64 rx_csum_errors;
u64 rx_vxlan_csum_errors;
}; };
struct xgbe_hw_if { struct xgbe_hw_if {
...@@ -770,6 +823,11 @@ struct xgbe_hw_if { ...@@ -770,6 +823,11 @@ struct xgbe_hw_if {
/* For ECC */ /* For ECC */
void (*disable_ecc_ded)(struct xgbe_prv_data *); void (*disable_ecc_ded)(struct xgbe_prv_data *);
void (*disable_ecc_sec)(struct xgbe_prv_data *, enum xgbe_ecc_sec); void (*disable_ecc_sec)(struct xgbe_prv_data *, enum xgbe_ecc_sec);
/* For VXLAN */
void (*enable_vxlan)(struct xgbe_prv_data *);
void (*disable_vxlan)(struct xgbe_prv_data *);
void (*set_vxlan_id)(struct xgbe_prv_data *);
}; };
/* This structure represents implementation specific routines for an /* This structure represents implementation specific routines for an
...@@ -811,7 +869,8 @@ struct xgbe_phy_impl_if { ...@@ -811,7 +869,8 @@ struct xgbe_phy_impl_if {
int (*an_config)(struct xgbe_prv_data *); int (*an_config)(struct xgbe_prv_data *);
/* Set/override auto-negotiation advertisement settings */ /* Set/override auto-negotiation advertisement settings */
unsigned int (*an_advertising)(struct xgbe_prv_data *); void (*an_advertising)(struct xgbe_prv_data *,
struct ethtool_link_ksettings *);
/* Process results of auto-negotiation */ /* Process results of auto-negotiation */
enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *);
...@@ -893,6 +952,7 @@ struct xgbe_hw_features { ...@@ -893,6 +952,7 @@ struct xgbe_hw_features {
unsigned int addn_mac; /* Additional MAC Addresses */ unsigned int addn_mac; /* Additional MAC Addresses */
unsigned int ts_src; /* Timestamp Source */ unsigned int ts_src; /* Timestamp Source */
unsigned int sa_vlan_ins; /* Source Address or VLAN Insertion */ unsigned int sa_vlan_ins; /* Source Address or VLAN Insertion */
unsigned int vxn; /* VXLAN/NVGRE */
/* HW Feature Register1 */ /* HW Feature Register1 */
unsigned int rx_fifo_size; /* MTL Receive FIFO Size */ unsigned int rx_fifo_size; /* MTL Receive FIFO Size */
...@@ -931,6 +991,12 @@ struct xgbe_version_data { ...@@ -931,6 +991,12 @@ struct xgbe_version_data {
unsigned int rx_desc_prefetch; unsigned int rx_desc_prefetch;
}; };
struct xgbe_vxlan_data {
struct list_head list;
sa_family_t sa_family;
__be16 port;
};
struct xgbe_prv_data { struct xgbe_prv_data {
struct net_device *netdev; struct net_device *netdev;
struct pci_dev *pcidev; struct pci_dev *pcidev;
...@@ -1072,6 +1138,15 @@ struct xgbe_prv_data { ...@@ -1072,6 +1138,15 @@ struct xgbe_prv_data {
u32 rss_table[XGBE_RSS_MAX_TABLE_SIZE]; u32 rss_table[XGBE_RSS_MAX_TABLE_SIZE];
u32 rss_options; u32 rss_options;
/* VXLAN settings */
unsigned int vxlan_port_set;
unsigned int vxlan_offloads_set;
unsigned int vxlan_force_disable;
unsigned int vxlan_port_count;
struct list_head vxlan_ports;
u16 vxlan_port;
netdev_features_t vxlan_features;
/* Netdev related settings */ /* Netdev related settings */
unsigned char mac_addr[ETH_ALEN]; unsigned char mac_addr[ETH_ALEN];
netdev_features_t netdev_features; netdev_features_t netdev_features;
...@@ -1172,7 +1247,6 @@ struct xgbe_prv_data { ...@@ -1172,7 +1247,6 @@ struct xgbe_prv_data {
struct tasklet_struct tasklet_i2c; struct tasklet_struct tasklet_i2c;
struct tasklet_struct tasklet_an; struct tasklet_struct tasklet_an;
#ifdef CONFIG_DEBUG_FS
struct dentry *xgbe_debugfs; struct dentry *xgbe_debugfs;
unsigned int debugfs_xgmac_reg; unsigned int debugfs_xgmac_reg;
...@@ -1183,7 +1257,6 @@ struct xgbe_prv_data { ...@@ -1183,7 +1257,6 @@ struct xgbe_prv_data {
unsigned int debugfs_xprop_reg; unsigned int debugfs_xprop_reg;
unsigned int debugfs_xi2c_reg; unsigned int debugfs_xi2c_reg;
#endif
}; };
/* Function prototypes*/ /* Function prototypes*/
...@@ -1232,9 +1305,11 @@ void xgbe_init_tx_coalesce(struct xgbe_prv_data *); ...@@ -1232,9 +1305,11 @@ void xgbe_init_tx_coalesce(struct xgbe_prv_data *);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void xgbe_debugfs_init(struct xgbe_prv_data *); void xgbe_debugfs_init(struct xgbe_prv_data *);
void xgbe_debugfs_exit(struct xgbe_prv_data *); void xgbe_debugfs_exit(struct xgbe_prv_data *);
void xgbe_debugfs_rename(struct xgbe_prv_data *pdata);
#else #else
static inline void xgbe_debugfs_init(struct xgbe_prv_data *pdata) {} static inline void xgbe_debugfs_init(struct xgbe_prv_data *pdata) {}
static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {} static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {}
static inline void xgbe_debugfs_rename(struct xgbe_prv_data *pdata) {}
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
/* NOTE: Uncomment for function trace log messages in KERNEL LOG */ /* NOTE: Uncomment for function trace log messages in KERNEL LOG */
......
...@@ -136,6 +136,17 @@ struct ethtool_link_ksettings { ...@@ -136,6 +136,17 @@ struct ethtool_link_ksettings {
#define ethtool_link_ksettings_add_link_mode(ptr, name, mode) \ #define ethtool_link_ksettings_add_link_mode(ptr, name, mode) \
__set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name) __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
/**
* ethtool_link_ksettings_del_link_mode - clear bit in link_ksettings
* link mode mask
* @ptr : pointer to struct ethtool_link_ksettings
* @name : one of supported/advertising/lp_advertising
* @mode : one of the ETHTOOL_LINK_MODE_*_BIT
* (not atomic, no bound checking)
*/
#define ethtool_link_ksettings_del_link_mode(ptr, name, mode) \
__clear_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
/** /**
* ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask * ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask
* @ptr : pointer to struct ethtool_link_ksettings * @ptr : pointer to struct ethtool_link_ksettings
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment