cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/ethernet/cadence/macb.c

/*
 * Cadence MACB/GEM Ethernet Controller driver
 *
 * Copyright (C) 2004-2006 Atmel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.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/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/macb.h>
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include "macb.h"


#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 RX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)     \
                                 * (bp)->rx_ring_size)


#define DEFAULT_TX_RING_SIZE	512 
/* must be power of 2 */

#define MIN_TX_RING_SIZE	64

#define MAX_TX_RING_SIZE	4096

#define TX_RING_BYTES(bp)	(macb_dma_desc_get_size(bp)     \
                                 * (bp)->tx_ring_size)

/* 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(RXUBR)      \
                                 | 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))

/* 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)))

#define GEM_MAX_TX_LEN		((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1)))


#define GEM_MTU_MIN_SIZE	ETH_MIN_MTU

#define MACB_NETIF_LSO		(NETIF_F_TSO | NETIF_F_UFO)


#define MACB_WOL_HAS_MAGIC_PACKET	(0x1 << 0)

#define MACB_WOL_ENABLED		(0x1 << 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	1230

/* DMA buffer descriptor might be different size
 * depends on hardware configuration.
 */

static unsigned int macb_dma_desc_get_size(struct macb *bp) { #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) return sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64); #endif return sizeof(struct macb_dma_desc); }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo45100.00%1100.00%
Total45100.00%1100.00%


static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int idx) { #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT /* Dma buffer descriptor is 4 words length (instead of 2 words) * for 64b GEM. */ if (bp->hw_dma_cap == HW_DMA_CAP_64B) idx <<= 1; #endif return idx; }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo37100.00%1100.00%
Total37100.00%1100.00%

#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)); }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo38100.00%1100.00%
Total38100.00%1100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen1970.37%150.00%
Zach Brown829.63%150.00%
Total27100.00%2100.00%


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]; }

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen2143.75%125.00%
Rafal Ozieblo2041.67%125.00%
Zach Brown48.33%125.00%
Cyrille Pitchen36.25%125.00%
Total48100.00%4100.00%


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)]; }

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen2678.79%133.33%
Zach Brown412.12%133.33%
Cyrille Pitchen39.09%133.33%
Total33100.00%3100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen3274.42%125.00%
Zach Brown49.30%125.00%
Rafal Ozieblo49.30%125.00%
Cyrille Pitchen36.98%125.00%
Total43100.00%4100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen1970.37%150.00%
Zach Brown829.63%150.00%
Total27100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen2659.09%150.00%
Rafal Ozieblo1840.91%150.00%
Total44100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Havard Skinnemoen2784.38%133.33%
Nicolas Ferre39.38%133.33%
Zach Brown26.25%133.33%
Total32100.00%3100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko24100.00%1100.00%
Total24100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko28100.00%1100.00%
Total28100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko24100.00%1100.00%
Total24100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko28100.00%1100.00%
Total28100.00%1100.00%

/* 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); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko55100.00%1100.00%
Total55100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Shevchenko50100.00%1100.00%
Total50100.00%1100.00%


static void macb_set_hwaddr(struct macb *bp) { u32 bottom; u16 top; bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr)); macb_or_gem_writel(bp, SA1B, bottom); top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4))); macb_or_gem_writel(bp, SA1T, top); /* 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); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7154.62%120.00%
Joachim Eastwood5643.08%240.00%
Jamie Iles21.54%120.00%
Cyrille Pitchen10.77%120.00%
Total130100.00%5100.00%


static void macb_get_hwaddr(struct macb *bp) { struct macb_platform_data *pdata; u32 bottom; u16 top; u8 addr[6]; int i; pdata = dev_get_platdata(&bp->pdev->dev); /* 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); if (pdata && pdata->rev_eth_addr) { addr[5] = bottom & 0xff; addr[4] = (bottom >> 8) & 0xff; addr[3] = (bottom >> 16) & 0xff; addr[2] = (bottom >> 24) & 0xff; addr[1] = top & 0xff; addr[0] = (top & 0xff00) >> 8; } else { 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)) { memcpy(bp->dev->dev_addr, addr, sizeof(addr)); return; } } dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); eth_hw_addr_random(bp->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen13146.29%110.00%
Joachim Eastwood12343.46%220.00%
Sven Schnelle165.65%110.00%
Andy Shevchenko41.41%110.00%
Jingoo Han41.41%110.00%
Jamie Iles20.71%110.00%
Danny Kukawka10.35%110.00%
Cyrille Pitchen10.35%110.00%
Moritz Fischer10.35%110.00%
Total283100.00%10100.00%


static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct macb *bp = bus->priv; int value; macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | MACB_BF(RW, MACB_MAN_READ) | MACB_BF(PHYA, mii_id) | MACB_BF(REGA, regnum) | MACB_BF(CODE, MACB_MAN_CODE))); /* wait for end of transfer */ while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) cpu_relax(); value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); return value; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen8577.98%150.00%
frederic Rodo2422.02%150.00%
Total109100.00%2100.00%


static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct macb *bp = bus->priv; macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | MACB_BF(RW, MACB_MAN_WRITE) | MACB_BF(PHYA, mii_id) | MACB_BF(REGA, regnum) | MACB_BF(CODE, MACB_MAN_CODE) | MACB_BF(DATA, value))); /* wait for end of transfer */ while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR))) cpu_relax(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7270.59%150.00%
frederic Rodo3029.41%150.00%
Total102100.00%2100.00%

/** * macb_set_tx_clk() - Set a clock to a new frequency * @clk Pointer to the clock to change * @rate New frequency in Hz * @dev Pointer to the struct net_device */
static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) { long ferr, rate, rate_rounded; if (!clk) return; switch (speed) { case SPEED_10: rate = 2500000; break; case SPEED_100: rate = 25000000; break; case SPEED_1000: rate = 125000000; break; default: return; } rate_rounded = clk_round_rate(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(dev, "unable to generate target frequency: %ld Hz\n", rate); if (clk_set_rate(clk, rate_rounded)) netdev_err(dev, "adjusting tx_clk failed.\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Sören Brinkmann12695.45%266.67%
Cyrille Pitchen64.55%133.33%
Total132100.00%3100.00%


static void macb_handle_link_change(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct phy_device *phydev = dev->phydev; unsigned long flags; int status_change = 0; spin_lock_irqsave(&bp->lock, flags); if (phydev->link) { if ((bp->speed != phydev->speed) || (bp->duplex != phydev->duplex)) { u32 reg; reg = macb_readl(bp, NCFGR); reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); if (macb_is_gem(bp)) reg &= ~GEM_BIT(GBE); if (phydev->duplex) reg |= MACB_BIT(FD); if (phydev->speed == SPEED_100) reg |= MACB_BIT(SPD); if (phydev->speed == SPEED_1000 && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) reg |= GEM_BIT(GBE); macb_or_gem_writel(bp, NCFGR, reg); bp->speed = phydev->speed; bp->duplex = phydev->duplex; status_change = 1; } } if (phydev->link != bp->link) { if (!phydev->link) { bp->speed = 0; bp->duplex = -1; } bp->link = phydev->link; status_change = 1; } spin_unlock_irqrestore(&bp->lock, flags); if (status_change) { if (phydev->link) { /* Update the TX clock rate if and only if the link is * up and there has been a link change. */ macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); netif_carrier_on(dev); netdev_info(dev, "link up (%d/%s)\n", phydev->speed, phydev->duplex == DUPLEX_FULL ? "Full" : "Half"); } else { netif_carrier_off(dev); netdev_info(dev, "link down\n"); } } }

Contributors

PersonTokensPropCommitsCommitProp
frederic Rodo14243.56%19.09%
Håvard Skinnemoen9529.14%19.09%
Patrice Vilchez319.51%19.09%
Nicolas Ferre195.83%218.18%
Sören Brinkmann133.99%19.09%
Jaeden Amero133.99%19.09%
Jamie Iles82.45%19.09%
Philippe Reynes20.61%19.09%
Atsushi Nemoto20.61%19.09%
Anton Vorontsov10.31%19.09%
Total326100.00%11100.00%

/* based on au1000_eth. c*/
static int macb_mii_probe(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct macb_platform_data *pdata; struct phy_device *phydev; int phy_irq; int ret; phydev = phy_find_first(bp->mii_bus); if (!phydev) { netdev_err(dev, "no PHY found\n"); return -ENXIO; } pdata = dev_get_platdata(&bp->pdev->dev); if (pdata && gpio_is_valid(pdata->phy_irq_pin)) { ret = devm_gpio_request(&bp->pdev->dev, pdata->phy_irq_pin, "phy int"); if (!ret) { phy_irq = gpio_to_irq(pdata->phy_irq_pin); phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; } } else { phydev->irq = PHY_POLL; } /* attach the mac to the phy */ ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, bp->phy_interface); if (ret) { netdev_err(dev, "Could not attach to PHY\n"); return ret; } /* mask with MAC supported features */ if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) phydev->supported &= PHY_GBIT_FEATURES; else phydev->supported &= PHY_BASIC_FEATURES; if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) phydev->supported &= ~SUPPORTED_1000baseT_Half; phydev->advertising = phydev->supported; bp->link = 0; bp->speed = 0; bp->duplex = -1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic Rodo9236.65%19.09%
Joachim Eastwood8132.27%19.09%
Håvard Skinnemoen176.77%19.09%
Nathan Sullivan155.98%19.09%
Patrice Vilchez145.58%19.09%
Bartosz Folta93.59%19.09%
Jiri Pirko83.19%19.09%
Nicolas Ferre62.39%19.09%
Jamie Iles62.39%19.09%
Jean-Christophe Plagniol-Villard20.80%19.09%
Boris Brezillon10.40%19.09%
Total251100.00%11100.00%


static int macb_mii_init(struct macb *bp) { struct macb_platform_data *pdata; struct device_node *np; int err = -ENXIO, i; /* 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; bp->mii_bus->write = &macb_mdio_write; 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; pdata = dev_get_platdata(&bp->pdev->dev); dev_set_drvdata(&bp->dev->dev, bp->mii_bus); np = bp->pdev->dev.of_node; if (np) { /* try dt phy registration */ err = of_mdiobus_register(bp->mii_bus, np); /* fallback to standard phy registration if no phy were * found during dt phy registration */ if (!err && !phy_find_first(bp->mii_bus)) { for (i = 0; i < PHY_MAX_ADDR; i++) { struct phy_device *phydev; phydev = mdiobus_scan(bp->mii_bus, i); if (IS_ERR(phydev) && PTR_ERR(phydev) != -ENODEV) { err = PTR_ERR(phydev); break; } } if (err) goto err_out_unregister_bus; } } else { for (i = 0; i < PHY_MAX_ADDR; i++) bp->mii_bus->irq[i] = PHY_POLL; if (pdata) bp->mii_bus->phy_mask = pdata->phy_mask; err = mdiobus_register(bp->mii_bus); } 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: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Boris Brezillon14138.11%210.00%
frederic Rodo11531.08%15.00%
Lennert Buytenhek3910.54%210.00%
Bartosz Folta246.49%15.00%
Håvard Skinnemoen123.24%15.00%
Sergei Shtylyov82.16%15.00%
Florian Fainelli82.16%210.00%
Andy Fleming71.89%15.00%
Atsushi Nemoto51.35%15.00%
Jingoo Han41.08%15.00%
Jamie Iles20.54%210.00%
Moritz Fischer20.54%210.00%
Andrew Lunn10.27%15.00%
Uwe Kleine-König10.27%15.00%
Cyrille Pitchen10.27%15.00%
Total370100.00%20100.00%


