Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/cadence/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 149 kB image not shown  

Quelle  macb_main.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Cadence MACB/GEM Ethernet Controller driver
 *
 * Copyright (C) 2004-2006 Atmel Corporation
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/crc32.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/circ_buf.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/phylink.h>
#include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/iopoll.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/ptp_classify.h>
#include <linux/reset.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/inetdevice.h>
#include "macb.h"

/* This structure is only used for MACB on SiFive FU540 devices */
struct sifive_fu540_macb_mgmt {
 void __iomem *reg;
 unsigned long rate;
 struct clk_hw hw;
};

#define MACB_RX_BUFFER_SIZE 128
#define RX_BUFFER_MULTIPLE 64  /* bytes */

#define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */
#define MIN_RX_RING_SIZE 64
#define MAX_RX_RING_SIZE 8192

#define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */
#define MIN_TX_RING_SIZE 64
#define MAX_TX_RING_SIZE 4096

/* level of occupied TX descriptors under which we wake up TX process */
#define MACB_TX_WAKEUP_THRESH(bp) (3 * (bp)->tx_ring_size / 4)

#define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(ISR_ROVR))
#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND)   \
     | MACB_BIT(ISR_RLE)  \
     | MACB_BIT(TXERR))
#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP) \
     | MACB_BIT(TXUBR))

/* Max length of transmit frame must be a multiple of 8 bytes */
#define MACB_TX_LEN_ALIGN 8
#define MACB_MAX_TX_LEN  ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))
/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a
 * false amba_error in TX path from the DMA assuming there is not enough
 * space in the SRAM (16KB) even when there is.
 */

#define GEM_MAX_TX_LEN  (unsigned int)(0x3FC0)

#define GEM_MTU_MIN_SIZE ETH_MIN_MTU
#define MACB_NETIF_LSO  NETIF_F_TSO

#define MACB_WOL_ENABLED  BIT(0)

#define HS_SPEED_10000M   4
#define MACB_SERDES_RATE_10G  1

/* Graceful stop timeouts in us. We should allow up to
 * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
 */

#define MACB_HALT_TIMEOUT 14000
#define MACB_PM_TIMEOUT  100 /* ms */

#define MACB_MDIO_TIMEOUT 1000000 /* in usecs */

/* DMA buffer descriptor might be different size
 * depends on hardware configuration:
 *
 * 1. dma address width 32 bits:
 *    word 1: 32 bit address of Data Buffer
 *    word 2: control
 *
 * 2. dma address width 64 bits:
 *    word 1: 32 bit address of Data Buffer
 *    word 2: control
 *    word 3: upper 32 bit address of Data Buffer
 *    word 4: unused
 *
 * 3. dma address width 32 bits with hardware timestamping:
 *    word 1: 32 bit address of Data Buffer
 *    word 2: control
 *    word 3: timestamp word 1
 *    word 4: timestamp word 2
 *
 * 4. dma address width 64 bits with hardware timestamping:
 *    word 1: 32 bit address of Data Buffer
 *    word 2: control
 *    word 3: upper 32 bit address of Data Buffer
 *    word 4: unused
 *    word 5: timestamp word 1
 *    word 6: timestamp word 2
 */

static unsigned int macb_dma_desc_get_size(struct macb *bp)
{
#ifdef MACB_EXT_DESC
 unsigned int desc_size;

 switch (bp->hw_dma_cap) {
 case HW_DMA_CAP_64B:
  desc_size = sizeof(struct macb_dma_desc)
   + sizeof(struct macb_dma_desc_64);
  break;
 case HW_DMA_CAP_PTP:
  desc_size = sizeof(struct macb_dma_desc)
   + sizeof(struct macb_dma_desc_ptp);
  break;
 case HW_DMA_CAP_64B_PTP:
  desc_size = sizeof(struct macb_dma_desc)
   + sizeof(struct macb_dma_desc_64)
   + sizeof(struct macb_dma_desc_ptp);
  break;
 default:
  desc_size = sizeof(struct macb_dma_desc);
 }
 return desc_size;
#endif
 return sizeof(struct macb_dma_desc);
}

static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int desc_idx)
{
#ifdef MACB_EXT_DESC
 switch (bp->hw_dma_cap) {
 case HW_DMA_CAP_64B:
 case HW_DMA_CAP_PTP:
  desc_idx <<= 1;
  break;
 case HW_DMA_CAP_64B_PTP:
  desc_idx *= 3;
  break;
 default:
  break;
 }
#endif
 return desc_idx;
}

#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc)
{
 return (struct macb_dma_desc_64 *)((void *)desc
  + sizeof(struct macb_dma_desc));
}
#endif

/* Ring buffer accessors */
static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
{
 return index & (bp->tx_ring_size - 1);
}

static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue,
       unsigned int index)
{
 index = macb_tx_ring_wrap(queue->bp, index);
 index = macb_adj_dma_desc_idx(queue->bp, index);
 return &queue->tx_ring[index];
}

static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue,
           unsigned int index)
{
 return &queue->tx_skb[macb_tx_ring_wrap(queue->bp, index)];
}

static dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index)
{
 dma_addr_t offset;

 offset = macb_tx_ring_wrap(queue->bp, index) *
   macb_dma_desc_get_size(queue->bp);

 return queue->tx_ring_dma + offset;
}

static unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index)
{
 return index & (bp->rx_ring_size - 1);
}

static struct macb_dma_desc *macb_rx_desc(struct macb_queue *queue, unsigned int index)
{
 index = macb_rx_ring_wrap(queue->bp, index);
 index = macb_adj_dma_desc_idx(queue->bp, index);
 return &queue->rx_ring[index];
}

static void *macb_rx_buffer(struct macb_queue *queue, unsigned int index)
{
 return queue->rx_buffers + queue->bp->rx_buffer_size *
        macb_rx_ring_wrap(queue->bp, index);
}

/* I/O accessors */
static u32 hw_readl_native(struct macb *bp, int offset)
{
 return __raw_readl(bp->regs + offset);
}

static void hw_writel_native(struct macb *bp, int offset, u32 value)
{
 __raw_writel(value, bp->regs + offset);
}

static u32 hw_readl(struct macb *bp, int offset)
{
 return readl_relaxed(bp->regs + offset);
}

static void hw_writel(struct macb *bp, int offset, u32 value)
{
 writel_relaxed(value, bp->regs + offset);
}

/* Find the CPU endianness by using the loopback bit of NCR register. When the
 * CPU is in big endian we need to program swapped mode for management
 * descriptor access.
 */

static bool hw_is_native_io(void __iomem *addr)
{
 u32 value = MACB_BIT(LLB);

 __raw_writel(value, addr + MACB_NCR);
 value = __raw_readl(addr + MACB_NCR);

 /* Write 0 back to disable everything */
 __raw_writel(0, addr + MACB_NCR);

 return value == MACB_BIT(LLB);
}

static bool hw_is_gem(void __iomem *addr, bool native_io)
{
 u32 id;

 if (native_io)
  id = __raw_readl(addr + MACB_MID);
 else
  id = readl_relaxed(addr + MACB_MID);

 return MACB_BFEXT(IDNUM, id) >= 0x2;
}

static void macb_set_hwaddr(struct macb *bp)
{
 u32 bottom;
 u16 top;

 bottom = get_unaligned_le32(bp->dev->dev_addr);
 macb_or_gem_writel(bp, SA1B, bottom);
 top = get_unaligned_le16(bp->dev->dev_addr + 4);
 macb_or_gem_writel(bp, SA1T, top);

 if (gem_has_ptp(bp)) {
  gem_writel(bp, RXPTPUNI, bottom);
  gem_writel(bp, TXPTPUNI, bottom);
 }

 /* Clear unused address register sets */
 macb_or_gem_writel(bp, SA2B, 0);
 macb_or_gem_writel(bp, SA2T, 0);
 macb_or_gem_writel(bp, SA3B, 0);
 macb_or_gem_writel(bp, SA3T, 0);
 macb_or_gem_writel(bp, SA4B, 0);
 macb_or_gem_writel(bp, SA4T, 0);
}

static void macb_get_hwaddr(struct macb *bp)
{
 u32 bottom;
 u16 top;
 u8 addr[6];
 int i;

 /* Check all 4 address register for valid address */
 for (i = 0; i < 4; i++) {
  bottom = macb_or_gem_readl(bp, SA1B + i * 8);
  top = macb_or_gem_readl(bp, SA1T + i * 8);

  addr[0] = bottom & 0xff;
  addr[1] = (bottom >> 8) & 0xff;
  addr[2] = (bottom >> 16) & 0xff;
  addr[3] = (bottom >> 24) & 0xff;
  addr[4] = top & 0xff;
  addr[5] = (top >> 8) & 0xff;

  if (is_valid_ether_addr(addr)) {
   eth_hw_addr_set(bp->dev, addr);
   return;
  }
 }

 dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
 eth_hw_addr_random(bp->dev);
}

static int macb_mdio_wait_for_idle(struct macb *bp)
{
 u32 val;

 return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE),
      1, MACB_MDIO_TIMEOUT);
}

static int macb_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
{
 struct macb *bp = bus->priv;
 int status;

 status = pm_runtime_resume_and_get(&bp->pdev->dev);
 if (status < 0)
  goto mdio_pm_exit;

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_read_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
         | MACB_BF(RW, MACB_MAN_C22_READ)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, regnum)
         | MACB_BF(CODE, MACB_MAN_C22_CODE)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_read_exit;

 status = MACB_BFEXT(DATA, macb_readl(bp, MAN));

