#include <linux/phy.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/iopoll.h>
#include "xilinx_axienet.h"
{}
};
+/* Option table for setting up Axi Ethernet hardware options */
+static struct xxvenet_option xxvenet_options[] = {
+ { /* Turn on FCS stripping on receive packets */
+ .opt = XAE_OPTION_FCS_STRIP,
+ .reg = XXV_RCW1_OFFSET,
+ .m_or = XXV_RCW1_FCS_MASK,
+ }, { /* Turn on FCS insertion on transmit packets */
+ .opt = XAE_OPTION_FCS_INSERT,
+ .reg = XXV_TC_OFFSET,
+ .m_or = XXV_TC_FCS_MASK,
+ }, { /* Enable transmitter */
+ .opt = XAE_OPTION_TXEN,
+ .reg = XXV_TC_OFFSET,
+ .m_or = XXV_TC_TX_MASK,
+ }, { /* Enable receiver */
+ .opt = XAE_OPTION_RXEN,
+ .reg = XXV_RCW1_OFFSET,
+ .m_or = XXV_RCW1_RX_MASK,
+ },
+ {}
+};
+
/**
* axienet_dma_in32 - Memory mapped Axi DMA register read
* @lp: Pointer to axienet local structure
lp->options |= options;
}
+static void xxvenet_setoptions(struct net_device *ndev, u32 options)
+{
+ int reg;
+ struct axienet_local *lp = netdev_priv(ndev);
+ struct xxvenet_option *tp = &xxvenet_options[0];
+
+ while (tp->opt) {
+ reg = ((axienet_ior(lp, tp->reg)) & ~(tp->m_or));
+ if (options & tp->opt)
+ reg |= tp->m_or;
+ axienet_iow(lp, tp->reg, reg);
+ tp++;
+ }
+
+ lp->options |= options;
+}
+
static void __axienet_device_reset(struct axienet_local *lp, off_t offset)
{
u32 timeout;
{
u32 axienet_status;
struct axienet_local *lp = netdev_priv(ndev);
+ u32 err, val;
__axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
__axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
- lp->options |= XAE_OPTION_VLAN;
- lp->options &= (~XAE_OPTION_JUMBO);
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G) {
+ lp->options |= XAE_OPTION_VLAN;
+ lp->options &= (~XAE_OPTION_JUMBO);
+ }
if ((ndev->mtu > XAE_MTU) &&
(ndev->mtu <= XAE_JUMBO_MTU)) {
lp->max_frm_size = ndev->mtu + VLAN_ETH_HLEN +
XAE_TRL_SIZE;
-
- if (lp->max_frm_size <= lp->rxmem)
+ if (lp->max_frm_size <= lp->rxmem &&
+ (lp->axienet_config->mactype != XAXIENET_10G_25G))
lp->options |= XAE_OPTION_JUMBO;
}
__func__);
}
- axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
- axienet_status &= ~XAE_RCW1_RX_MASK;
- axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G) {
+ axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
+ axienet_status &= ~XAE_RCW1_RX_MASK;
+ axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
+ }
+
+ if (lp->axienet_config->mactype == XAXIENET_10G_25G) {
+ /* Check for block lock bit got set or not
+ * This ensures that 10G ethernet IP
+ * is functioning normally or not.
+ */
+ err = readl_poll_timeout(lp->regs + XXV_STATRX_BLKLCK_OFFSET,
+ val, (val & XXV_RX_BLKLCK_MASK),
+ 10, DELAY_OF_ONE_MILLISEC);
+ if (err) {
+ netdev_err(ndev, "%s: Block lock bit of XXV MAC didn't",
+ __func__);
+ netdev_err(ndev, "Got Set cross check the ref clock");
+ netdev_err(ndev, "Configuration for the mac");
+ }
+ }
- if (!lp->eth_hasnobuf) {
+ if ((lp->axienet_config->mactype == XAXIENET_1G) &&
+ !lp->eth_hasnobuf) {
axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
if (axienet_status & XAE_INT_RXRJECT_MASK)
axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
}
- axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+ if (lp->axienet_config->mactype == XAXIENET_10G_25G) {
+ lp->options |= XAE_OPTION_FCS_STRIP;
+ lp->options |= XAE_OPTION_FCS_INSERT;
+ } else {
+ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+ }
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
- /* Sync default options with HW but leave receiver and
- * transmitter disabled.
- */
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
axienet_set_multicast_list(ndev);
- axienet_setoptions(ndev, lp->options);
+ lp->axienet_config->setoptions(ndev, lp->options);
netif_trans_update(ndev);
}
struct axienet_local *lp = netdev_priv(ndev);
struct axidma_bd *cur_p;
unsigned long flags;
+ u32 pad = 0;
num_frag = skb_shinfo(skb)->nr_frags;
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
return NETDEV_TX_BUSY;
}
+ /* Work around for XXV MAC as MAC will drop the packets
+ * of size less than 64 bytes we need to append data
+ * to make packet length greater than or equal to 64
+ */
+ if (skb->len < XXV_MAC_MIN_PKT_LEN &&
+ (lp->axienet_config->mactype == XAXIENET_10G_25G))
+ pad = XXV_MAC_MIN_PKT_LEN - skb->len;
+
if (skb->ip_summed == CHECKSUM_PARTIAL && !lp->eth_hasnobuf &&
(lp->axienet_config->mactype == XAXIENET_1G)) {
if (lp->features & XAE_FEATURE_FULL_TX_CSUM) {
cur_p->app0 |= 2; /* Tx Full Checksum Offload Enabled */
}
- cur_p->cntrl = skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK;
+ cur_p->cntrl = (skb_headlen(skb) | XAXIDMA_BD_CTRL_TXSOF_MASK) + pad;
cur_p->phys = dma_map_single(ndev->dev.parent, skb->data,
skb_headlen(skb), DMA_TO_DEVICE);
skb_frag_address(frag),
skb_frag_size(frag),
DMA_TO_DEVICE);
- cur_p->cntrl = skb_frag_size(frag);
+ cur_p->cntrl = skb_frag_size(frag) + pad;
}
cur_p->cntrl |= XAXIDMA_BD_CTRL_TXEOF_MASK;
static void axienet_dma_err_handler(unsigned long data);
+static int axienet_mii_init(struct net_device *ndev)
+{
+ struct axienet_local *lp = netdev_priv(ndev);
+ int ret, mdio_mcreg;
+
+ mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
+ ret = axienet_mdio_wait_until_ready(lp);
+ if (ret < 0)
+ return ret;
+
+ /* Disable the MDIO interface till Axi Ethernet Reset is completed.
+ * When we do an Axi Ethernet reset, it resets the complete core
+ * Including the MDIO. If MDIO is not disabled when the reset process is
+ * Started, MDIO will be broken afterwards.
+ */
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET,
+ (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
+ axienet_device_reset(ndev);
+ /* Enable the MDIO */
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
+ ret = axienet_mdio_wait_until_ready(lp);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
/**
* axienet_open - Driver open routine.
* @ndev: Pointer to net_device structure
*/
static int axienet_open(struct net_device *ndev)
{
- int ret, mdio_mcreg;
+ int ret = 0;
struct axienet_local *lp = netdev_priv(ndev);
struct phy_device *phydev = NULL;
dev_dbg(&ndev->dev, "axienet_open()\n");
- mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
- ret = axienet_mdio_wait_until_ready(lp);
- if (ret < 0)
- return ret;
- /* Disable the MDIO interface till Axi Ethernet Reset is completed.
- * When we do an Axi Ethernet reset, it resets the complete core
- * including the MDIO. If MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards.
- */
- axienet_iow(lp, XAE_MDIO_MC_OFFSET,
- (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK)));
- axienet_device_reset(ndev);
- /* Enable the MDIO */
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
- ret = axienet_mdio_wait_until_ready(lp);
+ if (lp->axienet_config->mactype == XAXIENET_10G_25G)
+ axienet_device_reset(ndev);
+ else
+ ret = axienet_mii_init(ndev);
if (ret < 0)
return ret;
cr = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
cr & (~XAXIDMA_CR_RUNSTOP_MASK));
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
napi_disable(&lp->napi);
tasklet_kill(&lp->dma_err_tasklet);
struct net_device *ndev = lp->ndev;
struct axidma_bd *cur_p;
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
- mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
- axienet_mdio_wait_until_ready(lp);
- /* Disable the MDIO interface till Axi Ethernet Reset is completed.
- * When we do an Axi Ethernet reset, it resets the complete core
- * including the MDIO. So if MDIO is not disabled when the reset
- * process is started, MDIO will be broken afterwards.
- */
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
- ~XAE_MDIO_MC_MDIOEN_MASK));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G) {
+ mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
+ axienet_mdio_wait_until_ready(lp);
+ /* Disable the MDIO interface till Axi Ethernet Reset is
+ * Completed. When we do an Axi Ethernet reset, it resets the
+ * Complete core including the MDIO. So if MDIO is not disabled
+ * When the reset process is started,
+ * MDIO will be broken afterwards.
+ */
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg &
+ ~XAE_MDIO_MC_MDIOEN_MASK));
+ }
__axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET);
__axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET);
- axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
- axienet_mdio_wait_until_ready(lp);
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G) {
+ axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg);
+ axienet_mdio_wait_until_ready(lp);
+ }
for (i = 0; i < TX_BD_NUM; i++) {
cur_p = &lp->tx_bd_v[i];
axienet_dma_out32(lp, XAXIDMA_TX_CR_OFFSET,
cr | XAXIDMA_CR_RUNSTOP_MASK);
- axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
- axienet_status &= ~XAE_RCW1_RX_MASK;
- axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G) {
+ axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
+ axienet_status &= ~XAE_RCW1_RX_MASK;
+ axienet_iow(lp, XAE_RCW1_OFFSET, axienet_status);
+ }
- if (!lp->eth_hasnobuf) {
+ if ((lp->axienet_config->mactype == XAXIENET_1G) && !lp->eth_hasnobuf) {
axienet_status = axienet_ior(lp, XAE_IP_OFFSET);
if (axienet_status & XAE_INT_RXRJECT_MASK)
axienet_iow(lp, XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
}
- axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
+ if (lp->axienet_config->mactype != XAXIENET_10G_25G)
+ axienet_iow(lp, XAE_FCC_OFFSET, XAE_FCC_FCRX_MASK);
- /* Sync default options with HW but leave receiver and
- * transmitter disabled.
- */
- axienet_setoptions(ndev, lp->options &
- ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
+ lp->axienet_config->setoptions(ndev, lp->options &
+ ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
axienet_set_mac_address(ndev, NULL);
axienet_set_multicast_list(ndev);
- axienet_setoptions(ndev, lp->options);
+ lp->axienet_config->setoptions(ndev, lp->options);
}
static const struct axienet_config axienet_1g_config = {
.setoptions = axienet_setoptions,
};
+static const struct axienet_config axienet_10g25g_config = {
+ .mactype = XAXIENET_10G_25G,
+ .setoptions = xxvenet_setoptions,
+};
+
/* Match table for of_platform binding */
static const struct of_device_id axienet_of_match[] = {
{ .compatible = "xlnx,axi-ethernet-1.00.a", .data = &axienet_1g_config},
{ .compatible = "xlnx,axi-2_5-gig-ethernet-1.0",
.data = &axienet_2_5g_config},
{ .compatible = "xlnx,ten-gig-eth-mac", .data = &axienet_10g_config},
+ { .compatible = "xlnx,xxv-ethernet-1.0",
+ .data = &axienet_10g25g_config},
{},
};