static void macb_update_stats(struct macb *bp) { u32 *p = &bp->hw_stats.macb.rx_pause_frames; u32 *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); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7580.65%125.00%
Andy Shevchenko1313.98%125.00%
Jamie Iles44.30%125.00%
David S. Miller11.08%125.00%
Total93100.00%4100.00%


static int macb_halt_tx(struct macb *bp) { unsigned long halt_time, timeout; u32 status; macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT)); timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT); do { halt_time = jiffies; status = macb_readl(bp, TSR); if (!(status & MACB_BIT(TGO))) return 0; usleep_range(10, 250); } while (time_before(halt_time, timeout)); return -ETIMEDOUT; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre5656.00%125.00%
Håvard Skinnemoen3737.00%125.00%
Richard Röjfors44.00%125.00%
Erik Waling33.00%125.00%
Total100100.00%4100.00%


static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) { 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) { dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen98100.00%1100.00%
Total98100.00%1100.00%


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); } #endif desc->addr = lower_32_bits(addr); }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo4771.21%150.00%
Harini Katakam1928.79%150.00%
Total66100.00%2100.00%


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)); return addr; }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo7589.29%150.00%
Harini Katakam910.71%150.00%
Total84100.00%2100.00%


static void macb_tx_error_task(struct work_struct *work) { struct macb_queue *queue = container_of(work, struct macb_queue, tx_error_task); struct macb *bp = queue->bp; struct macb_tx_skb *tx_skb; struct macb_dma_desc *desc; struct sk_buff *skb; unsigned int tail; unsigned long flags; netdev_vdbg(bp->dev, "macb_tx_error_task: q = %u, t = %u, h = %u\n", (unsigned int)(queue - bp->queues), queue->tx_tail, queue->tx_head); /* Prevent the queue IRQ handlers from running: each of them may call * macb_tx_interrupt(), 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. */ 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)) /* Just complain for now, reinitializing TX path can be good */ netdev_err(bp->dev, "BUG: halt tx timed out\n"); /* 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); 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->stats.tx_packets++; bp->stats.tx_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); } /* 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)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif /* 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); /* 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); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre17738.39%18.33%
Cyrille Pitchen16636.01%216.67%
Gregory CLEMENT316.72%18.33%
Harini Katakam245.21%18.33%
Richard Röjfors204.34%18.33%
Havard Skinnemoen132.82%18.33%
Rafal Ozieblo122.60%18.33%
Håvard Skinnemoen91.95%18.33%
Tord Andersson40.87%18.33%
Moritz Fischer30.65%18.33%
Zach Brown20.43%18.33%
Total461100.00%12100.00%


static void macb_tx_interrupt(struct macb_queue *queue) { unsigned int tail; unsigned int head; u32 status; struct macb *bp = queue->bp; u16 queue_index = queue - bp->queues; status = macb_readl(bp, TSR); macb_writel(bp, TSR, status); if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(queue, ISR, MACB_BIT(TCOMP)); netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n", (unsigned long)status); head = queue->tx_head; for (tail = queue->tx_tail; tail != head; 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) { netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", macb_tx_ring_wrap(bp, tail), skb->data); bp->stats.tx_packets++; bp->stats.tx_bytes += skb->len; } /* Now we can safely release resources */ macb_tx_unmap(bp, tx_skb); /* 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; } } 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); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen11538.85%19.09%
Cyrille Pitchen6421.62%218.18%
Nicolas Ferre6421.62%327.27%
Havard Skinnemoen3511.82%327.27%
Steffen Trumtrar103.38%19.09%
Zach Brown82.70%19.09%
Total296100.00%11100.00%


static void gem_rx_refill(struct macb *bp) { unsigned int entry; struct sk_buff *skb; dma_addr_t paddr; struct macb_dma_desc *desc; while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, bp->rx_ring_size) > 0) { entry = macb_rx_ring_wrap(bp, bp->rx_prepared_head); /* Make hw descriptor updates visible to CPU */ rmb(); bp->rx_prepared_head++; desc = macb_rx_desc(bp, entry); if (!bp->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; } bp->rx_skbuff[entry] = skb; if (entry == bp->rx_ring_size - 1) paddr |= MACB_BIT(RX_WRAP); macb_set_addr(bp, desc, paddr); desc->ctrl = 0; /* properly align Ethernet header */ skb_reserve(skb, NET_IP_ALIGN); } else { desc->addr &= ~MACB_BIT(RX_USED); desc->ctrl = 0; } } /* Make descriptor updates visible to hardware */ wmb(); netdev_vdbg(bp->dev, "rx ring: prepared head %d, tail %d\n", bp->rx_prepared_head, bp->rx_tail); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre11343.80%18.33%
Håvard Skinnemoen5019.38%18.33%
Sören Brinkmann3112.02%18.33%
Rafal Ozieblo197.36%18.33%
Punnaiah Choudary Kalluri176.59%18.33%
Zach Brown83.10%18.33%
Havard Skinnemoen72.71%216.67%
Pradeep A. Dalvi51.94%18.33%
Harini Katakam41.55%18.33%
Moritz Fischer20.78%18.33%
Eric Dumazet20.78%18.33%
Total258100.00%12100.00%