mdio_read_exit:
 pm_runtime_mark_last_busy(&bp->pdev->dev);
 pm_runtime_put_autosuspend(&bp->pdev->dev);
mdio_pm_exit:
 return status;
}

static int macb_mdio_read_c45(struct mii_bus *bus, int mii_id, int devad,
         int regnum)
{
 struct macb *bp = bus->priv;
 int status;

 status = pm_runtime_get_sync(&bp->pdev->dev);
 if (status < 0) {
  pm_runtime_put_noidle(&bp->pdev->dev);
  goto mdio_pm_exit;
 }

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_read_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
         | MACB_BF(RW, MACB_MAN_C45_ADDR)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, devad & 0x1F)
         | MACB_BF(DATA, regnum & 0xFFFF)
         | MACB_BF(CODE, MACB_MAN_C45_CODE)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_read_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
         | MACB_BF(RW, MACB_MAN_C45_READ)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, devad & 0x1F)
         | MACB_BF(CODE, MACB_MAN_C45_CODE)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_read_exit;

 status = MACB_BFEXT(DATA, macb_readl(bp, MAN));

mdio_read_exit:
 pm_runtime_mark_last_busy(&bp->pdev->dev);
 pm_runtime_put_autosuspend(&bp->pdev->dev);
mdio_pm_exit:
 return status;
}

static int macb_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
          u16 value)
{
 struct macb *bp = bus->priv;
 int status;

 status = pm_runtime_resume_and_get(&bp->pdev->dev);
 if (status < 0)
  goto mdio_pm_exit;

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_write_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C22_SOF)
         | MACB_BF(RW, MACB_MAN_C22_WRITE)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, regnum)
         | MACB_BF(CODE, MACB_MAN_C22_CODE)
         | MACB_BF(DATA, value)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_write_exit;

mdio_write_exit:
 pm_runtime_mark_last_busy(&bp->pdev->dev);
 pm_runtime_put_autosuspend(&bp->pdev->dev);
mdio_pm_exit:
 return status;
}

static int macb_mdio_write_c45(struct mii_bus *bus, int mii_id,
          int devad, int regnum,
          u16 value)
{
 struct macb *bp = bus->priv;
 int status;

 status = pm_runtime_get_sync(&bp->pdev->dev);
 if (status < 0) {
  pm_runtime_put_noidle(&bp->pdev->dev);
  goto mdio_pm_exit;
 }

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_write_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
         | MACB_BF(RW, MACB_MAN_C45_ADDR)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, devad & 0x1F)
         | MACB_BF(DATA, regnum & 0xFFFF)
         | MACB_BF(CODE, MACB_MAN_C45_CODE)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_write_exit;

 macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_C45_SOF)
         | MACB_BF(RW, MACB_MAN_C45_WRITE)
         | MACB_BF(PHYA, mii_id)
         | MACB_BF(REGA, devad & 0x1F)
         | MACB_BF(CODE, MACB_MAN_C45_CODE)
         | MACB_BF(DATA, value)));

 status = macb_mdio_wait_for_idle(bp);
 if (status < 0)
  goto mdio_write_exit;

mdio_write_exit:
 pm_runtime_mark_last_busy(&bp->pdev->dev);
 pm_runtime_put_autosuspend(&bp->pdev->dev);
mdio_pm_exit:
 return status;
}

static void macb_init_buffers(struct macb *bp)
{
 struct macb_queue *queue;
 unsigned int q;

#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 /* Single register for all queues' high 32 bits. */
 if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
  macb_writel(bp, RBQPH,
       upper_32_bits(bp->queues[0].rx_ring_dma));
  macb_writel(bp, TBQPH,
       upper_32_bits(bp->queues[0].tx_ring_dma));
 }
#endif

 for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
  queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma));
  queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
 }
}

/**
 * macb_set_tx_clk() - Set a clock to a new frequency
 * @bp: pointer to struct macb
 * @speed: New frequency in Hz
 */

static void macb_set_tx_clk(struct macb *bp, int speed)
{
 long ferr, rate, rate_rounded;

 if (!bp->tx_clk || (bp->caps & MACB_CAPS_CLK_HW_CHG))
  return;

 /* In case of MII the PHY is the clock master */
 if (bp->phy_interface == PHY_INTERFACE_MODE_MII)
  return;

 rate = rgmii_clock(speed);
 if (rate < 0)
  return;

 rate_rounded = clk_round_rate(bp->tx_clk, rate);
 if (rate_rounded < 0)
  return;

 /* RGMII allows 50 ppm frequency error. Test and warn if this limit
 * is not satisfied.
 */

 ferr = abs(rate_rounded - rate);
 ferr = DIV_ROUND_UP(ferr, rate / 100000);
 if (ferr > 5)
  netdev_warn(bp->dev,
       "unable to generate target frequency: %ld Hz\n",
       rate);

 if (clk_set_rate(bp->tx_clk, rate_rounded))
  netdev_err(bp->dev, "adjusting tx_clk failed.\n");
}

static void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
     phy_interface_t interface, int speed,
     int duplex)
{
 struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);
 u32 config;

 config = gem_readl(bp, USX_CONTROL);
 config = GEM_BFINS(SERDES_RATE, MACB_SERDES_RATE_10G, config);
 config = GEM_BFINS(USX_CTRL_SPEED, HS_SPEED_10000M, config);
 config &= ~(GEM_BIT(TX_SCR_BYPASS) | GEM_BIT(RX_SCR_BYPASS));
 config |= GEM_BIT(TX_EN);
 gem_writel(bp, USX_CONTROL, config);
}

static void macb_usx_pcs_get_state(struct phylink_pcs *pcs,
       unsigned int neg_mode,
       struct phylink_link_state *state)
{
 struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);
 u32 val;

 state->speed = SPEED_10000;
 state->duplex = 1;
 state->an_complete = 1;

 val = gem_readl(bp, USX_STATUS);
 state->link = !!(val & GEM_BIT(USX_BLOCK_LOCK));
 val = gem_readl(bp, NCFGR);
 if (val & GEM_BIT(PAE))
  state->pause = MLO_PAUSE_RX;
}

static int macb_usx_pcs_config(struct phylink_pcs *pcs,
          unsigned int neg_mode,
          phy_interface_t interface,
          const unsigned long *advertising,
          bool permit_pause_to_mac)
{
 struct macb *bp = container_of(pcs, struct macb, phylink_usx_pcs);

 gem_writel(bp, USX_CONTROL, gem_readl(bp, USX_CONTROL) |
     GEM_BIT(SIGNAL_OK));

 return 0;
}

static void macb_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
          struct phylink_link_state *state)
{
 state->link = 0;
}

static void macb_pcs_an_restart(struct phylink_pcs *pcs)
{
 /* Not supported */
}

static int macb_pcs_config(struct phylink_pcs *pcs,
      unsigned int neg_mode,
      phy_interface_t interface,
      const unsigned long *advertising,
      bool permit_pause_to_mac)
{
 return 0;
}

static const struct phylink_pcs_ops macb_phylink_usx_pcs_ops = {
 .pcs_get_state = macb_usx_pcs_get_state,
 .pcs_config = macb_usx_pcs_config,
 .pcs_link_up = macb_usx_pcs_link_up,
};

static const struct phylink_pcs_ops macb_phylink_pcs_ops = {
 .pcs_get_state = macb_pcs_get_state,
 .pcs_an_restart = macb_pcs_an_restart,
 .pcs_config = macb_pcs_config,
};

static void macb_mac_config(struct phylink_config *config, unsigned int mode,
       const struct phylink_link_state *state)
{
 struct net_device *ndev = to_net_dev(config->dev);
 struct macb *bp = netdev_priv(ndev);
 unsigned long flags;
 u32 old_ctrl, ctrl;
 u32 old_ncr, ncr;

 spin_lock_irqsave(&bp->lock, flags);

 old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR);
 old_ncr = ncr = macb_or_gem_readl(bp, NCR);

 if (bp->caps & MACB_CAPS_MACB_IS_EMAC) {
  if (state->interface == PHY_INTERFACE_MODE_RMII)
   ctrl |= MACB_BIT(RM9200_RMII);
 } else if (macb_is_gem(bp)) {
  ctrl &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL));
  ncr &= ~GEM_BIT(ENABLE_HS_MAC);

  if (state->interface == PHY_INTERFACE_MODE_SGMII) {
   ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
  } else if (state->interface == PHY_INTERFACE_MODE_10GBASER) {
   ctrl |= GEM_BIT(PCSSEL);
   ncr |= GEM_BIT(ENABLE_HS_MAC);
  } else if (bp->caps & MACB_CAPS_MIIONRGMII &&
      bp->phy_interface == PHY_INTERFACE_MODE_MII) {
   ncr |= MACB_BIT(MIIONRGMII);
  }
 }

 /* Apply the new configuration, if any */
 if (old_ctrl ^ ctrl)
  macb_or_gem_writel(bp, NCFGR, ctrl);

 if (old_ncr ^ ncr)
  macb_or_gem_writel(bp, NCR, ncr);

 /* Disable AN for SGMII fixed link configuration, enable otherwise.
 * Must be written after PCSSEL is set in NCFGR,
 * otherwise writes will not take effect.
 */

 if (macb_is_gem(bp) && state->interface == PHY_INTERFACE_MODE_SGMII) {
  u32 pcsctrl, old_pcsctrl;

  old_pcsctrl = gem_readl(bp, PCSCNTRL);
  if (mode == MLO_AN_FIXED)
   pcsctrl = old_pcsctrl & ~GEM_BIT(PCSAUTONEG);
  else
   pcsctrl = old_pcsctrl | GEM_BIT(PCSAUTONEG);
  if (old_pcsctrl != pcsctrl)
   gem_writel(bp, PCSCNTRL, pcsctrl);
 }

 spin_unlock_irqrestore(&bp->lock, flags);
}