/* Mark DMA descriptors from begin up to and not including end as unused */
static void discard_partial_frame(struct macb *bp, unsigned int begin, unsigned int end) { unsigned int frag; for (frag = begin; frag != end; frag++) { struct macb_dma_desc *desc = macb_rx_desc(bp, 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. */ }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre6498.46%150.00%
Moritz Fischer11.54%150.00%
Total65100.00%2100.00%


static int gem_rx(struct macb *bp, int budget) { 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, bp->rx_tail); desc = macb_rx_desc(bp, entry); /* Make hw descriptor updates visible to CPU */ rmb(); rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false; addr = macb_get_addr(bp, desc); ctrl = desc->ctrl; if (!rxused) break; bp->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->stats.rx_dropped++; break; } skb = bp->rx_skbuff[entry]; if (unlikely(!skb)) { netdev_err(bp->dev, "inconsistent Rx descriptor chain\n"); bp->stats.rx_dropped++; break; } /* now everything is ready for receiving packet */ bp->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->stats.rx_packets++; bp->stats.rx_bytes += skb->len; #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 netif_receive_skb(skb); } gem_rx_refill(bp); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre32980.05%112.50%
Cyrille Pitchen399.49%225.00%
Harini Katakam327.79%225.00%
Rafal Ozieblo61.46%112.50%
Sören Brinkmann30.73%112.50%
Zach Brown20.49%112.50%
Total411100.00%8100.00%


static int macb_rx_frame(struct macb *bp, 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; desc = macb_rx_desc(bp, 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->stats.rx_dropped++; for (frag = first_frag; ; frag++) { desc = macb_rx_desc(bp, 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(bp, frag), frag_len); offset += bp->rx_buffer_size; desc = macb_rx_desc(bp, 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->stats.rx_packets++; bp->stats.rx_bytes += skb->len; netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n", skb->len, skb->csum); netif_receive_skb(skb); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre18753.74%216.67%
Håvard Skinnemoen10831.03%18.33%
Havard Skinnemoen288.05%433.33%
Cyrille Pitchen144.02%18.33%
Harini Katakam41.15%18.33%
Zach Brown41.15%18.33%
Arnaldo Carvalho de Melo20.57%18.33%
Moritz Fischer10.29%18.33%
Total348100.00%12100.00%


static inline void macb_init_rx_ring(struct macb *bp) { dma_addr_t addr; struct macb_dma_desc *desc = NULL; int i; addr = bp->rx_buffers_dma; for (i = 0; i < bp->rx_ring_size; i++) { desc = macb_rx_desc(bp, i); macb_set_addr(bp, desc, addr); desc->ctrl = 0; addr += bp->rx_buffer_size; } desc->addr |= MACB_BIT(RX_WRAP); bp->rx_tail = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen6670.97%250.00%
Rafal Ozieblo2324.73%125.00%
Zach Brown44.30%125.00%
Total93100.00%4100.00%


static int macb_rx(struct macb *bp, int budget) { bool reset_rx_queue = false; int received = 0; unsigned int tail; int first_frag = -1; for (tail = bp->rx_tail; budget > 0; tail++) { struct macb_dma_desc *desc = macb_rx_desc(bp, tail); u32 ctrl; /* Make hw descriptor updates visible to CPU */ rmb(); ctrl = desc->ctrl; if (!(desc->addr & MACB_BIT(RX_USED))) break; if (ctrl & MACB_BIT(RX_SOF)) { if (first_frag != -1) discard_partial_frame(bp, 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(bp, 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(bp); macb_writel(bp, RBQP, bp->rx_ring_dma); macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); spin_unlock_irqrestore(&bp->lock, flags); return received; } if (first_frag != -1) bp->rx_tail = first_frag; else bp->rx_tail = tail; return received; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen16952.32%120.00%
Cyrille Pitchen13341.18%120.00%
Havard Skinnemoen195.88%240.00%
Rafal Ozieblo20.62%120.00%
Total323100.00%5100.00%


static int macb_poll(struct napi_struct *napi, int budget) { struct macb *bp = container_of(napi, struct macb, napi); int work_done; u32 status; status = macb_readl(bp, RSR); macb_writel(bp, RSR, status); work_done = 0; netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n", (unsigned long)status, budget); work_done = bp->macbgem_ops.mog_rx(bp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); /* Packets received while interrupts were disabled */ status = macb_readl(bp, RSR); if (status) { if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) macb_writel(bp, ISR, MACB_BIT(RCOMP)); napi_reschedule(napi); } else { macb_writel(bp, IER, MACB_RX_INT_FLAGS); } } /* TODO: Handle errors */ return work_done; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7849.06%112.50%
Sören Brinkmann3421.38%112.50%
Nicolas Ferre2415.09%225.00%
Stephen Hemminger1710.69%112.50%
Eric Dumazet31.89%112.50%
Joshua Hoke21.26%112.50%
Havard Skinnemoen10.63%112.50%
Total159100.00%8100.00%


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 & MACB_RX_INT_FLAGS) { /* 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, MACB_RX_INT_FLAGS); if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(queue, ISR, MACB_BIT(RCOMP)); if (napi_schedule_prep(&bp->napi)) { netdev_vdbg(bp->dev, "scheduling RX softirq\n"); __napi_schedule(&bp->napi); } } 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; } if (status & MACB_BIT(TCOMP)) macb_tx_interrupt(queue); /* 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 at91 manual, section 41.3.1 or the Zynq manual * section 16.7.4 for details. */ 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 */ if (macb_is_gem(bp)) bp->hw_stats.gem.rx_overruns++; else bp->hw_stats.macb.rx_overruns++; if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(queue, ISR, MACB_BIT(ISR_ROVR)); } if (status & MACB_BIT(HRESP)) { /* TODO: Reset the hardware, and maybe move the * netdev_err to a lower-priority context as well * (work queue?) */ 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; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen15032.12%14.55%
Nathan Sullivan8818.84%313.64%
Sören Brinkmann5110.92%14.55%
Cyrille Pitchen4810.28%29.09%
Nicolas Ferre337.07%29.09%
Jamie Iles224.71%29.09%
Alexander Stein194.07%14.55%
Havard Skinnemoen153.21%14.55%
Steffen Trumtrar102.14%14.55%
Stephen Hemminger81.71%14.55%
Joshua Hoke71.50%14.55%
Erik Waling30.64%14.55%
frederic Rodo30.64%14.55%
Zumeng Chen30.64%14.55%
Moritz Fischer30.64%14.55%
Joachim Eastwood20.43%14.55%
Ben Hutchings20.43%14.55%
Total467100.00%22100.00%

#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); }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen4457.14%150.00%
Thomas Petazzoni3342.86%150.00%
Total77100.00%2100.00%

#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); } 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); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen55975.13%222.22%
Rafal Ozieblo16522.18%222.22%
Zach Brown111.48%111.11%
Harini Katakam40.54%111.11%
Håvard Skinnemoen20.27%111.11%
Havard Skinnemoen20.27%111.11%
Moritz Fischer10.13%111.11%
Total744100.00%9100.00%


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 */ if (!skb_is_nonlinear(skb)) return features; /* length of header */ hdrlen = skb_transport_offset(skb); if (ip_hdr(skb)->protocol == IPPROTO_TCP) hdrlen += tcp_hdrlen(skb); /* For LSO: * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo156100.00%1100.00%
Total156100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Helmut Buchsbaum63100.00%1100.00%
Total63100.00%1100.00%


static int 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 long flags; unsigned int desc_cnt, nr_frags, frag_size, f; unsigned int hdrlen; bool is_lso, is_udp = 0; is_lso = (skb_shinfo(skb)->gso_size != 0); if (is_lso) { is_udp = !!(ip_hdr(skb)->protocol == IPPROTO_UDP); /* length of headers */ if (is_udp) /* only queue eth + ip headers separately for UDP */ hdrlen = skb_transport_offset(skb); else hdrlen = skb_transport_offset(skb) + tcp_hdrlen(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(&bp->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); spin_unlock_irqrestore(&bp->lock, flags); netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", queue->tx_head, queue->tx_tail); return NETDEV_TX_BUSY; } if (macb_clear_csum(skb)) { dev_kfree_skb_any(skb); 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); macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1) netif_stop_subqueue(dev, queue_index); unlock: spin_unlock_irqrestore(&bp->lock, flags); return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Rafal Ozieblo15129.09%15.26%
Cyrille Pitchen12724.47%210.53%
Håvard Skinnemoen8115.61%15.26%
Nicolas Ferre6712.91%210.53%
Sören Brinkmann183.47%15.26%
Helmut Buchsbaum142.70%15.26%
Jamie Iles132.50%15.26%
Havard Skinnemoen112.12%15.26%
Andy Shevchenko101.93%15.26%
Dongdong Deng91.73%15.26%
Zach Brown61.16%15.26%
Arnaldo Carvalho de Melo61.16%210.53%
Wei Yongjun30.58%15.26%
Patrick McHardy10.19%15.26%
Eric W. Biedermann10.19%15.26%
Moritz Fischer10.19%15.26%
Total519100.00%19100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre9198.91%150.00%
Alexey Dobriyan11.09%150.00%
Total92100.00%2100.00%


static void gem_free_rx_buffers(struct macb *bp) { struct sk_buff *skb; struct macb_dma_desc *desc; dma_addr_t addr; int i; if (!bp->rx_skbuff) return; for (i = 0; i < bp->rx_ring_size; i++) { skb = bp->rx_skbuff[i]; if (!skb) continue; desc = macb_rx_desc(bp, 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(bp->rx_skbuff); bp->rx_skbuff = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre9475.20%222.22%
Håvard Skinnemoen1612.80%111.11%
Rafal Ozieblo64.80%111.11%
Zach Brown32.40%111.11%
Harini Katakam21.60%111.11%
Sören Brinkmann21.60%111.11%
Moritz Fischer10.80%111.11%
Havard Skinnemoen10.80%111.11%
Total125100.00%9100.00%


static void macb_free_rx_buffers(struct macb *bp) { if (bp->rx_buffers) { dma_free_coherent(&bp->pdev->dev, bp->rx_ring_size * bp->rx_buffer_size, bp->rx_buffers, bp->rx_buffers_dma); bp->rx_buffers = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre4894.12%266.67%
Zach Brown35.88%133.33%
Total51100.00%3100.00%


static void macb_free_consistent(struct macb *bp) { struct macb_queue *queue; unsigned int q; bp->macbgem_ops.mog_free_rx_buffers(bp); if (bp->rx_ring) { dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES(bp), bp->rx_ring, bp->rx_ring_dma); bp->rx_ring = NULL; } for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { kfree(queue->tx_skb); queue->tx_skb = NULL; if (queue->tx_ring) { dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES(bp), queue->tx_ring, queue->tx_ring_dma); queue->tx_ring = NULL; } } }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7452.11%125.00%
Cyrille Pitchen5236.62%125.00%
Nicolas Ferre107.04%125.00%
Zach Brown64.23%125.00%
Total142100.00%4100.00%


static int gem_alloc_rx_buffers(struct macb *bp) { int size; size = bp->rx_ring_size * sizeof(struct sk_buff *); bp->rx_skbuff = kzalloc(size, GFP_KERNEL); if (!bp->rx_skbuff) return -ENOMEM; else netdev_dbg(bp->dev, "Allocated %d RX struct sk_buff entries at %p\n", bp->rx_ring_size, bp->rx_skbuff); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre5882.86%133.33%
Zach Brown710.00%133.33%
Håvard Skinnemoen57.14%133.33%
Total70100.00%3100.00%


static int macb_alloc_rx_buffers(struct macb *bp) { int size; size = bp->rx_ring_size * bp->rx_buffer_size; bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size, &bp->rx_buffers_dma, GFP_KERNEL); if (!bp->rx_buffers) return -ENOMEM; netdev_dbg(bp->dev, "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n", size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre5970.24%250.00%
Håvard Skinnemoen2226.19%125.00%
Zach Brown33.57%125.00%
Total84100.00%4100.00%


static int macb_alloc_consistent(struct macb *bp) { struct macb_queue *queue; unsigned int q; int size; for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { size = TX_RING_BYTES(bp); queue->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size, &queue->tx_ring_dma, GFP_KERNEL); if (!queue->tx_ring) goto out_err; netdev_dbg(bp->dev, "Allocated TX ring for queue %u of %d bytes at %08lx (mapped %p)\n", q, size, (unsigned long)queue->tx_ring_dma, queue->tx_ring); size = bp->tx_ring_size * sizeof(struct macb_tx_skb); queue->tx_skb = kmalloc(size, GFP_KERNEL); if (!queue->tx_skb) goto out_err; } size = RX_RING_BYTES(bp); bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size, &bp->rx_ring_dma, GFP_KERNEL); if (!bp->rx_ring) goto out_err; netdev_dbg(bp->dev, "Allocated RX ring of %d bytes at %08lx (mapped %p)\n", size, (unsigned long)bp->rx_ring_dma, bp->rx_ring); if (bp->macbgem_ops.mog_alloc_rx_buffers(bp)) goto out_err; return 0; out_err: macb_free_consistent(bp); return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen11849.58%116.67%
Cyrille Pitchen8134.03%116.67%
Nicolas Ferre2811.76%233.33%
Zach Brown93.78%116.67%
Jamie Iles20.84%116.67%
Total238100.00%6100.00%


static void gem_init_rings(struct macb *bp) { struct macb_queue *queue; struct macb_dma_desc *desc = NULL; unsigned int q; int i; for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { for (i = 0; i < bp->tx_ring_size; i++) { desc = macb_tx_desc(queue, i); macb_set_addr(bp, desc, 0); desc->ctrl = MACB_BIT(TX_USED); } desc->ctrl |= MACB_BIT(TX_WRAP); queue->tx_head = 0; queue->tx_tail = 0; } bp->rx_tail = 0; bp->rx_prepared_head = 0; gem_rx_refill(bp); }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen4834.78%120.00%
Nicolas Ferre4734.06%120.00%
Rafal Ozieblo2316.67%120.00%
Håvard Skinnemoen1611.59%120.00%
Zach Brown42.90%120.00%
Total138100.00%5100.00%


static void macb_init_rings(struct macb *bp) { int i; struct macb_dma_desc *desc = NULL; macb_init_rx_ring(bp); for (i = 0; i < bp->tx_ring_size; i++) { desc = macb_tx_desc(&bp->queues[0], i); macb_set_addr(bp, desc, 0); desc->ctrl = MACB_BIT(TX_USED); } bp->queues[0].tx_head = 0; bp->queues[0].tx_tail = 0; desc->ctrl |= MACB_BIT(TX_WRAP); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen5147.66%116.67%
Cyrille Pitchen2725.23%233.33%
Rafal Ozieblo2422.43%116.67%
Zach Brown43.74%116.67%
Ben Shelton10.93%116.67%
Total107100.00%6100.00%


static void macb_reset_hw(struct macb *bp) { struct macb_queue *queue; unsigned int q; /* Disable RX and TX (XXX: Should we halt the transmission * more gracefully?) */ macb_writel(bp, NCR, 0); /* Clear the stats registers (XXX: Update stats first?) */ macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); /* Clear all status flags */ macb_writel(bp, TSR, -1); macb_writel(bp, RSR, -1); /* Disable all interrupts */ for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { queue_writel(queue, IDR, -1); queue_readl(queue, ISR); if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(queue, ISR, -1); } }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen6249.21%120.00%
Cyrille Pitchen3930.95%120.00%
Nathan Sullivan1814.29%120.00%
Joachim Eastwood64.76%120.00%
Moritz Fischer10.79%120.00%
Total126100.00%5100.00%


static u32 gem_mdc_clk_div(struct macb *bp) { u32 config; unsigned long pclk_hz = clk_get_rate(bp->pclk); if (pclk_hz <= 20000000) config = GEM_BF(CLK, GEM_CLK_DIV8); else if (pclk_hz <= 40000000) config = GEM_BF(CLK, GEM_CLK_DIV16); else if (pclk_hz <= 80000000) config = GEM_BF(CLK, GEM_CLK_DIV32); else if (pclk_hz <= 120000000) config = GEM_BF(CLK, GEM_CLK_DIV48); else if (pclk_hz <= 160000000) config = GEM_BF(CLK, GEM_CLK_DIV64); else config = GEM_BF(CLK, GEM_CLK_DIV96); return config; }

Contributors

PersonTokensPropCommitsCommitProp
Jamie Iles9782.91%150.00%
Håvard Skinnemoen2017.09%150.00%
Total117100.00%2100.00%


static u32 macb_mdc_clk_div(struct macb *bp) { u32 config; unsigned long pclk_hz; if (macb_is_gem(bp)) return gem_mdc_clk_div(bp); pclk_hz = clk_get_rate(bp->pclk); if (pclk_hz <= 20000000) config = MACB_BF(CLK, MACB_CLK_DIV8); else if (pclk_hz <= 40000000) config = MACB_BF(CLK, MACB_CLK_DIV16); else if (pclk_hz <= 80000000) config = MACB_BF(CLK, MACB_CLK_DIV32); else config = MACB_BF(CLK, MACB_CLK_DIV64); return config; }

Contributors

PersonTokensPropCommitsCommitProp
Jamie Iles9292.00%150.00%
Håvard Skinnemoen88.00%150.00%
Total100100.00%2100.00%

/* Get the DMA bus width field of the network configuration register that we * should program. We find the width from decoding the design configuration * register to find the maximum supported data bus width. */
static u32 macb_dbw(struct macb *bp) { if (!macb_is_gem(bp)) return 0; switch (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1))) { case 4: return GEM_BF(DBW, GEM_DBW128); case 2: return GEM_BF(DBW, GEM_DBW64); case 1: default: return GEM_BF(DBW, GEM_DBW32); } }

Contributors

PersonTokensPropCommitsCommitProp
Jamie Iles72100.00%1100.00%
Total72100.00%1100.00%

/* Configure the receive DMA engine * - use the correct receive buffer size * - set best burst length for DMA operations * (if not supported by FIFO, it will fallback to default) * - set both rx/tx packet buffers to full memory size * These are configurable parameters for GEM. */
static void macb_configure_dma(struct macb *bp) { u32 dmacfg; if (macb_is_gem(bp)) { dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE); if (bp->dma_burst_length) dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg); dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); dmacfg &= ~GEM_BIT(ENDIA_PKT); if (bp->native_io) dmacfg &= ~GEM_BIT(ENDIA_DESC); else dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ if (bp->dev->features & NETIF_F_HW_CSUM) dmacfg |= GEM_BIT(TXCOEN); else dmacfg &= ~GEM_BIT(TXCOEN); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) dmacfg |= GEM_BIT(ADDR64); #endif netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", dmacfg); gem_writel(bp, DMACFG, dmacfg); } }

Contributors

PersonTokensPropCommitsCommitProp
Jamie Iles5529.73%18.33%
Nicolas Ferre5328.65%433.33%
Cyrille Pitchen2614.05%18.33%
Arun Chandran2111.35%216.67%
Harini Katakam126.49%18.33%
Rafal Ozieblo84.32%18.33%
Steffen Trumtrar73.78%18.33%
Andy Shevchenko31.62%18.33%
Total185100.00%12100.00%


static void macb_init_hw(struct macb *bp) { struct macb_queue *queue; unsigned int q; u32 config; macb_reset_hw(bp); macb_set_hwaddr(bp); config = macb_mdc_clk_div(bp); if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ if (bp->caps & MACB_CAPS_JUMBO) config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ else config |= MACB_BIT(BIG); /* Receive oversized frames */ if (bp->dev->flags & IFF_PROMISC) config |= MACB_BIT(CAF); /* Copy All Frames */ else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) config |= GEM_BIT(RXCOEN); if (!(bp->dev->flags & IFF_BROADCAST)) config |= MACB_BIT(NBC); /* No BroadCast */ config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) gem_writel(bp, JML, bp->jumbo_max_len); bp->speed = SPEED_10; bp->duplex = DUPLEX_HALF; bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; if (bp->caps & MACB_CAPS_JUMBO) bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; macb_configure_dma(bp); /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); #endif for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif /* Enable interrupts */ queue_writel(queue, IER, MACB_RX_INT_FLAGS | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); } /* Enable TX and RX */ macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen10526.25%16.25%
Harini Katakam9924.75%212.50%
Cyrille Pitchen7819.50%212.50%
Jamie Iles399.75%318.75%
Rafal Ozieblo205.00%16.25%
Punnaiah Choudary Kalluri205.00%16.25%
Vitalii Demianets123.00%16.25%
Havard Skinnemoen102.50%16.25%
Peter Korsgaard82.00%16.25%
frederic Rodo51.25%16.25%
Dan Carpenter30.75%16.25%
Joachim Eastwood10.25%16.25%
Total400100.00%16100.00%

/* The hash address register is 64 bits long and takes up two * locations in the memory map. The least significant bits are stored * in EMAC_HSL and the most significant bits in EMAC_HSH. * * The unicast hash enable and the multicast hash enable bits in the * network configuration register enable the reception of hash matched * frames. The destination address is reduced to a 6 bit index into * the 64 bit hash register using the following hash function. The * hash function is an exclusive or of every sixth bit of the * destination address. * * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] * * da[0] represents the least significant bit of the first byte * received, that is, the multicast/unicast indicator, and da[47] * represents the most significant bit of the last byte received. If * the hash index, hi[n], points to a bit that is set in the hash * register then the frame will be matched according to whether the * frame is multicast or unicast. A multicast match will be signalled * if the multicast hash enable bit is set, da[0] is 1 and the hash * index points to a bit set in the hash register. A unicast match * will be signalled if the unicast hash enable bit is set, da[0] is 0 * and the hash index points to a bit set in the hash register. To * receive all multicast frames, the hash register should be set with * all ones and the multicast hash enable bit should be set in the * network configuration register. */
static inline int hash_bit_value(int bitnr, __u8 *addr) { if (addr[bitnr / 8] & (1 << (bitnr % 8))) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Patrice Vilchez39100.00%1100.00%
Total39100.00%1100.00%

/* Return the hash index value for the specified address. */
static int hash_get_index(__u8 *addr) { int i, j, bitval; int hash_index = 0; for (j = 0; j < 6; j++) { for (i = 0, bitval = 0; i < 8; i++) bitval ^= hash_bit_value(i * 6 + j, addr); hash_index |= (bitval << j); } return hash_index; }

Contributors

PersonTokensPropCommitsCommitProp
Patrice Vilchez78100.00%1100.00%
Total78100.00%1100.00%

/* Add multicast addresses to the internal multicast-hash table. */
static void macb_sethashtable(struct net_device *dev) { struct netdev_hw_addr *ha; unsigned long mc_filter[2]; unsigned int bitnr; struct macb *bp = netdev_priv(dev); mc_filter[0] = 0; mc_filter[1] = 0; netdev_for_each_mc_addr(ha, dev) { bitnr = hash_get_index(ha->addr); mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); } macb_or_gem_writel(bp, HRB, mc_filter[0]); macb_or_gem_writel(bp, HRT, mc_filter[1]); }

Contributors

PersonTokensPropCommitsCommitProp
Patrice Vilchez9386.92%116.67%
Jiri Pirko109.35%350.00%
Jamie Iles21.87%116.67%
Moritz Fischer21.87%116.67%
Total107100.00%6100.00%

/* Enable/Disable promiscuous and multicast modes. */
static void macb_set_rx_mode(struct net_device *dev) { unsigned long cfg; struct macb *bp = netdev_priv(dev); cfg = macb_readl(bp, NCFGR); if (dev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ cfg |= MACB_BIT(CAF); /* Disable RX checksum offload */ if (macb_is_gem(bp)) cfg &= ~GEM_BIT(RXCOEN); } else { /* Disable promiscuous mode */ cfg &= ~MACB_BIT(CAF); /* Enable RX checksum offload only if requested */ if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM) cfg |= GEM_BIT(RXCOEN); } if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ macb_or_gem_writel(bp, HRB, -1); macb_or_gem_writel(bp, HRT, -1); cfg |= MACB_BIT(NCFGR_MTI); } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ macb_sethashtable(dev); cfg |= MACB_BIT(NCFGR_MTI); } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ macb_or_gem_writel(bp, HRB, 0); macb_or_gem_writel(bp, HRT, 0); cfg &= ~MACB_BIT(NCFGR_MTI); } macb_writel(bp, NCFGR, cfg); }

Contributors

PersonTokensPropCommitsCommitProp
Patrice Vilchez16577.46%120.00%
Cyrille Pitchen4018.78%240.00%
Jiri Pirko41.88%120.00%
Jamie Iles41.88%120.00%
Total213100.00%5100.00%


static int macb_open(struct net_device *dev) { struct macb *bp = netdev_priv(dev); size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN; int err; netdev_dbg(bp->dev, "open\n"); /* carrier starts down */ netif_carrier_off(dev); /* if the phy is not yet register, retry later*/ if (!dev->phydev) return -EAGAIN; /* RX buffers initialization */ macb_init_rx_buffer_size(bp, bufsz); err = macb_alloc_consistent(bp); if (err) { netdev_err(dev, "Unable to allocate DMA memory (error %d)\n", err); return err; } napi_enable(&bp->napi); bp->macbgem_ops.mog_init_rings(bp); macb_init_hw(bp); /* schedule a link state check */ phy_start(dev->phydev); netif_tx_start_all_queues(dev); if (bp->ptp_info) bp->ptp_info->ptp_init(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen7348.67%110.00%
Nicolas Ferre3221.33%330.00%
Andrei Pistirica1510.00%110.00%
frederic Rodo138.67%110.00%
Stephen Hemminger85.33%110.00%
Philippe Reynes42.67%110.00%
Jamie Iles42.67%110.00%
Cyrille Pitchen10.67%110.00%
Total150100.00%10100.00%


static int macb_close(struct net_device *dev) { struct macb *bp = netdev_priv(dev); unsigned long flags; netif_tx_stop_all_queues(dev); napi_disable(&bp->napi); if (dev->phydev) phy_stop(dev->phydev); spin_lock_irqsave(&bp->lock, flags); macb_reset_hw(bp); netif_carrier_off(dev); spin_unlock_irqrestore(&bp->lock, flags); macb_free_consistent(bp); if (bp->ptp_info) bp->ptp_info->ptp_remove(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen6966.35%116.67%
Andrei Pistirica1514.42%116.67%
Stephen Hemminger87.69%116.67%
frederic Rodo76.73%116.67%
Philippe Reynes43.85%116.67%
Cyrille Pitchen10.96%116.67%
Total104100.00%6100.00%


static int macb_change_mtu(struct net_device *dev, int new_mtu) { if (netif_running(dev)) return -EBUSY; dev->mtu = new_mtu; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Harini Katakam34100.00%1100.00%
Total34100.00%1100.00%


static void gem_update_stats(struct macb *bp) { unsigned int i; u32 *p = &bp->hw_stats.gem.tx_octets_31_0; for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { u32 offset = gem_statistics[i].offset; u64 val = bp->macb_reg_readl(bp, offset); bp->ethtool_stats[i] += val; *p += val; if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { /* Add GEM_OCTTXH, GEM_OCTRXH */ val = bp->macb_reg_readl(bp, offset + 4); bp->ethtool_stats[i] += ((u64)val) << 32; *(++p) += val; } } }

Contributors

PersonTokensPropCommitsCommitProp
Xander Huff8463.64%120.00%
Jamie Iles3929.55%120.00%
Andy Shevchenko75.30%240.00%
David S. Miller21.52%120.00%
Total132100.00%5100.00%


static struct net_device_stats *gem_get_stats(struct macb *bp) { struct gem_stats *hwstat = &bp->hw_stats.gem; struct net_device_stats *nstat = &bp->stats; gem_update_stats(bp); nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors + hwstat->rx_alignment_errors + hwstat->rx_resource_errors + hwstat->rx_overruns + hwstat->rx_oversize_frames + hwstat->rx_jabbers + hwstat->rx_undersized_frames + hwstat->rx_length_field_frame_errors); nstat->tx_errors = (hwstat->tx_late_collisions + hwstat->tx_excessive_collisions + hwstat->tx_underrun + hwstat->tx_carrier_sense_errors); nstat->multicast = hwstat->rx_multicast_frames; nstat->collisions = (hwstat->tx_single_collision_frames + hwstat->tx_multiple_collision_frames + hwstat->tx_excessive_collisions); nstat->rx_length_errors = (hwstat->rx_oversize_frames + hwstat->rx_jabbers + hwstat->rx_undersized_frames + hwstat->rx_length_field_frame_errors); nstat->rx_over_errors = hwstat->rx_resource_errors; nstat->rx_crc_errors = hwstat->rx_frame_check_sequence_errors; nstat->rx_frame_errors = hwstat->rx_alignment_errors; nstat->rx_fifo_errors = hwstat->rx_overruns; nstat->tx_aborted_errors = hwstat->tx_excessive_collisions; nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors; nstat->tx_fifo_errors = hwstat->tx_underrun; return nstat; }

Contributors

PersonTokensPropCommitsCommitProp
Jamie Iles207100.00%1100.00%
Total207100.00%1100.00%


static void gem_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct macb *bp; bp = netdev_priv(dev); gem_update_stats(bp); memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN); }

Contributors

PersonTokensPropCommitsCommitProp
Xander Huff54100.00%1100.00%
Total54100.00%1100.00%


static int gem_get_sset_count(struct net_device *dev, int sset) { switch (sset) { case ETH_SS_STATS: return GEM_STATS_LEN; default: return -EOPNOTSUPP; } }

Contributors

PersonTokensPropCommitsCommitProp
Xander Huff31100.00%1100.00%
Total31100.00%1100.00%


static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) { unsigned int i; switch (sset) { case ETH_SS_STATS: for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) memcpy(p, gem_statistics[i].stat_string, ETH_GSTRING_LEN); break; } }

Contributors

PersonTokensPropCommitsCommitProp
Xander Huff6298.41%150.00%
Andy Shevchenko11.59%150.00%
Total63100.00%2100.00%


static struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); struct net_device_stats *nstat = &bp->stats; struct macb_stats *hwstat = &bp->hw_stats.macb; if (macb_is_gem(bp)) return gem_get_stats(bp); /* read stats from hardware */ macb_update_stats(bp); /* Convert HW stats into netdevice stats */ nstat->rx_errors = (hwstat->rx_fcs_errors + hwstat->rx_align_errors + hwstat->rx_resource_errors + hwstat->rx_overruns + hwstat->rx_oversize_pkts + hwstat->rx_jabbers + hwstat->rx_undersize_pkts + hwstat->rx_length_mismatch); nstat->tx_errors = (hwstat->tx_late_cols + hwstat->tx_excessive_cols + hwstat->tx_underruns + hwstat->tx_carrier_errors + hwstat->sqe_test_errors); nstat->collisions = (hwstat->tx_single_cols + hwstat->tx_multiple_cols + hwstat->tx_excessive_cols); nstat->rx_length_errors = (hwstat->rx_oversize_pkts + hwstat->rx_jabbers + hwstat->rx_undersize_pkts + hwstat->rx_length_mismatch); nstat->rx_over_errors = hwstat->rx_resource_errors + hwstat->rx_overruns; nstat->rx_crc_errors = hwstat->rx_fcs_errors; nstat->rx_frame_errors = hwstat->rx_align_errors; nstat->rx_fifo_errors = hwstat->rx_overruns; /* XXX: What does "missed" mean? */ nstat->tx_aborted_errors = hwstat->tx_excessive_cols; nstat->tx_carrier_errors = hwstat->tx_carrier_errors; nstat->tx_fifo_errors = hwstat->tx_underruns; /* Don't know about heartbeat or window errors... */ return nstat; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen17273.50%116.67%
frederic Rodo3816.24%116.67%
Jamie Iles156.41%116.67%
Alexander Stein41.71%116.67%
Wolfgang Steinwender41.71%116.67%
Cyrille Pitchen10.43%116.67%
Total234100.00%6100.00%


static int macb_get_regs_len(struct net_device *netdev) { return MACB_GREGS_NBR * sizeof(u32); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre19100.00%1100.00%
Total19100.00%1100.00%


static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { struct macb *bp = netdev_priv(dev); unsigned int tail, head; u32 *regs_buff = p; regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1)) | MACB_GREGS_VERSION; tail = macb_tx_ring_wrap(bp, bp->queues[0].tx_tail); head = macb_tx_ring_wrap(bp, bp->queues[0].tx_head); regs_buff[0] = macb_readl(bp, NCR); regs_buff[1] = macb_or_gem_readl(bp, NCFGR); regs_buff[2] = macb_readl(bp, NSR); regs_buff[3] = macb_readl(bp, TSR); regs_buff[4] = macb_readl(bp, RBQP); regs_buff[5] = macb_readl(bp, TBQP); regs_buff[6] = macb_readl(bp, RSR); regs_buff[7] = macb_readl(bp, IMR); regs_buff[8] = tail; regs_buff[9] = head; regs_buff[10] = macb_tx_dma(&bp->queues[0], tail); regs_buff[11] = macb_tx_dma(&bp->queues[0], head); if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) regs_buff[12] = macb_or_gem_readl(bp, USRIO); if (macb_is_gem(bp)) regs_buff[13] = gem_readl(bp, DMACFG); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre25087.11%240.00%
Cyrille Pitchen227.67%120.00%
Neil Armstrong113.83%120.00%
Zach Brown41.39%120.00%
Total287100.00%5100.00%


static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct macb *bp = netdev_priv(netdev); wol->supported = 0; wol->wolopts = 0; if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) { wol->supported = WAKE_MAGIC; if (bp->wol & MACB_WOL_ENABLED) wol->wolopts |= WAKE_MAGIC; } }

Contributors

PersonTokensPropCommitsCommitProp
Sergio Prado68100.00%1100.00%
Total68100.00%1100.00%


static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct macb *bp = netdev_priv(netdev); if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) || (wol->wolopts & ~WAKE_MAGIC)) return -EOPNOTSUPP; if (wol->wolopts & WAKE_MAGIC) bp->wol |= MACB_WOL_ENABLED; else bp->wol &= ~MACB_WOL_ENABLED; device_set_wakeup_enable(&bp->pdev->dev, bp->wol & MACB_WOL_ENABLED); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sergio Prado91100.00%1100.00%
Total91100.00%1100.00%


static void macb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct macb *bp = netdev_priv(netdev); ring->rx_max_pending = MAX_RX_RING_SIZE; ring->tx_max_pending = MAX_TX_RING_SIZE; ring->rx_pending = bp->rx_ring_size; ring->tx_pending = bp->tx_ring_size; }

Contributors

PersonTokensPropCommitsCommitProp
Zach Brown54100.00%1100.00%
Total54100.00%1100.00%


static int macb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct macb *bp = netdev_priv(netdev); u32 new_rx_size, new_tx_size; unsigned int reset = 0; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; new_rx_size = clamp_t(u32, ring->rx_pending, MIN_RX_RING_SIZE, MAX_RX_RING_SIZE); new_rx_size = roundup_pow_of_two(new_rx_size); new_tx_size = clamp_t(u32, ring->tx_pending, MIN_TX_RING_SIZE, MAX_TX_RING_SIZE); new_tx_size = roundup_pow_of_two(new_tx_size); if ((new_tx_size == bp->tx_ring_size) && (new_rx_size == bp->rx_ring_size)) { /* nothing to do */ return 0; } if (netif_running(bp->dev)) { reset = 1; macb_close(bp->dev); } bp->rx_ring_size = new_rx_size; bp->tx_ring_size = new_tx_size; if (reset) macb_open(bp->dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Zach Brown171100.00%1100.00%
Total171100.00%1100.00%


static int macb_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info) { struct macb *bp = netdev_priv(netdev); if (bp->ptp_info) return bp->ptp_info->get_ts_info(netdev, info); return ethtool_op_get_ts_info(netdev, info); }