static void macb_mac_link_down(struct phylink_config *config, unsigned int mode,
          phy_interface_t interface)
{
 struct net_device *ndev = to_net_dev(config->dev);
 struct macb *bp = netdev_priv(ndev);
 struct macb_queue *queue;
 unsigned int q;
 u32 ctrl;

 if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
  for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
   queue_writel(queue, IDR,
         bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));

 /* Disable Rx and Tx */
 ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE));
 macb_writel(bp, NCR, ctrl);

 netif_tx_stop_all_queues(ndev);
}

static void macb_mac_link_up(struct phylink_config *config,
        struct phy_device *phy,
        unsigned int mode, phy_interface_t interface,
        int speed, int duplex,
        bool tx_pause, bool rx_pause)
{
 struct net_device *ndev = to_net_dev(config->dev);
 struct macb *bp = netdev_priv(ndev);
 struct macb_queue *queue;
 unsigned long flags;
 unsigned int q;
 u32 ctrl;

 spin_lock_irqsave(&bp->lock, flags);

 ctrl = macb_or_gem_readl(bp, NCFGR);

 ctrl &= ~(MACB_BIT(SPD) | MACB_BIT(FD));

 if (speed == SPEED_100)
  ctrl |= MACB_BIT(SPD);

 if (duplex)
  ctrl |= MACB_BIT(FD);

 if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
  ctrl &= ~MACB_BIT(PAE);
  if (macb_is_gem(bp)) {
   ctrl &= ~GEM_BIT(GBE);

   if (speed == SPEED_1000)
    ctrl |= GEM_BIT(GBE);
  }

  if (rx_pause)
   ctrl |= MACB_BIT(PAE);

  /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down
 * cleared the pipeline and control registers.
 */

  bp->macbgem_ops.mog_init_rings(bp);
  macb_init_buffers(bp);

  for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
   queue_writel(queue, IER,
         bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
 }

 macb_or_gem_writel(bp, NCFGR, ctrl);

 if (bp->phy_interface == PHY_INTERFACE_MODE_10GBASER)
  gem_writel(bp, HS_MAC_CONFIG, GEM_BFINS(HS_MAC_SPEED, HS_SPEED_10000M,
       gem_readl(bp, HS_MAC_CONFIG)));

 spin_unlock_irqrestore(&bp->lock, flags);

 if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
  macb_set_tx_clk(bp, speed);

 /* Enable Rx and Tx; Enable PTP unicast */
 ctrl = macb_readl(bp, NCR);
 if (gem_has_ptp(bp))
  ctrl |= MACB_BIT(PTPUNI);

 macb_writel(bp, NCR, ctrl | MACB_BIT(RE) | MACB_BIT(TE));

 netif_tx_wake_all_queues(ndev);
}

static struct phylink_pcs *macb_mac_select_pcs(struct phylink_config *config,
            phy_interface_t interface)
{
 struct net_device *ndev = to_net_dev(config->dev);
 struct macb *bp = netdev_priv(ndev);

 if (interface == PHY_INTERFACE_MODE_10GBASER)
  return &bp->phylink_usx_pcs;
 else if (interface == PHY_INTERFACE_MODE_SGMII)
  return &bp->phylink_sgmii_pcs;
 else
  return NULL;
}

static const struct phylink_mac_ops macb_phylink_ops = {
 .mac_select_pcs = macb_mac_select_pcs,
 .mac_config = macb_mac_config,
 .mac_link_down = macb_mac_link_down,
 .mac_link_up = macb_mac_link_up,
};

static bool macb_phy_handle_exists(struct device_node *dn)
{
 dn = of_parse_phandle(dn, "phy-handle", 0);
 of_node_put(dn);
 return dn != NULL;
}

static int macb_phylink_connect(struct macb *bp)
{
 struct device_node *dn = bp->pdev->dev.of_node;
 struct net_device *dev = bp->dev;
 struct phy_device *phydev;
 int ret;

 if (dn)
  ret = phylink_of_phy_connect(bp->phylink, dn, 0);

 if (!dn || (ret && !macb_phy_handle_exists(dn))) {
  phydev = phy_find_first(bp->mii_bus);
  if (!phydev) {
   netdev_err(dev, "no PHY found\n");
   return -ENXIO;
  }

  /* attach the mac to the phy */
  ret = phylink_connect_phy(bp->phylink, phydev);
 }

 if (ret) {
  netdev_err(dev, "Could not attach PHY (%d)\n", ret);
  return ret;
 }

 phylink_start(bp->phylink);

 return 0;
}

static void macb_get_pcs_fixed_state(struct phylink_config *config,
         struct phylink_link_state *state)
{
 struct net_device *ndev = to_net_dev(config->dev);
 struct macb *bp = netdev_priv(ndev);

 state->link = (macb_readl(bp, NSR) & MACB_BIT(NSR_LINK)) != 0;
}

/* based on au1000_eth. c*/
static int macb_mii_probe(struct net_device *dev)
{
 struct macb *bp = netdev_priv(dev);

 bp->phylink_sgmii_pcs.ops = &macb_phylink_pcs_ops;
 bp->phylink_usx_pcs.ops = &macb_phylink_usx_pcs_ops;

 bp->phylink_config.dev = &dev->dev;
 bp->phylink_config.type = PHYLINK_NETDEV;
 bp->phylink_config.mac_managed_pm = true;

 if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
  bp->phylink_config.poll_fixed_state = true;
  bp->phylink_config.get_fixed_state = macb_get_pcs_fixed_state;
 }

 bp->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
  MAC_10 | MAC_100;

 __set_bit(PHY_INTERFACE_MODE_MII,
    bp->phylink_config.supported_interfaces);
 __set_bit(PHY_INTERFACE_MODE_RMII,
    bp->phylink_config.supported_interfaces);

 /* Determine what modes are supported */
 if (macb_is_gem(bp) && (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
  bp->phylink_config.mac_capabilities |= MAC_1000FD;
  if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
   bp->phylink_config.mac_capabilities |= MAC_1000HD;

  __set_bit(PHY_INTERFACE_MODE_GMII,
     bp->phylink_config.supported_interfaces);
  phy_interface_set_rgmii(bp->phylink_config.supported_interfaces);

  if (bp->caps & MACB_CAPS_PCS)
   __set_bit(PHY_INTERFACE_MODE_SGMII,
      bp->phylink_config.supported_interfaces);

  if (bp->caps & MACB_CAPS_HIGH_SPEED) {
   __set_bit(PHY_INTERFACE_MODE_10GBASER,
      bp->phylink_config.supported_interfaces);
   bp->phylink_config.mac_capabilities |= MAC_10000FD;
  }
 }

 bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode,
         bp->phy_interface, &macb_phylink_ops);
 if (IS_ERR(bp->phylink)) {
  netdev_err(dev, "Could not create a phylink instance (%ld)\n",
      PTR_ERR(bp->phylink));
  return PTR_ERR(bp->phylink);
 }

 return 0;
}

static int macb_mdiobus_register(struct macb *bp, struct device_node *mdio_np)
{
 struct device_node *child, *np = bp->pdev->dev.of_node;

 /* If we have a child named mdio, probe it instead of looking for PHYs
 * directly under the MAC node
 */

 if (mdio_np)
  return of_mdiobus_register(bp->mii_bus, mdio_np);

 /* Only create the PHY from the device tree if at least one PHY is
 * described. Otherwise scan the entire MDIO bus. We do this to support
 * old device tree that did not follow the best practices and did not
 * describe their network PHYs.
 */

 for_each_available_child_of_node(np, child)
  if (of_mdiobus_child_is_phy(child)) {
   /* The loop increments the child refcount,
 * decrement it before returning.
 */

   of_node_put(child);

   return of_mdiobus_register(bp->mii_bus, np);
  }

 return mdiobus_register(bp->mii_bus);
}

static int macb_mii_init(struct macb *bp)
{
 struct device_node *mdio_np, *np = bp->pdev->dev.of_node;
 int err = -ENXIO;

 /* With fixed-link, we don't need to register the MDIO bus,
 * except if we have a child named "mdio" in the device tree.
 * In that case, some devices may be attached to the MACB's MDIO bus.
 */

 mdio_np = of_get_child_by_name(np, "mdio");
 if (!mdio_np && of_phy_is_fixed_link(np))
  return macb_mii_probe(bp->dev);

 /* Enable management port */
 macb_writel(bp, NCR, MACB_BIT(MPE));

 bp->mii_bus = mdiobus_alloc();
 if (!bp->mii_bus) {
  err = -ENOMEM;
  goto err_out;
 }

 bp->mii_bus->name = "MACB_mii_bus";
 bp->mii_bus->read = &macb_mdio_read_c22;
 bp->mii_bus->write = &macb_mdio_write_c22;
 bp->mii_bus->read_c45 = &macb_mdio_read_c45;
 bp->mii_bus->write_c45 = &macb_mdio_write_c45;
 snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
   bp->pdev->name, bp->pdev->id);
 bp->mii_bus->priv = bp;
 bp->mii_bus->parent = &bp->pdev->dev;

 dev_set_drvdata(&bp->dev->dev, bp->mii_bus);

 err = macb_mdiobus_register(bp, mdio_np);
 if (err)
  goto err_out_free_mdiobus;

 err = macb_mii_probe(bp->dev);
 if (err)
  goto err_out_unregister_bus;

 return 0;