Contributors

PersonTokensPropCommitsCommitProp
Andrei Pistirica52100.00%1100.00%
Total52100.00%1100.00%

static const struct ethtool_ops macb_ethtool_ops = { .get_regs_len = macb_get_regs_len, .get_regs = macb_get_regs, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, .get_wol = macb_get_wol, .set_wol = macb_set_wol, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_ringparam = macb_get_ringparam, .set_ringparam = macb_set_ringparam, }; static const struct ethtool_ops gem_ethtool_ops = { .get_regs_len = macb_get_regs_len, .get_regs = macb_get_regs, .get_link = ethtool_op_get_link, .get_ts_info = macb_get_ts_info, .get_ethtool_stats = gem_get_ethtool_stats, .get_strings = gem_get_ethtool_strings, .get_sset_count = gem_get_sset_count, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_ringparam = macb_get_ringparam, .set_ringparam = macb_set_ringparam, };
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct phy_device *phydev = dev->phydev; struct macb *bp = netdev_priv(dev); if (!netif_running(dev)) return -EINVAL; if (!phydev) return -ENODEV; if (!bp->ptp_info) return phy_mii_ioctl(phydev, rq, cmd); switch (cmd) { case SIOCSHWTSTAMP: return bp->ptp_info->set_hwtst(dev, rq, cmd); case SIOCGHWTSTAMP: return bp->ptp_info->get_hwtst(dev, rq); default: return phy_mii_ioctl(phydev, rq, cmd); } }