err_out_unregister_bus:
 mdiobus_unregister(bp->mii_bus);
err_out_free_mdiobus:
 mdiobus_free(bp->mii_bus);
err_out:
 of_node_put(mdio_np);

 return err;
}

static void macb_update_stats(struct macb *bp)
{
 u64 *p = &bp->hw_stats.macb.rx_pause_frames;
 u64 *end = &bp->hw_stats.macb.tx_pause_frames + 1;
 int offset = MACB_PFR;

 WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);

 for (; p < end; p++, offset += 4)
  *p += bp->macb_reg_readl(bp, offset);
}

static int macb_halt_tx(struct macb *bp)
{
 u32 status;

 macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));

 /* Poll TSR until TGO is cleared or timeout. */
 return read_poll_timeout_atomic(macb_readl, status,
     !(status & MACB_BIT(TGO)),
     250, MACB_HALT_TIMEOUT, false,
     bp, TSR);
}

static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budget)
{
 if (tx_skb->mapping) {
  if (tx_skb->mapped_as_page)
   dma_unmap_page(&bp->pdev->dev, tx_skb->mapping,
           tx_skb->size, DMA_TO_DEVICE);
  else
   dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
      tx_skb->size, DMA_TO_DEVICE);
  tx_skb->mapping = 0;
 }

 if (tx_skb->skb) {
  napi_consume_skb(tx_skb->skb, budget);
  tx_skb->skb = NULL;
 }
}

static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr)
{
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 struct macb_dma_desc_64 *desc_64;

 if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
  desc_64 = macb_64b_desc(bp, desc);
  desc_64->addrh = upper_32_bits(addr);
  /* The low bits of RX address contain the RX_USED bit, clearing
 * of which allows packet RX. Make sure the high bits are also
 * visible to HW at that point.
 */

  dma_wmb();
 }
#endif
 desc->addr = lower_32_bits(addr);
}

static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc)
{
 dma_addr_t addr = 0;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
 struct macb_dma_desc_64 *desc_64;

 if (bp->hw_dma_cap & HW_DMA_CAP_64B) {
  desc_64 = macb_64b_desc(bp, desc);
  addr = ((u64)(desc_64->addrh) << 32);
 }
#endif
 addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
#ifdef CONFIG_MACB_USE_HWSTAMP
 if (bp->hw_dma_cap & HW_DMA_CAP_PTP)
  addr &= ~GEM_BIT(DMA_RXVALID);
#endif
 return addr;
}

static void macb_tx_error_task(struct work_struct *work)
{
 struct macb_queue *queue = container_of(work, struct macb_queue,
            tx_error_task);
 bool   halt_timeout = false;
 struct macb  *bp = queue->bp;
 u32   queue_index;
 u32   packets = 0;
 u32   bytes = 0;
 struct macb_tx_skb *tx_skb;
 struct macb_dma_desc *desc;
 struct sk_buff  *skb;
 unsigned int  tail;
 unsigned long  flags;

 queue_index = queue - bp->queues;
 netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n",
      queue_index, queue->tx_tail, queue->tx_head);

 /* Prevent the queue NAPI TX poll from running, as it calls
 * macb_tx_complete(), which in turn may call netif_wake_subqueue().
 * As explained below, we have to halt the transmission before updating
 * TBQP registers so we call netif_tx_stop_all_queues() to notify the
 * network engine about the macb/gem being halted.
 */

 napi_disable(&queue->napi_tx);
 spin_lock_irqsave(&bp->lock, flags);

 /* Make sure nobody is trying to queue up new packets */
 netif_tx_stop_all_queues(bp->dev);

 /* Stop transmission now
 * (in case we have just queued new packets)
 * macb/gem must be halted to write TBQP register
 */

 if (macb_halt_tx(bp)) {
  netdev_err(bp->dev, "BUG: halt tx timed out\n");
  macb_writel(bp, NCR, macb_readl(bp, NCR) & (~MACB_BIT(TE)));
  halt_timeout = true;
 }

 /* Treat frames in TX queue including the ones that caused the error.
 * Free transmit buffers in upper layer.
 */

 for (tail = queue->tx_tail; tail != queue->tx_head; tail++) {
  u32 ctrl;

  desc = macb_tx_desc(queue, tail);
  ctrl = desc->ctrl;
  tx_skb = macb_tx_skb(queue, tail);
  skb = tx_skb->skb;

  if (ctrl & MACB_BIT(TX_USED)) {
   /* skb is set for the last buffer of the frame */
   while (!skb) {
    macb_tx_unmap(bp, tx_skb, 0);
    tail++;
    tx_skb = macb_tx_skb(queue, tail);
    skb = tx_skb->skb;
   }

   /* ctrl still refers to the first buffer descriptor
 * since it's the only one written back by the hardware
 */

   if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) {
    netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
         macb_tx_ring_wrap(bp, tail),
         skb->data);
    bp->dev->stats.tx_packets++;
    queue->stats.tx_packets++;
    packets++;
    bp->dev->stats.tx_bytes += skb->len;
    queue->stats.tx_bytes += skb->len;
    bytes += skb->len;
   }
  } else {
   /* "Buffers exhausted mid-frame" errors may only happen
 * if the driver is buggy, so complain loudly about
 * those. Statistics are updated by hardware.
 */

   if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
    netdev_err(bp->dev,
        "BUG: TX buffers exhausted mid-frame\n");

   desc->ctrl = ctrl | MACB_BIT(TX_USED);
  }

  macb_tx_unmap(bp, tx_skb, 0);
 }

 netdev_tx_completed_queue(netdev_get_tx_queue(bp->dev, queue_index),
      packets, bytes);

 /* Set end of TX queue */
 desc = macb_tx_desc(queue, 0);
 macb_set_addr(bp, desc, 0);
 desc->ctrl = MACB_BIT(TX_USED);

 /* Make descriptor updates visible to hardware */
 wmb();

 /* Reinitialize the TX desc queue */
 queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
 /* Make TX ring reflect state of hardware */
 queue->tx_head = 0;
 queue->tx_tail = 0;

 /* Housework before enabling TX IRQ */
 macb_writel(bp, TSR, macb_readl(bp, TSR));
 queue_writel(queue, IER, MACB_TX_INT_FLAGS);

 if (halt_timeout)
  macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE));

 /* Now we are ready to start transmission again */
 netif_tx_start_all_queues(bp->dev);
 macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));

 spin_unlock_irqrestore(&bp->lock, flags);
 napi_enable(&queue->napi_tx);
}

static bool ptp_one_step_sync(struct sk_buff *skb)
{
 struct ptp_header *hdr;
 unsigned int ptp_class;
 u8 msgtype;

 /* No need to parse packet if PTP TS is not involved */
 if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
  goto not_oss;

 /* Identify and return whether PTP one step sync is being processed */
 ptp_class = ptp_classify_raw(skb);
 if (ptp_class == PTP_CLASS_NONE)
  goto not_oss;

 hdr = ptp_parse_header(skb, ptp_class);
 if (!hdr)
  goto not_oss;

 if (hdr->flag_field[0] & PTP_FLAG_TWOSTEP)
  goto not_oss;

 msgtype = ptp_get_msgtype(hdr, ptp_class);
 if (msgtype == PTP_MSGTYPE_SYNC)
  return true;

not_oss:
 return false;
}

static int macb_tx_complete(struct macb_queue *queue, int budget)
{
 struct macb *bp = queue->bp;
 u16 queue_index = queue - bp->queues;
 unsigned long flags;
 unsigned int tail;
 unsigned int head;
 int packets = 0;
 u32 bytes = 0;

 spin_lock_irqsave(&queue->tx_ptr_lock, flags);
 head = queue->tx_head;
 for (tail = queue->tx_tail; tail != head && packets < budget; tail++) {
  struct macb_tx_skb *tx_skb;
  struct sk_buff  *skb;
  struct macb_dma_desc *desc;
  u32   ctrl;

  desc = macb_tx_desc(queue, tail);

  /* Make hw descriptor updates visible to CPU */
  rmb();

  ctrl = desc->ctrl;

  /* TX_USED bit is only set by hardware on the very first buffer
 * descriptor of the transmitted frame.
 */

  if (!(ctrl & MACB_BIT(TX_USED)))
   break;

  /* Process all buffers of the current transmitted frame */
  for (;; tail++) {
   tx_skb = macb_tx_skb(queue, tail);
   skb = tx_skb->skb;

   /* First, update TX stats if needed */
   if (skb) {
    if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
        !ptp_one_step_sync(skb))
     gem_ptp_do_txstamp(bp, skb, desc);

    netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
         macb_tx_ring_wrap(bp, tail),
         skb->data);
    bp->dev->stats.tx_packets++;
    queue->stats.tx_packets++;
    bp->dev->stats.tx_bytes += skb->len;
    queue->stats.tx_bytes += skb->len;
    packets++;
    bytes += skb->len;
   }

   /* Now we can safely release resources */
   macb_tx_unmap(bp, tx_skb, budget);

   /* skb is set only for the last buffer of the frame.
 * WARNING: at this point skb has been freed by
 * macb_tx_unmap().
 */

   if (skb)
    break;
  }
 }

 netdev_tx_completed_queue(netdev_get_tx_queue(bp->dev, queue_index),
      packets, bytes);

 queue->tx_tail = tail;
 if (__netif_subqueue_stopped(bp->dev, queue_index) &&
     CIRC_CNT(queue->tx_head, queue->tx_tail,
       bp->tx_ring_size) <= MACB_TX_WAKEUP_THRESH(bp))
  netif_wake_subqueue(bp->dev, queue_index);
 spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);

 return packets;
}