Contributors

PersonTokensPropCommitsCommitProp
Andrei Pistirica6652.80%120.00%
frederic Rodo3427.20%120.00%
Håvard Skinnemoen2217.60%120.00%
Philippe Reynes21.60%120.00%
Cyrille Pitchen10.80%120.00%
Total125100.00%5100.00%


static int macb_set_features(struct net_device *netdev, netdev_features_t features) { struct macb *bp = netdev_priv(netdev); netdev_features_t changed = features ^ netdev->features; /* TX checksum offload */ if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) { u32 dmacfg; dmacfg = gem_readl(bp, DMACFG); if (features & NETIF_F_HW_CSUM) dmacfg |= GEM_BIT(TXCOEN); else dmacfg &= ~GEM_BIT(TXCOEN); gem_writel(bp, DMACFG, dmacfg); } /* RX checksum offload */ if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) { u32 netcfg; netcfg = gem_readl(bp, NCFGR); if (features & NETIF_F_RXCSUM && !(netdev->flags & IFF_PROMISC)) netcfg |= GEM_BIT(RXCOEN); else netcfg &= ~GEM_BIT(RXCOEN); gem_writel(bp, NCFGR, netcfg); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen163100.00%2100.00%
Total163100.00%2100.00%

static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, .ndo_start_xmit = macb_start_xmit, .ndo_set_rx_mode = macb_set_rx_mode, .ndo_get_stats = macb_get_stats, .ndo_do_ioctl = macb_ioctl, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = macb_change_mtu, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = macb_poll_controller, #endif .ndo_set_features = macb_set_features, .ndo_features_check = macb_features_check, }; /* Configure peripheral capabilities according to device tree * and integration options used */
static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_conf) { u32 dcfg; if (dt_conf) bp->caps = dt_conf->caps; if (hw_is_gem(bp->regs, bp->native_io)) { bp->caps |= MACB_CAPS_MACB_IS_GEM; dcfg = gem_readl(bp, DCFG1); if (GEM_BFEXT(IRQCOR, dcfg) == 0) bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; dcfg = gem_readl(bp, DCFG2); if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) bp->caps |= MACB_CAPS_FIFO_MODE; } dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); }

Contributors

PersonTokensPropCommitsCommitProp
Nicolas Ferre12193.08%360.00%
Andy Shevchenko96.92%240.00%
Total130100.00%5100.00%


static void macb_probe_queues(void __iomem *mem, bool native_io, unsigned int *queue_mask, unsigned int *num_queues) { unsigned int hw_q; *queue_mask = 0x1; *num_queues = 1; /* is it macb or gem ? * * We need to read directly from the hardware here because * we are early in the probe process and don't have the * MACB_CAPS_MACB_IS_GEM flag positioned */ if (!hw_is_gem(mem, native_io)) return; /* bit 0 is never set but queue 0 always exists */ *queue_mask = readl_relaxed(mem + GEM_DCFG6) & 0xff; *queue_mask |= 0x1; for (hw_q = 1; hw_q < MACB_MAX_QUEUES; ++hw_q) if (*queue_mask & (1 << hw_q)) (*num_queues)++; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen8889.80%120.00%
Andy Shevchenko66.12%120.00%
Nicolas Ferre33.06%240.00%
Arun Chandran11.02%120.00%
Total98100.00%5100.00%


static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, struct clk **hclk, struct clk **tx_clk, struct clk **rx_clk) { struct macb_platform_data *pdata; int err; pdata = dev_get_platdata(&pdev->dev); if (pdata) { *pclk = pdata->pclk; *hclk = pdata->hclk; } else { *pclk = devm_clk_get(&pdev->dev, "pclk"); *hclk = devm_clk_get(&pdev->dev, "hclk"); } if (IS_ERR(*pclk)) { err = PTR_ERR(*pclk); dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); return err; } if (IS_ERR(*hclk)) { err = PTR_ERR(*hclk); dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); return err; } *tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); if (IS_ERR(*tx_clk)) *tx_clk = NULL; *rx_clk = devm_clk_get(&pdev->dev, "rx_clk"); if (IS_ERR(*rx_clk)) *rx_clk = NULL; err = clk_prepare_enable(*pclk); if (err) { dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); return err; } err = clk_prepare_enable(*hclk); if (err) { dev_err(&pdev->dev, "failed to enable hclk (%u)\n", err); goto err_disable_pclk; } err = clk_prepare_enable(*tx_clk); if (err) { dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err); goto err_disable_hclk; } err = clk_prepare_enable(*rx_clk); if (err) { dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err); goto err_disable_txclk; } return 0; err_disable_txclk: clk_disable_unprepare(*tx_clk); err_disable_hclk: clk_disable_unprepare(*hclk); err_disable_pclk: clk_disable_unprepare(*pclk); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Sören Brinkmann10729.23%216.67%
Shubhrajyoti Datta6918.85%18.33%
Bartosz Folta5113.93%18.33%
Nicolas Ferre4913.39%18.33%
Håvard Skinnemoen318.47%18.33%
Cyrille Pitchen308.20%325.00%
Andrew Victor277.38%18.33%
Steffen Trumtrar10.27%18.33%
Jamie Iles10.27%18.33%
Total366100.00%12100.00%


static int macb_init(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); unsigned int hw_q, q; struct macb *bp = netdev_priv(dev); struct macb_queue *queue; int err; u32 val; bp->tx_ring_size = DEFAULT_TX_RING_SIZE; bp->rx_ring_size = DEFAULT_RX_RING_SIZE; /* set the queue register mapping once for all: queue0 has a special * register mapping but we don't want to test the queue index then * compute the corresponding register offset at run time. */ for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) { if (!(bp->queue_mask & (1 << hw_q))) continue; queue = &bp->queues[q]; queue->bp = bp; if (hw_q) { queue->ISR = GEM_ISR(hw_q - 1); queue->IER = GEM_IER(hw_q - 1); queue->IDR = GEM_IDR(hw_q - 1); queue->IMR = GEM_IMR(hw_q - 1); queue->TBQP = GEM_TBQP(hw_q - 1); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) queue->TBQPH = GEM_TBQPH(hw_q - 1); #endif } else { /* queue0 uses legacy registers */ queue->ISR = MACB_ISR; queue->IER = MACB_IER; queue->IDR = MACB_IDR; queue->IMR = MACB_IMR; queue->TBQP = MACB_TBQP; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (bp->hw_dma_cap == HW_DMA_CAP_64B) queue->TBQPH = MACB_TBQPH; #endif } /* get irq: here we use the linux queue index, not the hardware * queue index. the queue irq definitions in the device tree * must remove the optional gaps that could exist in the * hardware queue mask. */ queue->irq = platform_get_irq(pdev, q); err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt, IRQF_SHARED, dev->name, queue); if (err) { dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", queue->irq, err); return err; } INIT_WORK(&queue->tx_error_task, macb_tx_error_task); q++; } dev->netdev_ops = &macb_netdev_ops; netif_napi_add(dev, &bp->napi, macb_poll, 64); /* setup appropriated routines according to adapter type */ if (macb_is_gem(bp)) { bp->max_tx_length = GEM_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_rx = gem_rx; dev->ethtool_ops = &gem_ethtool_ops; } else { bp->max_tx_length = MACB_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_init_rings = macb_init_rings; bp->macbgem_ops.mog_rx = macb_rx; dev->ethtool_ops = &macb_ethtool_ops; } /* Set features */ dev->hw_features = NETIF_F_SG; /* Check LSO capability */ if (GEM_BFEXT(PBUF_LSO, gem_readl(bp, DCFG6))) dev->hw_features |= MACB_NETIF_LSO; /* Checksum offload is only available on gem with packet buffer */ if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE)) dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM; if (bp->caps & MACB_CAPS_SG_DISABLED) dev->hw_features &= ~NETIF_F_SG; dev->features = dev->hw_features; if (!(bp->caps & MACB_CAPS_USRIO_DISABLED)) { val = 0; if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII) val = GEM_BIT(RGMII); else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII && (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) val = MACB_BIT(RMII); else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII)) val = MACB_BIT(MII); if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN) val |= MACB_BIT(CLKEN); macb_or_gem_writel(bp, USRIO, val); } /* Set MII management clock divider */ val = macb_mdc_clk_div(bp); val |= macb_dbw(bp); if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); macb_writel(bp, NCFGR, val); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen26539.55%621.43%
Nicolas Ferre13119.55%414.29%
Håvard Skinnemoen568.36%13.57%
Rafal Ozieblo375.52%27.14%
Boris Brezillon345.07%13.57%
Harini Katakam274.03%13.57%
Punnaiah Choudary Kalluri213.13%27.14%
Xander Huff142.09%13.57%
Patrice Vilchez142.09%13.57%
Andrew Victor142.09%13.57%
Neil Armstrong131.94%13.57%
Zach Brown121.79%13.57%
Stephen Hemminger91.34%13.57%
Jamie Iles71.04%27.14%
Jean-Christophe Plagniol-Villard71.04%13.57%
Sören Brinkmann60.90%13.57%
Alexander Beregalov30.45%13.57%
Total670100.00%28100.00%

#if defined(CONFIG_OF) /* 1518 rounded up */ #define AT91ETHER_MAX_RBUFF_SZ 0x600 /* max number of receive buffers */ #define AT91ETHER_MAX_RX_DESCR 9 /* Initialize and start the Receiver and Transmit subsystems */
static int at91ether_start(struct net_device *dev) { struct macb *lp = netdev_priv(dev); struct macb_dma_desc *desc; dma_addr_t addr; u32 ctl; int i; lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev, (AT91ETHER_MAX_RX_DESCR * macb_dma_desc_get_size(lp)), &lp->rx_ring_dma, GFP_KERNEL); if (!lp->rx_ring) return -ENOMEM; lp->rx_buffers = dma_alloc_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * AT91ETHER_MAX_RBUFF_SZ, &lp->rx_buffers_dma, GFP_KERNEL); if (!lp->rx_buffers) { dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * macb_dma_desc_get_size(lp), lp->rx_ring, lp->rx_ring_dma); lp->rx_ring = NULL; return -ENOMEM; } addr = lp->rx_buffers_dma; for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) { desc = macb_rx_desc(lp, i); macb_set_addr(lp, desc, addr); desc->ctrl = 0; addr += AT91ETHER_MAX_RBUFF_SZ; } /* Set the Wrap bit on the last descriptor */ desc->addr |= MACB_BIT(RX_WRAP); /* Reset buffer index */ lp->rx_tail = 0; /* Program address of descriptor list in Rx Buffer Queue register */ macb_writel(lp, RBQP, lp->rx_ring_dma); /* Enable Receive and Transmit */ ctl = macb_readl(lp, NCR); macb_writel(lp, NCR, ctl | MACB_BIT(RE) | MACB_BIT(TE)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen23090.20%150.00%
Rafal Ozieblo259.80%150.00%
Total255100.00%2100.00%

/* Open the ethernet interface */
static int at91ether_open(struct net_device *dev) { struct macb *lp = netdev_priv(dev); u32 ctl; int ret; /* Clear internal statistics */ ctl = macb_readl(lp, NCR); macb_writel(lp, NCR, ctl | MACB_BIT(CLRSTAT)); macb_set_hwaddr(lp); ret = at91ether_start(dev); if (ret) return ret; /* Enable MAC interrupts */ macb_writel(lp, IER, MACB_BIT(RCOMP) | MACB_BIT(RXUBR) | MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE) | MACB_BIT(TCOMP) | MACB_BIT(ISR_ROVR) | MACB_BIT(HRESP)); /* schedule a link state check */ phy_start(dev->phydev); netif_start_queue(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen12798.45%150.00%
Philippe Reynes21.55%150.00%
Total129100.00%2100.00%

/* Close the interface */
static int at91ether_close(struct net_device *dev) { struct macb *lp = netdev_priv(dev); u32 ctl; /* Disable Receiver and Transmitter */ ctl = macb_readl(lp, NCR); macb_writel(lp, NCR, ctl & ~(MACB_BIT(TE) | MACB_BIT(RE))); /* Disable MAC interrupts */ macb_writel(lp, IDR, MACB_BIT(RCOMP) | MACB_BIT(RXUBR) | MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE) | MACB_BIT(TCOMP) | MACB_BIT(ISR_ROVR) | MACB_BIT(HRESP)); netif_stop_queue(dev); dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * macb_dma_desc_get_size(lp), lp->rx_ring, lp->rx_ring_dma); lp->rx_ring = NULL; dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * AT91ETHER_MAX_RBUFF_SZ, lp->rx_buffers, lp->rx_buffers_dma); lp->rx_buffers = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen16498.80%150.00%
Rafal Ozieblo21.20%150.00%
Total166100.00%2100.00%