static void gem_rx_refill(struct macb_queue *queue)
{
 unsigned int  entry;
 struct sk_buff  *skb;
 dma_addr_t  paddr;
 struct macb *bp = queue->bp;
 struct macb_dma_desc *desc;

 while (CIRC_SPACE(queue->rx_prepared_head, queue->rx_tail,
   bp->rx_ring_size) > 0) {
  entry = macb_rx_ring_wrap(bp, queue->rx_prepared_head);

  /* Make hw descriptor updates visible to CPU */
  rmb();

  desc = macb_rx_desc(queue, entry);

  if (!queue->rx_skbuff[entry]) {
   /* allocate sk_buff for this free entry in ring */
   skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size);
   if (unlikely(!skb)) {
    netdev_err(bp->dev,
        "Unable to allocate sk_buff\n");
    break;
   }

   /* now fill corresponding descriptor entry */
   paddr = dma_map_single(&bp->pdev->dev, skb->data,
            bp->rx_buffer_size,
            DMA_FROM_DEVICE);
   if (dma_mapping_error(&bp->pdev->dev, paddr)) {
    dev_kfree_skb(skb);
    break;
   }

   queue->rx_skbuff[entry] = skb;

   if (entry == bp->rx_ring_size - 1)
    paddr |= MACB_BIT(RX_WRAP);
   desc->ctrl = 0;
   /* Setting addr clears RX_USED and allows reception,
 * make sure ctrl is cleared first to avoid a race.
 */

   dma_wmb();
   macb_set_addr(bp, desc, paddr);

   /* properly align Ethernet header */
   skb_reserve(skb, NET_IP_ALIGN);
  } else {
   desc->ctrl = 0;
   dma_wmb();
   desc->addr &= ~MACB_BIT(RX_USED);
  }
  queue->rx_prepared_head++;
 }

 /* Make descriptor updates visible to hardware */
 wmb();

 netdev_vdbg(bp->dev, "rx ring: queue: %p, prepared head %d, tail %d\n",
   queue, queue->rx_prepared_head, queue->rx_tail);
}

/* Mark DMA descriptors from begin up to and not including end as unused */
static void discard_partial_frame(struct macb_queue *queue, unsigned int begin,
      unsigned int end)
{
 unsigned int frag;

 for (frag = begin; frag != end; frag++) {
  struct macb_dma_desc *desc = macb_rx_desc(queue, frag);

  desc->addr &= ~MACB_BIT(RX_USED);
 }

 /* Make descriptor updates visible to hardware */
 wmb();

 /* When this happens, the hardware stats registers for
 * whatever caused this is updated, so we don't have to record
 * anything.
 */

}

static int gem_rx(struct macb_queue *queue, struct napi_struct *napi,
    int budget)
{
 struct macb *bp = queue->bp;
 unsigned int  len;
 unsigned int  entry;
 struct sk_buff  *skb;
 struct macb_dma_desc *desc;
 int   count = 0;

 while (count < budget) {
  u32 ctrl;
  dma_addr_t addr;
  bool rxused;

  entry = macb_rx_ring_wrap(bp, queue->rx_tail);
  desc = macb_rx_desc(queue, entry);

  /* Make hw descriptor updates visible to CPU */
  rmb();

  rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
  addr = macb_get_addr(bp, desc);

  if (!rxused)
   break;

  /* Ensure ctrl is at least as up-to-date as rxused */
  dma_rmb();

  ctrl = desc->ctrl;

  queue->rx_tail++;
  count++;

  if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) {
   netdev_err(bp->dev,
       "not whole frame pointed by descriptor\n");
   bp->dev->stats.rx_dropped++;
   queue->stats.rx_dropped++;
   break;
  }
  skb = queue->rx_skbuff[entry];
  if (unlikely(!skb)) {
   netdev_err(bp->dev,
       "inconsistent Rx descriptor chain\n");
   bp->dev->stats.rx_dropped++;
   queue->stats.rx_dropped++;
   break;
  }
  /* now everything is ready for receiving packet */
  queue->rx_skbuff[entry] = NULL;
  len = ctrl & bp->rx_frm_len_mask;

  netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len);

  skb_put(skb, len);
  dma_unmap_single(&bp->pdev->dev, addr,
     bp->rx_buffer_size, DMA_FROM_DEVICE);

  skb->protocol = eth_type_trans(skb, bp->dev);
  skb_checksum_none_assert(skb);
  if (bp->dev->features & NETIF_F_RXCSUM &&
      !(bp->dev->flags & IFF_PROMISC) &&
      GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
   skb->ip_summed = CHECKSUM_UNNECESSARY;

  bp->dev->stats.rx_packets++;
  queue->stats.rx_packets++;
  bp->dev->stats.rx_bytes += skb->len;
  queue->stats.rx_bytes += skb->len;

  gem_ptp_do_rxstamp(bp, skb, desc);

#if defined(DEBUG) && defined(VERBOSE_DEBUG)
  netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
       skb->len, skb->csum);
  print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1,
          skb_mac_header(skb), 16, true);
  print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1,
          skb->data, 32, true);
#endif

  napi_gro_receive(napi, skb);
 }

 gem_rx_refill(queue);

 return count;
}

static int macb_rx_frame(struct macb_queue *queue, struct napi_struct *napi,
    unsigned int first_frag, unsigned int last_frag)
{
 unsigned int len;
 unsigned int frag;
 unsigned int offset;
 struct sk_buff *skb;
 struct macb_dma_desc *desc;
 struct macb *bp = queue->bp;

 desc = macb_rx_desc(queue, last_frag);
 len = desc->ctrl & bp->rx_frm_len_mask;

 netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
  macb_rx_ring_wrap(bp, first_frag),
  macb_rx_ring_wrap(bp, last_frag), len);

 /* The ethernet header starts NET_IP_ALIGN bytes into the
 * first buffer. Since the header is 14 bytes, this makes the
 * payload word-aligned.
 *
 * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy
 * the two padding bytes into the skb so that we avoid hitting
 * the slowpath in memcpy(), and pull them off afterwards.
 */

 skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN);
 if (!skb) {
  bp->dev->stats.rx_dropped++;
  for (frag = first_frag; ; frag++) {
   desc = macb_rx_desc(queue, frag);
   desc->addr &= ~MACB_BIT(RX_USED);
   if (frag == last_frag)
    break;
  }

  /* Make descriptor updates visible to hardware */
  wmb();

  return 1;
 }

 offset = 0;
 len += NET_IP_ALIGN;
 skb_checksum_none_assert(skb);
 skb_put(skb, len);

 for (frag = first_frag; ; frag++) {
  unsigned int frag_len = bp->rx_buffer_size;

  if (offset + frag_len > len) {
   if (unlikely(frag != last_frag)) {
    dev_kfree_skb_any(skb);
    return -1;
   }
   frag_len = len - offset;
  }
  skb_copy_to_linear_data_offset(skb, offset,
            macb_rx_buffer(queue, frag),
            frag_len);
  offset += bp->rx_buffer_size;
  desc = macb_rx_desc(queue, frag);
  desc->addr &= ~MACB_BIT(RX_USED);

  if (frag == last_frag)
   break;
 }

 /* Make descriptor updates visible to hardware */
 wmb();

 __skb_pull(skb, NET_IP_ALIGN);
 skb->protocol = eth_type_trans(skb, bp->dev);

 bp->dev->stats.rx_packets++;
 bp->dev->stats.rx_bytes += skb->len;
 netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
      skb->len, skb->csum);
 napi_gro_receive(napi, skb);

 return 0;
}

static inline void macb_init_rx_ring(struct macb_queue *queue)
{
 struct macb *bp = queue->bp;
 dma_addr_t addr;
 struct macb_dma_desc *desc = NULL;
 int i;

 addr = queue->rx_buffers_dma;
 for (i = 0; i < bp->rx_ring_size; i++) {
  desc = macb_rx_desc(queue, i);
  macb_set_addr(bp, desc, addr);
  desc->ctrl = 0;
  addr += bp->rx_buffer_size;
 }
 desc->addr |= MACB_BIT(RX_WRAP);
 queue->rx_tail = 0;
}