/* Transmit packet */
static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct macb *lp = netdev_priv(dev); if (macb_readl(lp, TSR) & MACB_BIT(RM9200_BNQ)) { netif_stop_queue(dev); /* Store packet information (to free when Tx completed) */ lp->skb = skb; lp->skb_length = skb->len; lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); if (dma_mapping_error(NULL, lp->skb_physaddr)) { dev_kfree_skb_any(skb); dev->stats.tx_dropped++; netdev_err(dev, "%s: DMA mapping error\n", __func__); return NETDEV_TX_OK; } /* Set address of the data in the Transmit Address register */ macb_writel(lp, TAR, lp->skb_physaddr); /* Set length of the packet in the Transmit Control register */ macb_writel(lp, TCR, skb->len); } else { netdev_err(dev, "%s called, but device is busy!\n", __func__); return NETDEV_TX_BUSY; } return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen12376.88%150.00%
Alexey Khoroshilov3723.12%150.00%
Total160100.00%2100.00%

/* Extract received frame from buffer descriptors and sent to upper layers. * (Called from interrupt context) */
static void at91ether_rx(struct net_device *dev) { struct macb *lp = netdev_priv(dev); struct macb_dma_desc *desc; unsigned char *p_recv; struct sk_buff *skb; unsigned int pktlen; desc = macb_rx_desc(lp, lp->rx_tail); while (desc->addr & MACB_BIT(RX_USED)) { p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ; pktlen = MACB_BF(RX_FRMLEN, desc->ctrl); skb = netdev_alloc_skb(dev, pktlen + 2); if (skb) { skb_reserve(skb, 2); memcpy(skb_put(skb, pktlen), p_recv, pktlen); skb->protocol = eth_type_trans(skb, dev); lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; netif_rx(skb); } else { lp->stats.rx_dropped++; } if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH)) lp->stats.multicast++; /* reset ownership bit */ desc->addr &= ~MACB_BIT(RX_USED); /* wrap after last buffer */ if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1) lp->rx_tail = 0; else lp->rx_tail++; desc = macb_rx_desc(lp, lp->rx_tail); } }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen19986.90%150.00%
Rafal Ozieblo3013.10%150.00%
Total229100.00%2100.00%

/* MAC interrupt handler */
static irqreturn_t at91ether_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct macb *lp = netdev_priv(dev); u32 intstatus, ctl; /* MAC Interrupt Status register indicates what interrupts are pending. * It is automatically cleared once read. */ intstatus = macb_readl(lp, ISR); /* Receive complete */ if (intstatus & MACB_BIT(RCOMP)) at91ether_rx(dev); /* Transmit complete */ if (intstatus & MACB_BIT(TCOMP)) { /* The TCOM bit is set even if the transmission failed */ if (intstatus & (MACB_BIT(ISR_TUND) | MACB_BIT(ISR_RLE))) lp->stats.tx_errors++; if (lp->skb) { dev_kfree_skb_irq(lp->skb); lp->skb = NULL; dma_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, DMA_TO_DEVICE); lp->stats.tx_packets++; lp->stats.tx_bytes += lp->skb_length; } netif_wake_queue(dev); } /* Work-around for EMAC Errata section 41.3.1 */ if (intstatus & MACB_BIT(RXUBR)) { ctl = macb_readl(lp, NCR); macb_writel(lp, NCR, ctl & ~MACB_BIT(RE)); wmb(); macb_writel(lp, NCR, ctl | MACB_BIT(RE)); } if (intstatus & MACB_BIT(ISR_ROVR)) netdev_err(dev, "ROVR error\n"); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen22398.67%150.00%
Zumeng Chen31.33%150.00%
Total226100.00%2100.00%