static int macb_rx(struct macb_queue *queue, struct napi_struct *napi,
     int budget)
{
 struct macb *bp = queue->bp;
 bool reset_rx_queue = false;
 int received = 0;
 unsigned int tail;
 int first_frag = -1;

 for (tail = queue->rx_tail; budget > 0; tail++) {
  struct macb_dma_desc *desc = macb_rx_desc(queue, tail);
  u32 ctrl;

  /* Make hw descriptor updates visible to CPU */
  rmb();

  if (!(desc->addr & MACB_BIT(RX_USED)))
   break;

  /* Ensure ctrl is at least as up-to-date as addr */
  dma_rmb();

  ctrl = desc->ctrl;

  if (ctrl & MACB_BIT(RX_SOF)) {
   if (first_frag != -1)
    discard_partial_frame(queue, first_frag, tail);
   first_frag = tail;
  }

  if (ctrl & MACB_BIT(RX_EOF)) {
   int dropped;

   if (unlikely(first_frag == -1)) {
    reset_rx_queue = true;
    continue;
   }

   dropped = macb_rx_frame(queue, napi, first_frag, tail);
   first_frag = -1;
   if (unlikely(dropped < 0)) {
    reset_rx_queue = true;
    continue;
   }
   if (!dropped) {
    received++;
    budget--;
   }
  }
 }

 if (unlikely(reset_rx_queue)) {
  unsigned long flags;
  u32 ctrl;

  netdev_err(bp->dev, "RX queue corruption: reset it\n");

  spin_lock_irqsave(&bp->lock, flags);

  ctrl = macb_readl(bp, NCR);
  macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));

  macb_init_rx_ring(queue);
  queue_writel(queue, RBQP, queue->rx_ring_dma);

  macb_writel(bp, NCR, ctrl | MACB_BIT(RE));

  spin_unlock_irqrestore(&bp->lock, flags);
  return received;
 }

 if (first_frag != -1)
  queue->rx_tail = first_frag;
 else
  queue->rx_tail = tail;

 return received;
}

static bool macb_rx_pending(struct macb_queue *queue)
{
 struct macb *bp = queue->bp;
 unsigned int  entry;
 struct macb_dma_desc *desc;

 entry = macb_rx_ring_wrap(bp, queue->rx_tail);
 desc = macb_rx_desc(queue, entry);

 /* Make hw descriptor updates visible to CPU */
 rmb();

 return (desc->addr & MACB_BIT(RX_USED)) != 0;
}

static int macb_rx_poll(struct napi_struct *napi, int budget)
{
 struct macb_queue *queue = container_of(napi, struct macb_queue, napi_rx);
 struct macb *bp = queue->bp;
 int work_done;

 work_done = bp->macbgem_ops.mog_rx(queue, napi, budget);

 netdev_vdbg(bp->dev, "RX poll: queue = %u, work_done = %d, budget = %d\n",
      (unsigned int)(queue - bp->queues), work_done, budget);

 if (work_done < budget && napi_complete_done(napi, work_done)) {
  queue_writel(queue, IER, bp->rx_intr_mask);

  /* Packet completions only seem to propagate to raise
 * interrupts when interrupts are enabled at the time, so if
 * packets were received while interrupts were disabled,
 * they will not cause another interrupt to be generated when
 * interrupts are re-enabled.
 * Check for this case here to avoid losing a wakeup. This can
 * potentially race with the interrupt handler doing the same
 * actions if an interrupt is raised just after enabling them,
 * but this should be harmless.
 */

  if (macb_rx_pending(queue)) {
   queue_writel(queue, IDR, bp->rx_intr_mask);
   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(RCOMP));
   netdev_vdbg(bp->dev, "poll: packets pending, reschedule\n");
   napi_schedule(napi);
  }
 }

 /* TODO: Handle errors */

 return work_done;
}

static void macb_tx_restart(struct macb_queue *queue)
{
 struct macb *bp = queue->bp;
 unsigned int head_idx, tbqp;
 unsigned long flags;

 spin_lock_irqsave(&queue->tx_ptr_lock, flags);

 if (queue->tx_head == queue->tx_tail)
  goto out_tx_ptr_unlock;

 tbqp = queue_readl(queue, TBQP) / macb_dma_desc_get_size(bp);
 tbqp = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, tbqp));
 head_idx = macb_adj_dma_desc_idx(bp, macb_tx_ring_wrap(bp, queue->tx_head));

 if (tbqp == head_idx)
  goto out_tx_ptr_unlock;

 spin_lock(&bp->lock);
 macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
 spin_unlock(&bp->lock);

out_tx_ptr_unlock:
 spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);
}

static bool macb_tx_complete_pending(struct macb_queue *queue)
{
 bool retval = false;
 unsigned long flags;

 spin_lock_irqsave(&queue->tx_ptr_lock, flags);
 if (queue->tx_head != queue->tx_tail) {
  /* Make hw descriptor updates visible to CPU */
  rmb();

  if (macb_tx_desc(queue, queue->tx_tail)->ctrl & MACB_BIT(TX_USED))
   retval = true;
 }
 spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);
 return retval;
}

static int macb_tx_poll(struct napi_struct *napi, int budget)
{
 struct macb_queue *queue = container_of(napi, struct macb_queue, napi_tx);
 struct macb *bp = queue->bp;
 int work_done;

 work_done = macb_tx_complete(queue, budget);

 rmb(); // ensure txubr_pending is up to date
 if (queue->txubr_pending) {
  queue->txubr_pending = false;
  netdev_vdbg(bp->dev, "poll: tx restart\n");
  macb_tx_restart(queue);
 }

 netdev_vdbg(bp->dev, "TX poll: queue = %u, work_done = %d, budget = %d\n",
      (unsigned int)(queue - bp->queues), work_done, budget);

 if (work_done < budget && napi_complete_done(napi, work_done)) {
  queue_writel(queue, IER, MACB_BIT(TCOMP));

  /* Packet completions only seem to propagate to raise
 * interrupts when interrupts are enabled at the time, so if
 * packets were sent while interrupts were disabled,
 * they will not cause another interrupt to be generated when
 * interrupts are re-enabled.
 * Check for this case here to avoid losing a wakeup. This can
 * potentially race with the interrupt handler doing the same
 * actions if an interrupt is raised just after enabling them,
 * but this should be harmless.
 */

  if (macb_tx_complete_pending(queue)) {
   queue_writel(queue, IDR, MACB_BIT(TCOMP));
   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(TCOMP));
   netdev_vdbg(bp->dev, "TX poll: packets pending, reschedule\n");
   napi_schedule(napi);
  }
 }

 return work_done;
}

static void macb_hresp_error_task(struct work_struct *work)
{
 struct macb *bp = from_work(bp, work, hresp_err_bh_work);
 struct net_device *dev = bp->dev;
 struct macb_queue *queue;
 unsigned int q;
 u32 ctrl;

 for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
  queue_writel(queue, IDR, bp->rx_intr_mask |
      MACB_TX_INT_FLAGS |
      MACB_BIT(HRESP));
 }
 ctrl = macb_readl(bp, NCR);
 ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE));
 macb_writel(bp, NCR, ctrl);

 netif_tx_stop_all_queues(dev);
 netif_carrier_off(dev);

 bp->macbgem_ops.mog_init_rings(bp);

 /* Initialize TX and RX buffers */
 macb_init_buffers(bp);

 /* Enable interrupts */
 for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
  queue_writel(queue, IER,
        bp->rx_intr_mask |
        MACB_TX_INT_FLAGS |
        MACB_BIT(HRESP));

 ctrl |= MACB_BIT(RE) | MACB_BIT(TE);
 macb_writel(bp, NCR, ctrl);

 netif_carrier_on(dev);
 netif_tx_start_all_queues(dev);
}

static irqreturn_t macb_wol_interrupt(int irq, void *dev_id)
{
 struct macb_queue *queue = dev_id;
 struct macb *bp = queue->bp;
 u32 status;

 status = queue_readl(queue, ISR);

 if (unlikely(!status))
  return IRQ_NONE;

 spin_lock(&bp->lock);

 if (status & MACB_BIT(WOL)) {
  queue_writel(queue, IDR, MACB_BIT(WOL));
  macb_writel(bp, WOL, 0);
  netdev_vdbg(bp->dev, "MACB WoL: queue = %u, isr = 0x%08lx\n",
       (unsigned int)(queue - bp->queues),
       (unsigned long)status);
  if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
   queue_writel(queue, ISR, MACB_BIT(WOL));
  pm_wakeup_event(&bp->pdev->dev, 0);
 }

 spin_unlock(&bp->lock);

 return IRQ_HANDLED;
}

static irqreturn_t gem_wol_interrupt(int irq, void *dev_id)
{
 struct macb_queue *queue = dev_id;
 struct macb *bp = queue->bp;
 u32 status;

 status = queue_readl(queue, ISR);

 if (unlikely(!status))
  return IRQ_NONE;

 spin_lock(&bp->lock);

 if (status & GEM_BIT(WOL)) {
  queue_writel(queue, IDR, GEM_BIT(WOL));
  gem_writel(bp, WOL, 0);
  netdev_vdbg(bp->dev, "GEM WoL: queue = %u, isr = 0x%08lx\n",
       (unsigned int)(queue - bp->queues),
       (unsigned long)status);
  if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
   queue_writel(queue, ISR, GEM_BIT(WOL));
  pm_wakeup_event(&bp->pdev->dev, 0);
 }

 spin_unlock(&bp->lock);

 return IRQ_HANDLED;
}