#ifdef CONFIG_NET_POLL_CONTROLLER
static void at91ether_poll_controller(struct net_device *dev) { unsigned long flags; local_irq_save(flags); at91ether_interrupt(dev->irq, dev); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen34100.00%1100.00%
Total34100.00%1100.00%

#endif static const struct net_device_ops at91ether_netdev_ops = { .ndo_open = at91ether_open, .ndo_stop = at91ether_close, .ndo_start_xmit = at91ether_start_xmit, .ndo_get_stats = macb_get_stats, .ndo_set_rx_mode = macb_set_rx_mode, .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = macb_ioctl, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = at91ether_poll_controller, #endif };
static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk, struct clk **hclk, struct clk **tx_clk, struct clk **rx_clk) { int err; *hclk = NULL; *tx_clk = NULL; *rx_clk = NULL; *pclk = devm_clk_get(&pdev->dev, "ether_clk"); if (IS_ERR(*pclk)) return PTR_ERR(*pclk); err = clk_prepare_enable(*pclk); if (err) { dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen6759.29%133.33%
Nicolas Ferre3530.97%133.33%
Shubhrajyoti Datta119.73%133.33%
Total113100.00%3100.00%


static int at91ether_init(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(dev); int err; u32 reg; dev->netdev_ops = &at91ether_netdev_ops; dev->ethtool_ops = &macb_ethtool_ops; err = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, 0, dev->name, dev); if (err) return err; macb_writel(bp, NCR, 0); reg = MACB_BF(CLK, MACB_CLK_DIV32) | MACB_BIT(BIG); if (bp->phy_interface == PHY_INTERFACE_MODE_RMII) reg |= MACB_BIT(RM9200_RMII); macb_writel(bp, NCFGR, reg); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen8765.91%150.00%
Nicolas Ferre4534.09%150.00%
Total132100.00%2100.00%

static const struct macb_config at91sam9260_config = { .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config pc302gem_config = { .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config sama5d2_config = { .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config sama5d3_config = { .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config sama5d4_config = { .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, .dma_burst_length = 4, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config emac_config = { .clk_init = at91ether_clk_init, .init = at91ether_init, }; static const struct macb_config np4_config = { .caps = MACB_CAPS_USRIO_DISABLED, .clk_init = macb_clk_init, .init = macb_init, }; static const struct macb_config zynqmp_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, .jumbo_max_len = 10240, }; static const struct macb_config zynq_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, }; static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, { .compatible = "cdns,macb" }, { .compatible = "cdns,np4-macb", .data = &np4_config }, { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, { .compatible = "cdns,gem", .data = &pc302gem_config }, { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config }, { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, { .compatible = "cdns,emac", .data = &emac_config }, { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, { .compatible = "cdns,zynq-gem", .data = &zynq_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, macb_dt_ids); #endif /* CONFIG_OF */ static const struct macb_config default_gem_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, .jumbo_max_len = 10240, };
static int macb_probe(struct platform_device *pdev) { const struct macb_config *macb_config = &default_gem_config; int (*clk_init)(struct platform_device *, struct clk **, struct clk **, struct clk **, struct clk **) = macb_config->clk_init; int (*init)(struct platform_device *) = macb_config->init; struct device_node *np = pdev->dev.of_node; struct device_node *phy_node; struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL; unsigned int queue_mask, num_queues; struct macb_platform_data *pdata; bool native_io; struct phy_device *phydev; struct net_device *dev; struct resource *regs; void __iomem *mem; const char *mac; struct macb *bp; int err; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(mem)) return PTR_ERR(mem); if (np) { const struct of_device_id *match; match = of_match_node(macb_dt_ids, np); if (match && match->data) { macb_config = match->data; clk_init = macb_config->clk_init; init = macb_config->init; } } err = clk_init(pdev, &pclk, &hclk, &tx_clk, &rx_clk); if (err) return err; native_io = hw_is_native_io(mem); macb_probe_queues(mem, native_io, &queue_mask, &num_queues); dev = alloc_etherdev_mq(sizeof(*bp), num_queues); if (!dev) { err = -ENOMEM; goto err_disable_clocks; } dev->base_addr = regs->start; SET_NETDEV_DEV(dev, &pdev->dev); bp = netdev_priv(dev); bp->pdev = pdev; bp->dev = dev; bp->regs = mem; bp->native_io = native_io; if (native_io) { bp->macb_reg_readl = hw_readl_native; bp->macb_reg_writel = hw_writel_native; } else { bp->macb_reg_readl = hw_readl; bp->macb_reg_writel = hw_writel; } bp->num_queues = num_queues; bp->queue_mask = queue_mask; if (macb_config) bp->dma_burst_length = macb_config->dma_burst_length; bp->pclk = pclk; bp->hclk = hclk; bp->tx_clk = tx_clk; bp->rx_clk = rx_clk; if (macb_config) bp->jumbo_max_len = macb_config->jumbo_max_len; bp->wol = 0; if (of_get_property(np, "magic-packet", NULL)) bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); bp->hw_dma_cap = HW_DMA_CAP_64B; } else bp->hw_dma_cap = HW_DMA_CAP_32B; #endif spin_lock_init(&bp->lock); /* setup capabilities */ macb_configure_caps(bp, macb_config); platform_set_drvdata(pdev, dev); dev->irq = platform_get_irq(pdev, 0); if (dev->irq < 0) { err = dev->irq; goto err_out_free_netdev; } /* MTU range: 68 - 1500 or 10240 */ dev->min_mtu = GEM_MTU_MIN_SIZE; if (bp->caps & MACB_CAPS_JUMBO) dev->max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; else dev->max_mtu = ETH_DATA_LEN; mac = of_get_mac_address(np); if (mac) ether_addr_copy(bp->dev->dev_addr, mac); else macb_get_hwaddr(bp); /* Power up the PHY if there is a GPIO reset */ phy_node = of_get_next_available_child(np, NULL); if (phy_node) { int gpio = of_get_named_gpio(phy_node, "reset-gpios", 0); if (gpio_is_valid(gpio)) { bp->reset_gpio = gpio_to_desc(gpio); gpiod_direction_output(bp->reset_gpio, 1); } } of_node_put(phy_node); err = of_get_phy_mode(np); if (err < 0) { pdata = dev_get_platdata(&pdev->dev); if (pdata && pdata->is_rmii) bp->phy_interface = PHY_INTERFACE_MODE_RMII; else bp->phy_interface = PHY_INTERFACE_MODE_MII; } else { bp->phy_interface = err; } /* IP specific init */ err = init(pdev); if (err) goto err_out_free_netdev; err = macb_mii_init(bp); if (err) goto err_out_free_netdev; phydev = dev->phydev; netif_carrier_off(dev); err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); goto err_out_unregister_mdio; } phy_attached_info(phydev); netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), dev->base_addr, dev->irq, dev->dev_addr); return 0; err_out_unregister_mdio: phy_disconnect(dev->phydev); mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); /* Shutdown the PHY if there is a GPIO reset */ if (bp->reset_gpio) gpiod_set_value(bp->reset_gpio, 0); err_out_free_netdev: free_netdev(dev); err_disable_clocks: clk_disable_unprepare(tx_clk); clk_disable_unprepare(hclk); clk_disable_unprepare(pclk); clk_disable_unprepare(rx_clk); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen29531.02%12.94%
Nicolas Ferre18719.66%514.71%
Andy Shevchenko788.20%12.94%
Gregory CLEMENT616.41%25.88%
Florian Fainelli586.10%12.94%
Håvard Skinnemoen474.94%12.94%
Harini Katakam424.42%25.88%
Sergio Prado373.89%25.88%
Jarod Wilson373.89%12.94%
Shubhrajyoti Datta242.52%12.94%
Rafal Ozieblo171.79%12.94%
Bartosz Folta151.58%12.94%
Jamie Iles111.16%25.88%
Bo Shen80.84%12.94%
frederic Rodo80.84%12.94%
Sören Brinkmann60.63%25.88%
Sudip Mukherjee40.42%12.94%
Philippe Reynes40.42%12.94%
David S. Miller40.42%12.94%
Sergei Shtylyov20.21%12.94%
Charles Keepax20.21%12.94%
Joe Perches10.11%12.94%
Steffen Trumtrar10.11%12.94%
Moritz Fischer10.11%12.94%
Wei Yongjun10.11%12.94%
Total951100.00%34100.00%


static int macb_remove(struct platform_device *pdev) { struct net_device *dev; struct macb *bp; dev = platform_get_drvdata(pdev); if (dev) { bp = netdev_priv(dev); if (dev->phydev) phy_disconnect(dev->phydev); mdiobus_unregister(bp->mii_bus); dev->phydev = NULL; mdiobus_free(bp->mii_bus); /* Shutdown the PHY if there is a GPIO reset */ if (bp->reset_gpio) gpiod_set_value(bp->reset_gpio, 0); unregister_netdev(dev); clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); clk_disable_unprepare(bp->rx_clk); free_netdev(dev); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen6146.56%17.14%
Gregory CLEMENT96.87%17.14%
Atsushi Nemoto96.87%17.14%
Lennert Buytenhek75.34%17.14%
Sören Brinkmann75.34%17.14%
Shubhrajyoti Datta75.34%17.14%
frederic Rodo64.58%17.14%
Charles Keepax64.58%17.14%
Nathan Sullivan64.58%17.14%
Cyrille Pitchen53.82%17.14%
Philippe Reynes43.05%17.14%
Steffen Trumtrar21.53%17.14%
Sergei Shtylyov10.76%17.14%
Andrew Victor10.76%17.14%
Total131100.00%14100.00%


static int __maybe_unused macb_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); netif_carrier_off(netdev); netif_device_detach(netdev); if (bp->wol & MACB_WOL_ENABLED) { macb_writel(bp, IER, MACB_BIT(WOL)); macb_writel(bp, WOL, MACB_BIT(MAG)); enable_irq_wake(bp->queues[0].irq); } else { clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); clk_disable_unprepare(bp->rx_clk); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sergio Prado4937.12%112.50%
Håvard Skinnemoen4937.12%112.50%
Sören Brinkmann1914.39%225.00%
Shubhrajyoti Datta75.30%112.50%
Nicolas Ferre53.79%112.50%
Steffen Trumtrar21.52%112.50%
Michal Simek10.76%112.50%
Total132100.00%8100.00%


static int __maybe_unused macb_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); struct macb *bp = netdev_priv(netdev); if (bp->wol & MACB_WOL_ENABLED) { macb_writel(bp, IDR, MACB_BIT(WOL)); macb_writel(bp, WOL, 0); disable_irq_wake(bp->queues[0].irq); } else { clk_prepare_enable(bp->pclk); clk_prepare_enable(bp->hclk); clk_prepare_enable(bp->tx_clk); clk_prepare_enable(bp->rx_clk); } netif_device_attach(netdev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Håvard Skinnemoen4939.52%114.29%
Sergio Prado4637.10%114.29%
Sören Brinkmann1915.32%228.57%
Shubhrajyoti Datta75.65%114.29%
Steffen Trumtrar21.61%114.29%
Michal Simek10.81%114.29%
Total124100.00%7100.00%

static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); static struct platform_driver macb_driver = { .probe = macb_probe, .remove = macb_remove, .driver = { .name = "macb", .of_match_table = of_match_ptr(macb_dt_ids), .pm = &macb_pm_ops, }, }; module_platform_driver(macb_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_ALIAS("platform:macb");

Overall Contributors

PersonTokensPropCommitsCommitProp
Cyrille Pitchen425825.39%137.14%
Håvard Skinnemoen258815.43%21.10%
Nicolas Ferre257015.32%189.89%
Rafal Ozieblo10436.22%21.10%
Jamie Iles7184.28%94.95%
frederic Rodo5233.12%10.55%
Sören Brinkmann4622.75%116.04%
Patrice Vilchez4342.59%21.10%
Zach Brown4042.41%21.10%
Harini Katakam3642.17%42.20%
Andy Shevchenko3412.03%42.20%
Havard Skinnemoen3151.88%42.20%
Sergio Prado3091.84%21.10%
Xander Huff2861.71%21.10%
Joachim Eastwood2721.62%63.30%
Boris Brezillon1791.07%31.65%
Nathan Sullivan1671.00%52.75%
Andrei Pistirica1490.89%10.55%
Bartosz Folta1340.80%10.55%
Shubhrajyoti Datta1250.75%10.55%
Gregory CLEMENT1070.64%31.65%
Helmut Buchsbaum770.46%10.55%
Florian Fainelli660.39%21.10%
Neil Armstrong600.36%21.10%
Punnaiah Choudary Kalluri580.35%31.65%
Alexander Beregalov530.32%10.55%
Stephen Hemminger510.30%21.10%
Thomas Petazzoni490.29%10.55%
Lennert Buytenhek460.27%21.10%
Andrew Victor420.25%10.55%
Philippe Reynes420.25%21.10%
Jarod Wilson380.23%10.55%
Alexey Khoroshilov370.22%10.55%
Steffen Trumtrar350.21%31.65%
Moritz Fischer300.18%42.20%
Richard Röjfors240.14%10.55%
Jiri Pirko230.14%52.75%
Alexander Stein230.14%10.55%
Arun Chandran220.13%21.10%
Jean-Christophe Plagniol-Villard210.13%10.55%
Atsushi Nemoto160.10%31.65%
Sven Schnelle160.10%10.55%
David S. Miller150.09%31.65%
Jaeden Amero130.08%10.55%
Vitalii Demianets120.07%10.55%
Sergei Shtylyov110.07%21.10%
Dongdong Deng90.05%10.55%
Joshua Hoke90.05%10.55%
Bo Shen80.05%10.55%
Charles Keepax80.05%10.55%
Arnaldo Carvalho de Melo80.05%31.65%
Peter Korsgaard80.05%10.55%
Jingoo Han80.05%10.55%
Kay Sievers70.04%10.55%
Andy Fleming70.04%10.55%
Erik Waling60.04%10.55%
Zumeng Chen60.04%10.55%
Nicolae Rosia60.04%10.55%
Eric Dumazet50.03%21.10%
Richard Cochran50.03%10.55%
Pradeep A. Dalvi50.03%10.55%
Sudip Mukherjee40.02%10.55%
Wolfgang Steinwender40.02%10.55%
Alexey Dobriyan40.02%21.10%
Wei Yongjun40.02%21.10%
Tord Andersson40.02%10.55%
Olof Johansson30.02%10.55%
Dan Carpenter30.02%10.55%
Ben Hutchings20.01%10.55%
Michal Simek20.01%10.55%
Danny Kukawka10.01%10.55%
Lad Prabhakar10.01%10.55%
Uwe Kleine-König10.01%10.55%
Eric W. Biedermann10.01%10.55%
Anton Vorontsov10.01%10.55%
Ben Shelton10.01%10.55%
Patrick McHardy10.01%10.55%
Andrew Lunn10.01%10.55%
Joe Perches10.01%10.55%
Jean Delvare10.01%10.55%
Total16773100.00%182100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.