static irqreturn_t macb_interrupt(int irq, void *dev_id)
{
 struct macb_queue *queue = dev_id;
 struct macb *bp = queue->bp;
 struct net_device *dev = bp->dev;
 u32 status, ctrl;

 status = queue_readl(queue, ISR);

 if (unlikely(!status))
  return IRQ_NONE;

 spin_lock(&bp->lock);

 while (status) {
  /* close possible race with dev_close */
  if (unlikely(!netif_running(dev))) {
   queue_writel(queue, IDR, -1);
   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, -1);
   break;
  }

  netdev_vdbg(bp->dev, "queue = %u, isr = 0x%08lx\n",
       (unsigned int)(queue - bp->queues),
       (unsigned long)status);

  if (status & bp->rx_intr_mask) {
   /* There's no point taking any more interrupts
 * until we have processed the buffers. The
 * scheduling call may fail if the poll routine
 * is already scheduled, so disable interrupts
 * now.
 */

   queue_writel(queue, IDR, bp->rx_intr_mask);
   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(RCOMP));

   if (napi_schedule_prep(&queue->napi_rx)) {
    netdev_vdbg(bp->dev, "scheduling RX softirq\n");
    __napi_schedule(&queue->napi_rx);
   }
  }

  if (status & (MACB_BIT(TCOMP) |
         MACB_BIT(TXUBR))) {
   queue_writel(queue, IDR, MACB_BIT(TCOMP));
   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(TCOMP) |
        MACB_BIT(TXUBR));

   if (status & MACB_BIT(TXUBR)) {
    queue->txubr_pending = true;
    wmb(); // ensure softirq can see update
   }

   if (napi_schedule_prep(&queue->napi_tx)) {
    netdev_vdbg(bp->dev, "scheduling TX softirq\n");
    __napi_schedule(&queue->napi_tx);
   }
  }

  if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
   queue_writel(queue, IDR, MACB_TX_INT_FLAGS);
   schedule_work(&queue->tx_error_task);

   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_TX_ERR_FLAGS);

   break;
  }

  /* Link change detection isn't possible with RMII, so we'll
 * add that if/when we get our hands on a full-blown MII PHY.
 */


  /* There is a hardware issue under heavy load where DMA can
 * stop, this causes endless "used buffer descriptor read"
 * interrupts but it can be cleared by re-enabling RX. See
 * the at91rm9200 manual, section 41.3.1 or the Zynq manual
 * section 16.7.4 for details. RXUBR is only enabled for
 * these two versions.
 */

  if (status & MACB_BIT(RXUBR)) {
   ctrl = macb_readl(bp, NCR);
   macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE));
   wmb();
   macb_writel(bp, NCR, ctrl | MACB_BIT(RE));

   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(RXUBR));
  }

  if (status & MACB_BIT(ISR_ROVR)) {
   /* We missed at least one packet */
   spin_lock(&bp->stats_lock);
   if (macb_is_gem(bp))
    bp->hw_stats.gem.rx_overruns++;
   else
    bp->hw_stats.macb.rx_overruns++;
   spin_unlock(&bp->stats_lock);

   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(ISR_ROVR));
  }

  if (status & MACB_BIT(HRESP)) {
   queue_work(system_bh_wq, &bp->hresp_err_bh_work);
   netdev_err(dev, "DMA bus error: HRESP not OK\n");

   if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
    queue_writel(queue, ISR, MACB_BIT(HRESP));
  }
  status = queue_readl(queue, ISR);
 }

 spin_unlock(&bp->lock);

 return IRQ_HANDLED;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling receive - used by netconsole and other diagnostic tools
 * to allow network i/o with interrupts disabled.
 */

static void macb_poll_controller(struct net_device *dev)
{
 struct macb *bp = netdev_priv(dev);
 struct macb_queue *queue;
 unsigned long flags;
 unsigned int q;

 local_irq_save(flags);
 for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
  macb_interrupt(dev->irq, queue);
 local_irq_restore(flags);
}
#endif

static unsigned int macb_tx_map(struct macb *bp,
    struct macb_queue *queue,
    struct sk_buff *skb,
    unsigned int hdrlen)
{
 dma_addr_t mapping;
 unsigned int len, entry, i, tx_head = queue->tx_head;
 struct macb_tx_skb *tx_skb = NULL;
 struct macb_dma_desc *desc;
 unsigned int offset, size, count = 0;
 unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags;
 unsigned int eof = 1, mss_mfs = 0;
 u32 ctrl, lso_ctrl = 0, seq_ctrl = 0;

 /* LSO */
 if (skb_shinfo(skb)->gso_size != 0) {
  if (ip_hdr(skb)->protocol == IPPROTO_UDP)
   /* UDP - UFO */
   lso_ctrl = MACB_LSO_UFO_ENABLE;
  else
   /* TCP - TSO */
   lso_ctrl = MACB_LSO_TSO_ENABLE;
 }

 /* First, map non-paged data */
 len = skb_headlen(skb);

 /* first buffer length */
 size = hdrlen;

 offset = 0;
 while (len) {
  entry = macb_tx_ring_wrap(bp, tx_head);
  tx_skb = &queue->tx_skb[entry];

  mapping = dma_map_single(&bp->pdev->dev,
      skb->data + offset,
      size, DMA_TO_DEVICE);
  if (dma_mapping_error(&bp->pdev->dev, mapping))
   goto dma_error;

  /* Save info to properly release resources */
  tx_skb->skb = NULL;
  tx_skb->mapping = mapping;
  tx_skb->size = size;
  tx_skb->mapped_as_page = false;

  len -= size;
  offset += size;
  count++;
  tx_head++;

  size = min(len, bp->max_tx_length);
 }

 /* Then, map paged data from fragments */
 for (f = 0; f < nr_frags; f++) {
  const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];

  len = skb_frag_size(frag);
  offset = 0;
  while (len) {
   size = min(len, bp->max_tx_length);
   entry = macb_tx_ring_wrap(bp, tx_head);
   tx_skb = &queue->tx_skb[entry];

   mapping = skb_frag_dma_map(&bp->pdev->dev, frag,
         offset, size, DMA_TO_DEVICE);
   if (dma_mapping_error(&bp->pdev->dev, mapping))
    goto dma_error;

   /* Save info to properly release resources */
   tx_skb->skb = NULL;
   tx_skb->mapping = mapping;
   tx_skb->size = size;
   tx_skb->mapped_as_page = true;

   len -= size;
   offset += size;
   count++;
   tx_head++;
  }
 }

 /* Should never happen */
 if (unlikely(!tx_skb)) {
  netdev_err(bp->dev, "BUG! empty skb!\n");
  return 0;
 }

 /* This is the last buffer of the frame: save socket buffer */
 tx_skb->skb = skb;

 /* Update TX ring: update buffer descriptors in reverse order
 * to avoid race condition
 */


 /* Set 'TX_USED' bit in buffer descriptor at tx_head position
 * to set the end of TX queue
 */

 i = tx_head;
 entry = macb_tx_ring_wrap(bp, i);
 ctrl = MACB_BIT(TX_USED);
 desc = macb_tx_desc(queue, entry);
 desc->ctrl = ctrl;

 if (lso_ctrl) {
  if (lso_ctrl == MACB_LSO_UFO_ENABLE)
   /* include header and FCS in value given to h/w */
   mss_mfs = skb_shinfo(skb)->gso_size +
     skb_transport_offset(skb) +
     ETH_FCS_LEN;
  else /* TSO */ {
   mss_mfs = skb_shinfo(skb)->gso_size;
   /* TCP Sequence Number Source Select
 * can be set only for TSO
 */

   seq_ctrl = 0;
  }
 }

 do {
  i--;
  entry = macb_tx_ring_wrap(bp, i);
  tx_skb = &queue->tx_skb[entry];
  desc = macb_tx_desc(queue, entry);

  ctrl = (u32)tx_skb->size;
  if (eof) {
   ctrl |= MACB_BIT(TX_LAST);
   eof = 0;
  }
  if (unlikely(entry == (bp->tx_ring_size - 1)))
   ctrl |= MACB_BIT(TX_WRAP);

  /* First descriptor is header descriptor */
  if (i == queue->tx_head) {
   ctrl |= MACB_BF(TX_LSO, lso_ctrl);
   ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl);
   if ((bp->dev->features & NETIF_F_HW_CSUM) &&
       skb->ip_summed != CHECKSUM_PARTIAL && !lso_ctrl &&
       !ptp_one_step_sync(skb))
    ctrl |= MACB_BIT(TX_NOCRC);
  } else
   /* Only set MSS/MFS on payload descriptors
 * (second or later descriptor)
 */

   ctrl |= MACB_BF(MSS_MFS, mss_mfs);

  /* Set TX buffer descriptor */
  macb_set_addr(bp, desc, tx_skb->mapping);
  /* desc->addr must be visible to hardware before clearing
 * 'TX_USED' bit in desc->ctrl.
 */

  wmb();
  desc->ctrl = ctrl;
 } while (i != queue->tx_head);

 queue->tx_head = tx_head;

 return count;

dma_error:
 netdev_err(bp->dev, "TX DMA map failed\n");

 for (i = queue->tx_head; i != tx_head; i++) {
  tx_skb = macb_tx_skb(queue, i);

  macb_tx_unmap(bp, tx_skb, 0);
 }

 return 0;
}

static netdev_features_t macb_features_check(struct sk_buff *skb,
          struct net_device *dev,
          netdev_features_t features)
{
 unsigned int nr_frags, f;
 unsigned int hdrlen;

 /* Validate LSO compatibility */

 /* there is only one buffer or protocol is not UDP */
 if (!skb_is_nonlinear(skb) || (ip_hdr(skb)->protocol != IPPROTO_UDP))
  return features;

 /* length of header */
 hdrlen = skb_transport_offset(skb);

 /* For UFO only:
 * When software supplies two or more payload buffers all payload buffers
 * apart from the last must be a multiple of 8 bytes in size.
 */

 if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, MACB_TX_LEN_ALIGN))
  return features & ~MACB_NETIF_LSO;

 nr_frags = skb_shinfo(skb)->nr_frags;
 /* No need to check last fragment */
 nr_frags--;
 for (f = 0; f < nr_frags; f++) {
  const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];

  if (!IS_ALIGNED(skb_frag_size(frag), MACB_TX_LEN_ALIGN))
   return features & ~MACB_NETIF_LSO;
 }
 return features;
}

static inline int macb_clear_csum(struct sk_buff *skb)
{
 /* no change for packets without checksum offloading */
 if (skb->ip_summed != CHECKSUM_PARTIAL)
  return 0;

 /* make sure we can modify the header */
 if (unlikely(skb_cow_head(skb, 0)))
  return -1;

 /* initialize checksum field
 * This is required - at least for Zynq, which otherwise calculates
 * wrong UDP header checksums for UDP packets with UDP data len <=2
 */

 *(__sum16 *)(skb_checksum_start(skb) + skb->csum_offset) = 0;
 return 0;
}

static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
{
 bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
        skb_is_nonlinear(*skb);
 int padlen = ETH_ZLEN - (*skb)->len;
 int tailroom = skb_tailroom(*skb);
 struct sk_buff *nskb;
 u32 fcs;

 if (!(ndev->features & NETIF_F_HW_CSUM) ||
     !((*skb)->ip_summed != CHECKSUM_PARTIAL) ||
     skb_shinfo(*skb)->gso_size || ptp_one_step_sync(*skb))
  return 0;

 if (padlen <= 0) {
  /* FCS could be appeded to tailroom. */
  if (tailroom >= ETH_FCS_LEN)
   goto add_fcs;
  /* No room for FCS, need to reallocate skb. */
  else
   padlen = ETH_FCS_LEN;
 } else {
  /* Add room for FCS. */
  padlen += ETH_FCS_LEN;
 }

 if (cloned || tailroom < padlen) {
  nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
  if (!nskb)
   return -ENOMEM;

  dev_consume_skb_any(*skb);
  *skb = nskb;
 }

 if (padlen > ETH_FCS_LEN)
  skb_put_zero(*skb, padlen - ETH_FCS_LEN);

add_fcs:
 /* set FCS to packet */
 fcs = crc32_le(~0, (*skb)->data, (*skb)->len);
 fcs = ~fcs;

 skb_put_u8(*skb, fcs  & 0xff);
 skb_put_u8(*skb, (fcs >> 8) & 0xff);
 skb_put_u8(*skb, (fcs >> 16) & 0xff);
 skb_put_u8(*skb, (fcs >> 24) & 0xff);

 return 0;
}

static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
 u16 queue_index = skb_get_queue_mapping(skb);
 struct macb *bp = netdev_priv(dev);
 struct macb_queue *queue = &bp->queues[queue_index];
 unsigned int desc_cnt, nr_frags, frag_size, f;
 unsigned int hdrlen;
 unsigned long flags;
 bool is_lso;
 netdev_tx_t ret = NETDEV_TX_OK;

 if (macb_clear_csum(skb)) {
  dev_kfree_skb_any(skb);
  return ret;
 }

 if (macb_pad_and_fcs(&skb, dev)) {
  dev_kfree_skb_any(skb);
  return ret;
 }

#ifdef CONFIG_MACB_USE_HWSTAMP
 if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
     (bp->hw_dma_cap & HW_DMA_CAP_PTP))
  skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
#endif

 is_lso = (skb_shinfo(skb)->gso_size != 0);

 if (is_lso) {
  /* length of headers */
  if (ip_hdr(skb)->protocol == IPPROTO_UDP)
   /* only queue eth + ip headers separately for UDP */
   hdrlen = skb_transport_offset(skb);
  else
   hdrlen = skb_tcp_all_headers(skb);
  if (skb_headlen(skb) < hdrlen) {
   netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n");
   /* if this is required, would need to copy to single buffer */
   return NETDEV_TX_BUSY;
  }
 } else
  hdrlen = min(skb_headlen(skb), bp->max_tx_length);

#if defined(DEBUG) && defined(VERBOSE_DEBUG)
 netdev_vdbg(bp->dev,
      "start_xmit: queue %hu len %u head %p data %p tail %p end %p\n",
      queue_index, skb->len, skb->head, skb->data,
      skb_tail_pointer(skb), skb_end_pointer(skb));
 print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1,
         skb->data, 16, true);
#endif

 /* Count how many TX buffer descriptors are needed to send this
 * socket buffer: skb fragments of jumbo frames may need to be
 * split into many buffer descriptors.
 */

 if (is_lso && (skb_headlen(skb) > hdrlen))
  /* extra header descriptor if also payload in first buffer */
  desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1;
 else
  desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
 nr_frags = skb_shinfo(skb)->nr_frags;
 for (f = 0; f < nr_frags; f++) {
  frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
  desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length);
 }

 spin_lock_irqsave(&queue->tx_ptr_lock, flags);

 /* This is a hard error, log it. */
 if (CIRC_SPACE(queue->tx_head, queue->tx_tail,
         bp->tx_ring_size) < desc_cnt) {
  netif_stop_subqueue(dev, queue_index);
  netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n",
      queue->tx_head, queue->tx_tail);
  ret = NETDEV_TX_BUSY;
  goto unlock;
 }

 /* Map socket buffer for DMA transfer */
 if (!macb_tx_map(bp, queue, skb, hdrlen)) {
  dev_kfree_skb_any(skb);
  goto unlock;
 }

 /* Make newly initialized descriptor visible to hardware */
 wmb();
 skb_tx_timestamp(skb);
 netdev_tx_sent_queue(netdev_get_tx_queue(bp->dev, queue_index),
        skb->len);

 spin_lock(&bp->lock);
 macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
 spin_unlock(&bp->lock);

 if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1)
  netif_stop_subqueue(dev, queue_index);

unlock:
 spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);

 return ret;
}

static void macb_init_rx_buffer_size(struct macb *bp, size_t size)
{
 if (!macb_is_gem(bp)) {
  bp->rx_buffer_size = MACB_RX_BUFFER_SIZE;
 } else {
  bp->rx_buffer_size = size;

  if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) {
   netdev_dbg(bp->dev,
       "RX buffer must be multiple of %d bytes, expanding\n",
       RX_BUFFER_MULTIPLE);
   bp->rx_buffer_size =
    roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE);
  }
 }

 netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%zu]\n",
     bp->dev->mtu, bp->rx_buffer_size);
}

static void gem_free_rx_buffers(struct macb *bp)
{
 struct sk_buff  *skb;
 struct macb_dma_desc *desc;
 struct macb_queue *queue;
 dma_addr_t  addr;
 unsigned int q;
 int i;

 for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
  if (!queue->rx_skbuff)
   continue;

  for (i = 0; i < bp->rx_ring_size; i++) {
   skb = queue->rx_skbuff[i];

   if (!skb)
    continue;

   desc = macb_rx_desc(queue, i);
   addr = macb_get_addr(bp, desc);

   dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size,
     DMA_FROM_DEVICE);
   dev_kfree_skb_any(skb);
   skb = NULL;
  }

  kfree(queue->rx_skbuff);
  queue->rx_skbuff = NULL;
 }
}

static void macb_free_rx_buffers(struct macb *bp)
{
 struct macb_queue *queue = &bp->queues[0];

 if (queue->rx_buffers) {
  dma_free_coherent(&bp->pdev->dev,
      bp->rx_ring_size * bp->rx_buffer_size,
      queue->rx_buffers, queue->rx_buffers_dma);
  queue->rx_buffers = NULL;
 }
}

static unsigned int macb_tx_ring_size_per_queue(struct macb *bp)
{
 return macb_dma_desc_get_size(bp) * bp->tx_ring_size + bp->tx_bd_rd_prefetch;
}

static unsigned int macb_rx_ring_size_per_queue(struct macb *bp)
{
 return macb_dma_desc_get_size(bp) * bp->rx_ring_size + bp->rx_bd_rd_prefetch;
}

static void macb_free_consistent(struct macb *bp)
{
 struct device *dev = &bp->pdev->dev;
 struct macb_queue *queue;
 unsigned int q;
 size_t size;

 if (bp->rx_ring_tieoff) {
  dma_free_coherent(dev, macb_dma_desc_get_size(bp),
      bp->rx_ring_tieoff, bp->rx_ring_tieoff_dma);
  bp->rx_ring_tieoff = NULL;
 }

 bp->macbgem_ops.mog_free_rx_buffers(bp);

 size = bp->num_queues * macb_tx_ring_size_per_queue(bp);
 dma_free_coherent(dev, size, bp->queues[0].tx_ring, bp->queues[0].tx_ring_dma);

 size = bp->num_queues * macb_rx_ring_size_per_queue(bp);
 dma_free_coherent(dev, size, bp->queues[0].rx_ring, bp->queues[0].rx_ring_dma);

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=81 G=88

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.