satip-axe/kernel/drivers/net/stmmac/stmmac_main.c

2305 lines
62 KiB
C
Raw Normal View History

/*******************************************************************************
This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
ST Ethernet IPs are built around a Synopsys IP Core.
Copyright(C) 2007-2011 STMicroelectronics Ltd
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Documentation available at:
http://www.stlinux.com
Support available at:
https://bugzilla.stlinux.com/
*******************************************************************************/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
#ifdef CONFIG_STMMAC_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#endif
#include "stmmac.h"
#undef STMMAC_DEBUG
/*#define STMMAC_DEBUG*/
#ifdef STMMAC_DEBUG
#define DBG(nlevel, klevel, fmt, args...) \
((void)(netif_msg_##nlevel(priv) && \
printk(KERN_##klevel fmt, ## args)))
#else
#define DBG(nlevel, klevel, fmt, args...) do { } while (0)
#endif
#undef STMMAC_RX_DEBUG
/*#define STMMAC_RX_DEBUG*/
#ifdef STMMAC_RX_DEBUG
#define RX_DBG(fmt, args...) printk(fmt, ## args)
#else
#define RX_DBG(fmt, args...) do { } while (0)
#endif
#undef STMMAC_XMIT_DEBUG
/*#define STMMAC_XMIT_DEBUG*/
#ifdef STMMAC_TX_DEBUG
#define TX_DBG(fmt, args...) printk(fmt, ## args)
#else
#define TX_DBG(fmt, args...) do { } while (0)
#endif
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
#define JUMBO_LEN 9000
/* Module parameters */
#define TX_TIMEO 5000 /* default 5 seconds */
static int watchdog = TX_TIMEO;
module_param(watchdog, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds");
static int debug = -1; /* -1: default, 0: no output, 16: all */
module_param(debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)");
int phyaddr = -1;
module_param(phyaddr, int, S_IRUGO);
MODULE_PARM_DESC(phyaddr, "Physical device address");
#define DMA_TX_SIZE 512
static int dma_txsize = DMA_TX_SIZE;
module_param(dma_txsize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list");
#define DMA_RX_SIZE 512
static int dma_rxsize = DMA_RX_SIZE;
module_param(dma_rxsize, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list");
static int flow_ctrl = FLOW_OFF;
module_param(flow_ctrl, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(flow_ctrl, "Flow control ability [on/off]");
static int pause = PAUSE_TIME;
module_param(pause, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(pause, "Flow Control Pause Time");
#define TC_DEFAULT 64
static int tc = TC_DEFAULT;
module_param(tc, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tc, "DMA threshold control value");
/* Pay attention to tune this parameter; take care of both
* hardware capability and network stabitily/performance impact.
* Many tests showed that ~4ms latency seems to be good enough. */
#ifdef CONFIG_STMMAC_TIMER
#define DEFAULT_PERIODIC_RATE 256
static int tmrate = DEFAULT_PERIODIC_RATE;
module_param(tmrate, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tmrate, "External timer freq. (default: 256Hz)");
#endif
#define DMA_BUFFER_SIZE BUF_SIZE_2KiB
static int buf_sz = DMA_BUFFER_SIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size");
static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
static int eee_timer = 1000;
module_param(eee_timer, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
#define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
/* Enable this option the driver could use the WoL+ feature
* available in some new PHY drivers. This allows to completely power-off
* the mac when suspend and the WoL will be done by the PHY device directly. */
static int wol_plus_en;
module_param(wol_plus_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(wol_plus_en, "Driver can use the WoL+ feature");
static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev);
#ifdef CONFIG_STMMAC_DEBUG_FS
static int stmmac_init_fs(struct net_device *dev);
static void stmmac_exit_fs(void);
#endif
/**
* stmmac_verify_args - verify the driver parameters.
* Description: it verifies if some wrong parameter is passed to the driver.
* Note that wrong parameters are replaced with the default values.
*/
static void stmmac_verify_args(void)
{
if (unlikely(watchdog < 0))
watchdog = TX_TIMEO;
if (unlikely(dma_rxsize < 0))
dma_rxsize = DMA_RX_SIZE;
if (unlikely(dma_txsize < 0))
dma_txsize = DMA_TX_SIZE;
if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
buf_sz = DMA_BUFFER_SIZE;
if (unlikely(flow_ctrl > 1))
flow_ctrl = FLOW_AUTO;
else if (likely(flow_ctrl < 0))
flow_ctrl = FLOW_OFF;
if (unlikely((pause < 0) || (pause > 0xffff)))
pause = PAUSE_TIME;
}
#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
static void print_pkt(unsigned char *buf, int len)
{
int j;
printk("len = %d byte, buf addr: 0x%p", len, buf);
for (j = 0; j < len; j++) {
if ((j % 16) == 0)
printk("\n %03x:", j);
printk(" %02x", buf[j]);
}
}
#endif
/* minimum number of free TX descriptors required to wake up TX process */
#define STMMAC_TX_THRESH(x) (x->dma_tx_size/4)
static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
{
return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
}
/* On some ST platforms, some HW system configuraton registers have to be
* set according to the link speed negotiated.
*/
static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
{
struct phy_device *phydev = priv->phydev;
if (likely(priv->plat->fix_mac_speed))
priv->plat->fix_mac_speed(priv->plat->bsp_priv,
phydev->speed);
}
static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
{
/* Check and enter in LPI mode */
if ((priv->dirty_tx == priv->cur_tx) &&
(priv->tx_path_in_lpi_mode == false))
priv->hw->mac->set_eee_mode(priv->ioaddr, priv->lpi_ctl_status);
}
void stmmac_disable_eee_mode(struct stmmac_priv *priv)
{
/* Exit and disable EEE in case of we are are in LPI state. */
priv->hw->mac->reset_eee_mode(priv->ioaddr, priv->lpi_ctl_status);
del_timer_sync(&priv->eee_ctrl_timer);
priv->tx_path_in_lpi_mode = false;
}
/**
* stmmac_eee_ctrl_timer
* @arg : data hook
* Description:
* If there is no data transfer and if we are not in LPI state,
* then MAC Transmitter can be moved to LPI state.
*/
static void stmmac_eee_ctrl_timer(unsigned long arg)
{
struct stmmac_priv *priv = (struct stmmac_priv *)arg;
stmmac_enable_eee_mode(priv);
mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
}
/**
* stmmac_eee_init
* @priv: private device pointer
* Description:
* If the EEE support has been enabled while configuring the driver,
* if the GMAC actually supports the EEE (from the HW cap reg) and the
* phy can also manage EEE, so enable the LPI state and start the timer
* to verify if the tx path can enter in LPI state.
*/
bool stmmac_eee_init(struct stmmac_priv *priv)
{
bool ret = false;
/* MAC core supports the EEE feature. */
if (priv->dma_cap.eee) {
/* Check if the PHY supports EEE*/
if (phy_check_eee(priv->phydev))
goto out;
init_timer(&priv->eee_ctrl_timer);
priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
priv->eee_ctrl_timer.data = (unsigned long)priv;
priv->eee_ctrl_timer.expires = STMMAC_LPI_TIMER(eee_timer);
add_timer(&priv->eee_ctrl_timer);
priv->hw->mac->set_eee_timer(priv->ioaddr, 0x3e8, 0);
pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
ret = true;
}
out:
return ret;
}
static void stmmac_eee_adjust(struct stmmac_priv *priv)
{
/* When the EEE has been already initialised we have to
* modify the PLS bit in the LPI ctrl & status reg according
* to the PHY link status. For this reason. */
if (priv->eee_enabled)
priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link,
priv->lpi_ctl_status);
}
/**
* stmmac_adjust_link
* @dev: net device structure
* Description: it adjusts the link parameters.
*/
static void stmmac_adjust_link(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phydev = priv->phydev;
unsigned long flags;
int new_state = 0;
unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
if (phydev == NULL)
return;
DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n",
phydev->addr, phydev->link);
spin_lock_irqsave(&priv->lock, flags);
if (phydev->link) {
u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
if (phydev->duplex != priv->oldduplex) {
new_state = 1;
if (!(phydev->duplex))
ctrl &= ~priv->hw->link.duplex;
else
ctrl |= priv->hw->link.duplex;
priv->oldduplex = phydev->duplex;
}
/* Flow Control operation */
if (phydev->pause)
priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex,
fc, pause_time);
if (phydev->speed != priv->speed) {
new_state = 1;
switch (phydev->speed) {
case 1000:
if (likely(priv->plat->has_gmac))
ctrl &= ~priv->hw->link.port;
stmmac_hw_fix_mac_speed(priv);
break;
case 100:
case 10:
if (priv->plat->has_gmac) {
ctrl |= priv->hw->link.port;
if (phydev->speed == SPEED_100) {
ctrl |= priv->hw->link.speed;
} else {
ctrl &= ~(priv->hw->link.speed);
}
} else {
ctrl &= ~priv->hw->link.port;
}
stmmac_hw_fix_mac_speed(priv);
break;
default:
if (netif_msg_link(priv))
pr_warning("%s: Speed (%d) is not 10"
" or 100!\n", dev->name, phydev->speed);
break;
}
priv->speed = phydev->speed;
}
writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
if (!priv->oldlink) {
new_state = 1;
priv->oldlink = 1;
}
} else if (priv->oldlink) {
new_state = 1;
priv->oldlink = 0;
priv->speed = 0;
priv->oldduplex = -1;
}
if (new_state && netif_msg_link(priv))
phy_print_status(phydev);
stmmac_eee_adjust(priv);
spin_unlock_irqrestore(&priv->lock, flags);
DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
}
/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
* Description: it initializes the driver's PHY state, and attaches the PHY
* to the mac driver.
* Return value:
* 0 on success
*/
static int stmmac_init_phy(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phydev;
char phy_id_fmt[MII_BUS_ID_SIZE + 3];
char bus_id[MII_BUS_ID_SIZE];
int interface = priv->plat->interface;
priv->oldlink = 0;
priv->speed = 0;
priv->oldduplex = -1;
snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
priv->plat->phy_addr);
/* (mii bus id:phy device id) */
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
0, interface);
if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
}
/* Stop Advertising 1000BASE Capability if interface is not GMII */
if ((interface == PHY_INTERFACE_MODE_MII) ||
(interface == PHY_INTERFACE_MODE_RMII))
phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full);
/*
* Broken HW is sometimes missing the pull-up resistor on the
* MDIO line, which results in reads to non-existent devices returning
* 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
* device as well.
* Note: phydev->phy_id is the result of reading the UID PHY registers.
*/
if (phydev->phy_id == 0) {
phy_disconnect(phydev);
return -ENODEV;
}
pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)"
" Link = %d\n", dev->name, phydev->phy_id, phydev->link);
priv->phydev = phydev;
if ((priv->phydev->drv->wol_supported) && (wol_plus_en)) {
pr_info("stmmac: attached PHY supports WoL Plus\n");
priv->phy_wol_plus = priv->phydev->drv->wol_supported;
}
return 0;
}
/**
* display_ring
* @p: pointer to the ring.
* @size: size of the ring.
* Description: display all the descriptors within the ring.
*/
static void display_ring(struct dma_desc *p, int size)
{
struct tmp_s {
u64 a;
unsigned int b;
unsigned int c;
};
int i;
for (i = 0; i < size; i++) {
struct tmp_s *x = (struct tmp_s *)(p + i);
pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
i, (unsigned int)virt_to_phys(&p[i]),
(unsigned int)(x->a), (unsigned int)((x->a) >> 32),
x->b, x->c);
pr_info("\n");
}
}
static int stmmac_set_bfsize(int mtu, int bufsize)
{
int ret = bufsize;
if (mtu >= BUF_SIZE_4KiB)
ret = BUF_SIZE_8KiB;
else if (mtu >= BUF_SIZE_2KiB)
ret = BUF_SIZE_4KiB;
else if (mtu >= DMA_BUFFER_SIZE)
ret = BUF_SIZE_2KiB;
else
ret = DMA_BUFFER_SIZE;
return ret;
}
/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
* Description: this function initializes the DMA RX/TX descriptors
* and allocates the socket buffers. It suppors the chained and ring
* modes.
*/
static void init_dma_desc_rings(struct net_device *dev)
{
int i;
struct stmmac_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
unsigned int txsize = priv->dma_tx_size;
unsigned int rxsize = priv->dma_rx_size;
unsigned int bfsize;
int dis_ic = 0;
int des3_as_data_buf = 0;
/* Set the max buffer size according to the DESC mode
* and the MTU. Note that RING mode allows 16KiB bsize. */
bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
if (bfsize == BUF_SIZE_16KiB)
des3_as_data_buf = 1;
else
bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
#ifdef CONFIG_STMMAC_TIMER
/* Disable interrupts on completion for the reception if timer is on */
if (likely(priv->tm->enable))
dis_ic = 1;
#endif
DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
txsize, rxsize, bfsize);
priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
priv->rx_skbuff =
kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
priv->dma_rx =
(struct dma_desc *)dma_alloc_coherent(priv->device,
rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
GFP_KERNEL);
priv->dma_tx =
(struct dma_desc *)dma_alloc_coherent(priv->device,
txsize *
sizeof(struct dma_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
return;
}
DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
"Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
dev->name, priv->dma_rx, priv->dma_tx,
(unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
/* RX INITIALIZATION */
DBG(probe, INFO, "stmmac: SKB addresses:\n"
"skb\t\tskb data\tdma data\n");
for (i = 0; i < rxsize; i++) {
struct dma_desc *p = priv->dma_rx + i;
skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
GFP_KERNEL);
if (unlikely(skb == NULL)) {
pr_err("%s: Rx init fails; skb is NULL\n", __func__);
break;
}
skb_reserve(skb, NET_IP_ALIGN);
priv->rx_skbuff[i] = skb;
priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
bfsize, DMA_FROM_DEVICE);
p->des2 = priv->rx_skbuff_dma[i];
priv->hw->ring->init_desc3(des3_as_data_buf, p);
DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
}
priv->cur_rx = 0;
priv->dirty_rx = (unsigned int)(i - rxsize);
priv->dma_buf_sz = bfsize;
buf_sz = bfsize;
/* TX INITIALIZATION */
for (i = 0; i < txsize; i++) {
priv->tx_skbuff[i] = NULL;
priv->dma_tx[i].des2 = 0;
}
/* In case of Chained mode this sets the des3 to the next
* element in the chain */
priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
priv->dirty_tx = 0;
priv->cur_tx = 0;
/* Clear the Rx/Tx descriptors */
priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
if (netif_msg_hw(priv)) {
pr_info("RX descriptor ring:\n");
display_ring(priv->dma_rx, rxsize);
pr_info("TX descriptor ring:\n");
display_ring(priv->dma_tx, txsize);
}
}
static void dma_free_rx_skbufs(struct stmmac_priv *priv)
{
int i;
for (i = 0; i < priv->dma_rx_size; i++) {
if (priv->rx_skbuff[i]) {
dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
priv->dma_buf_sz, DMA_FROM_DEVICE);
dev_kfree_skb_any(priv->rx_skbuff[i]);
}
priv->rx_skbuff[i] = NULL;
}
}
static void dma_free_tx_skbufs(struct stmmac_priv *priv)
{
int i;
for (i = 0; i < priv->dma_tx_size; i++) {
if (priv->tx_skbuff[i] != NULL) {
struct dma_desc *p = priv->dma_tx + i;
if (p->des2)
dma_unmap_single(priv->device, p->des2,
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
}
}
}
static void free_dma_desc_resources(struct stmmac_priv *priv)
{
/* Release the DMA TX/RX socket buffers */
dma_free_rx_skbufs(priv);
dma_free_tx_skbufs(priv);
/* Free the region of consistent memory previously allocated for
* the DMA */
dma_free_coherent(priv->device,
priv->dma_tx_size * sizeof(struct dma_desc),
priv->dma_tx, priv->dma_tx_phy);
dma_free_coherent(priv->device,
priv->dma_rx_size * sizeof(struct dma_desc),
priv->dma_rx, priv->dma_rx_phy);
kfree(priv->rx_skbuff_dma);
kfree(priv->rx_skbuff);
kfree(priv->tx_skbuff);
}
/**
* stmmac_dma_operation_mode - HW DMA operation mode
* @priv : pointer to the private device structure.
* Description: it sets the DMA operation mode: tx/rx DMA thresholds
* or Store-And-Forward capability.
*/
static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
if (likely(priv->plat->force_sf_dma_mode ||
((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) {
/*
* In case of GMAC, SF mode can be enabled
* to perform the TX COE in HW. This depends on:
* 1) TX COE if actually supported
* 2) There is no bugged Jumbo frame support
* that needs to not insert csum in the TDES.
*/
priv->hw->dma->dma_mode(priv->ioaddr,
SF_DMA_MODE, SF_DMA_MODE);
tc = SF_DMA_MODE;
} else
priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
}
/**
* stmmac_tx:
* @priv: private driver structure
* Description: it reclaims resources after transmission completes.
*/
static void stmmac_tx(struct stmmac_priv *priv)
{
unsigned int txsize = priv->dma_tx_size;
spin_lock(&priv->tx_lock);
while (priv->dirty_tx != priv->cur_tx) {
int last;
unsigned int entry = priv->dirty_tx % txsize;
struct sk_buff *skb = priv->tx_skbuff[entry];
struct dma_desc *p = priv->dma_tx + entry;
/* Check if the descriptor is owned by the DMA. */
if (priv->hw->desc->get_tx_owner(p))
break;
/* Verify tx error by looking at the last segment */
last = priv->hw->desc->get_tx_ls(p);
if (likely(last)) {
int tx_error =
priv->hw->desc->tx_status(&priv->dev->stats,
&priv->xstats, p,
priv->ioaddr);
if (likely(tx_error == 0)) {
priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++;
} else
priv->dev->stats.tx_errors++;
}
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
if (likely(p->des2))
dma_unmap_single(priv->device, p->des2,
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
priv->hw->ring->clean_desc3(p);
if (likely(skb != NULL)) {
/*
* If there's room in the queue (limit it to size)
* we add this skb back into the pool,
* if it's the right size.
*/
if ((skb_queue_len(&priv->rx_recycle) <
priv->dma_rx_size) &&
skb_recycle_check(skb, priv->dma_buf_sz))
__skb_queue_head(&priv->rx_recycle, skb);
else
dev_kfree_skb(skb);
priv->tx_skbuff[entry] = NULL;
}
priv->hw->desc->release_tx_desc(p);
priv->dirty_tx++;
}
if (unlikely(netif_queue_stopped(priv->dev) &&
stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
netif_tx_lock(priv->dev);
if (netif_queue_stopped(priv->dev) &&
stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
TX_DBG("%s: restart transmit\n", __func__);
netif_wake_queue(priv->dev);
}
netif_tx_unlock(priv->dev);
}
if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
stmmac_enable_eee_mode(priv);
mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
}
spin_unlock(&priv->tx_lock);
}
static inline void stmmac_enable_irq(struct stmmac_priv *priv)
{
#ifdef CONFIG_STMMAC_TIMER
if (likely(priv->tm->enable))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
else
#endif
priv->hw->dma->enable_dma_irq(priv->ioaddr);
}
static inline void stmmac_disable_irq(struct stmmac_priv *priv)
{
#ifdef CONFIG_STMMAC_TIMER
if (likely(priv->tm->enable))
priv->tm->timer_stop(priv->tm->timer_callb);
else
#endif
priv->hw->dma->disable_dma_irq(priv->ioaddr);
}
static int stmmac_has_work(struct stmmac_priv *priv)
{
unsigned int has_work = 0;
int rxret, tx_work = 0;
if (likely(priv->dma_rx)) {
rxret = priv->hw->desc->get_rx_owner(priv->dma_rx +
(priv->cur_rx % priv->dma_rx_size));
if (priv->dirty_tx != priv->cur_tx)
tx_work = 1;
if (likely(!rxret || tx_work))
has_work = 1;
}
return has_work;
}
static inline void _stmmac_schedule(struct stmmac_priv *priv)
{
if (likely(stmmac_has_work(priv))) {
stmmac_disable_irq(priv);
napi_schedule(&priv->napi);
}
}
#ifdef CONFIG_STMMAC_TIMER
void stmmac_schedule(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
priv->xstats.sched_timer_n++;
_stmmac_schedule(priv);
}
static void stmmac_no_timer_started(void *t, unsigned int x)
{;
};
static void stmmac_no_timer_stopped(void *t)
{;
};
#endif
/**
* stmmac_tx_err:
* @priv: pointer to the private device structure
* Description: it cleans the descriptors and restarts the transmission
* in case of errors.
*/
static void stmmac_tx_err(struct stmmac_priv *priv)
{
netif_stop_queue(priv->dev);
priv->hw->dma->stop_tx(priv->ioaddr);
dma_free_tx_skbufs(priv);
priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
priv->dirty_tx = 0;
priv->cur_tx = 0;
priv->hw->dma->start_tx(priv->ioaddr);
priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev);
}
static void stmmac_dma_interrupt(struct stmmac_priv *priv)
{
int status;
status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
if (likely(status == handle_tx_rx))
_stmmac_schedule(priv);
else if (unlikely(status == tx_hard_error_bump_tc)) {
/* Try to bump up the dma threshold on this failure */
if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
tc += 64;
priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
priv->xstats.threshold = tc;
}
} else if (unlikely(status == tx_hard_error))
stmmac_tx_err(priv);
}
static void stmmac_mmc_setup(struct stmmac_priv *priv)
{
unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
/* Mask MMC irq, counters are managed in SW and registers
* are cleared on each READ eventually. */
dwmac_mmc_intr_all_mask(priv->ioaddr);
if (priv->dma_cap.rmon) {
dwmac_mmc_ctrl(priv->ioaddr, mode);
memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
} else
pr_info(" No MAC Management Counters available\n");
}
static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
{
u32 hwid = priv->hw->synopsys_uid;
/* Only check valid Synopsys Id because old MAC chips
* have no HW registers where get the ID */
if (likely(hwid)) {
u32 uid = ((hwid & 0x0000ff00) >> 8);
u32 synid = (hwid & 0x000000ff);
pr_info("stmmac - user ID: 0x%x, Synopsys ID: 0x%x\n",
uid, synid);
return synid;
}
return 0;
}
/**
* stmmac_selec_desc_mode
* @priv : private structure
* Description: select the Enhanced/Alternate or Normal descriptors
*/
static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
{
if (priv->plat->enh_desc) {
pr_info(" Enhanced/Alternate descriptors\n");
priv->hw->desc = &enh_desc_ops;
} else {
pr_info(" Normal descriptors\n");
priv->hw->desc = &ndesc_ops;
}
}
/**
* stmmac_get_hw_features
* @priv : private device pointer
* Description:
* new GMAC chip generations have a new register to indicate the
* presence of the optional feature/functions.
* This can be also used to override the value passed through the
* platform and necessary for old MAC10/100 and GMAC chips.
*/
static int stmmac_get_hw_features(struct stmmac_priv *priv)
{
u32 hw_cap = 0;
if (priv->hw->dma->get_hw_feature) {
hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
priv->dma_cap.mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
priv->dma_cap.multi_addr =
(hw_cap & DMA_HW_FEAT_ADDMACADRSEL) >> 5;
priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
priv->dma_cap.pmt_remote_wake_up =
(hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
priv->dma_cap.pmt_magic_frame =
(hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
/* MMC */
priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
/* IEEE 1588-2002*/
priv->dma_cap.time_stamp =
(hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
/* IEEE 1588-2008*/
priv->dma_cap.atime_stamp =
(hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
/* 802.3az - Energy-Efficient Ethernet (EEE) */
priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
/* TX and RX csum */
priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
priv->dma_cap.rx_coe_type1 =
(hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
priv->dma_cap.rx_coe_type2 =
(hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
priv->dma_cap.rxfifo_over_2048 =
(hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
/* TX and RX number of channels */
priv->dma_cap.number_rx_channel =
(hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
priv->dma_cap.number_tx_channel =
(hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
/* Alternate (enhanced) DESC mode*/
priv->dma_cap.enh_desc =
(hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
}
return hw_cap;
}
static void stmmac_check_ether_addr(struct stmmac_priv *priv)
{
/* verify if the MAC address is valid, in case of failures it
* generates a random MAC address */
if (!is_valid_ether_addr(priv->dev->dev_addr)) {
priv->hw->mac->get_umac_addr((void __iomem *)
priv->dev->base_addr,
priv->dev->dev_addr, 0);
if (!is_valid_ether_addr(priv->dev->dev_addr))
random_ether_addr(priv->dev->dev_addr);
}
pr_warning("%s: device MAC address %pM\n", priv->dev->name,
priv->dev->dev_addr);
}
static int _stmmac_open(struct net_device *dev, bool resuming)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
stmmac_check_ether_addr(priv);
if (!resuming)
pm_runtime_get_sync(priv->device);
/* MDIO bus Registration */
#ifdef CONFIG_STMMAC_TIMER
priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
if (unlikely(priv->tm == NULL)) {
pr_err("%s: ERROR: timer memory alloc failed\n", __func__);
return -ENOMEM;
}
priv->tm->freq = tmrate;
/* Test if the external timer can be actually used.
* In case of failure continue without timer. */
if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
pr_warning("stmmac (%s): cannot attach the external timer.\n",
dev->name);
priv->tm->freq = 0;
priv->tm->timer_start = stmmac_no_timer_started;
priv->tm->timer_stop = stmmac_no_timer_stopped;
} else
priv->tm->enable = 1;
#endif
ret = stmmac_init_phy(dev);
if (unlikely(ret)) {
pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
goto open_error;
}
/* Create and initialize the TX/RX descriptors chains. */
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
init_dma_desc_rings(dev);
/* DMA initialization and SW reset */
ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl,
priv->dma_tx_phy, priv->dma_rx_phy);
if (ret < 0) {
pr_err("%s: DMA initialization failed\n", __func__);
goto open_error;
}
/* Copy the MAC addr into the HW */
priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
/* If required, perform hw setup of the bus. */
if (priv->plat->bus_setup)
priv->plat->bus_setup(priv->ioaddr);
/* Initialize the MAC Core */
priv->hw->mac->core_init(priv->ioaddr);
/* Request the IRQ lines */
ret = request_irq(dev->irq, stmmac_interrupt,
IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
__func__, dev->irq, ret);
goto open_error;
}
/* Request the Wake IRQ in case of another line is used for WoL */
if (priv->wol_irq != dev->irq) {
ret = request_irq(priv->wol_irq, stmmac_interrupt,
IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
pr_err("%s: ERROR: allocating the ext WoL IRQ %d "
"(error: %d)\n", __func__, priv->wol_irq, ret);
goto open_error_wolirq;
}
}
/* Request the IRQ lines */
if (priv->lpi_irq != -ENXIO) {
ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED,
dev->name, dev);
if (unlikely(ret < 0)) {
pr_err("%s: ERROR: allocating the LPI IRQ %d"
" (error: %d)\n", __func__, priv->lpi_irq, ret);
goto open_error_lpiirq;
}
}
/* Enable the MAC Rx/Tx */
stmmac_set_mac(priv->ioaddr, true);
/* Set the HW DMA mode and the COE */
stmmac_dma_operation_mode(priv);
/* Extra statistics */
memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
priv->xstats.threshold = tc;
stmmac_mmc_setup(priv);
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
if (ret < 0)
pr_warning("%s: failed debugFS registration\n", __func__);
#endif
/* Start the ball rolling... */
DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
priv->hw->dma->start_tx(priv->ioaddr);
priv->hw->dma->start_rx(priv->ioaddr);
#ifdef CONFIG_STMMAC_TIMER
if (likely(priv->tm->enable))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
#endif
/* Dump DMA/MAC registers */
if (netif_msg_hw(priv)) {
priv->hw->mac->dump_regs(priv->ioaddr);
priv->hw->dma->dump_regs(priv->ioaddr);
}
if (priv->phydev)
phy_start(priv->phydev);
priv->eee_enabled = stmmac_eee_init(priv);
if (!resuming)
pm_runtime_put(priv->device);
napi_enable(&priv->napi);
skb_queue_head_init(&priv->rx_recycle);
netif_start_queue(dev);
return 0;
open_error_lpiirq:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
open_error_wolirq:
free_irq(dev->irq, dev);
open_error:
#ifdef CONFIG_STMMAC_TIMER
kfree(priv->tm);
#endif
if (priv->phydev)
phy_disconnect(priv->phydev);
if (!resuming)
pm_runtime_put(priv->device);
return ret;
}
/**
* stmmac_open - open entry point of the driver
* @dev : pointer to the device structure.
* Description:
* This function is the open entry point of the driver.
* Return value:
* 0 on success and an appropriate (-)ve integer as defined in errno.h
* file on failure.
*/
static int stmmac_open(struct net_device *dev)
{
return _stmmac_open(dev, false);
}
static int _stmmac_release(struct net_device *dev, bool suspending)
{
struct stmmac_priv *priv = netdev_priv(dev);
if (!suspending)
pm_runtime_get_sync(priv->device);
if (priv->eee_enabled)
del_timer_sync(&priv->eee_ctrl_timer);
/* Stop and disconnect the PHY */
if (priv->phydev) {
phy_stop(priv->phydev);
phy_disconnect(priv->phydev);
priv->phydev = NULL;
}
netif_stop_queue(dev);
#ifdef CONFIG_STMMAC_TIMER
/* Stop and release the timer */
stmmac_close_ext_timer(priv->tm->timer_callb);
if (priv->tm != NULL)
kfree(priv->tm);
#endif
napi_disable(&priv->napi);
skb_queue_purge(&priv->rx_recycle);
/* Free the IRQ lines */
free_irq(dev->irq, dev);
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
if (priv->lpi_irq != -ENXIO)
free_irq(priv->lpi_irq, dev);
/* Stop TX/RX DMA and clear the descriptors */
priv->hw->dma->stop_tx(priv->ioaddr);
priv->hw->dma->stop_rx(priv->ioaddr);
/* Release and free the Rx/Tx resources */
free_dma_desc_resources(priv);
/* Disable the MAC Rx/Tx */
stmmac_set_mac(priv->ioaddr, false);
netif_carrier_off(dev);
#ifdef CONFIG_STMMAC_DEBUG_FS
stmmac_exit_fs();
#endif
if (!suspending)
pm_runtime_put_sync(priv->device);
return 0;
}
/**
* stmmac_release - close entry point of the driver
* @dev : device pointer.
* Description:
* This is the stop entry point of the driver.
*/
static int stmmac_release(struct net_device *dev)
{
return _stmmac_release(dev, false);
}
/*
* To perform emulated hardware segmentation on skb.
*/
static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb)
{
struct sk_buff *segs, *curr_skb;
int gso_segs = skb_shinfo(skb)->gso_segs;
/* Estimate the number of fragments in the worst case */
if (unlikely(stmmac_tx_avail(priv) < gso_segs)) {
netif_stop_queue(priv->dev);
TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n",
__func__);
if (stmmac_tx_avail(priv) < gso_segs)
return NETDEV_TX_BUSY;
netif_wake_queue(priv->dev);
}
TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n",
skb, skb->len);
segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO);
if (IS_ERR(segs))
goto sw_tso_end;
do {
curr_skb = segs;
segs = segs->next;
TX_DBG("\t\tcurrent skb->len: %d, *curr %p,"
"*next %p\n", curr_skb->len, curr_skb, segs);
curr_skb->next = NULL;
stmmac_xmit(curr_skb, priv->dev);
} while (segs);
sw_tso_end:
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
/**
* stmmac_xmit:
* @skb : the socket buffer
* @dev : device pointer
* Description : Tx entry point of the driver.
*/
static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int txsize = priv->dma_tx_size;
unsigned int entry;
int i, csum_insertion = 0;
int nfrags = skb_shinfo(skb)->nr_frags;
struct dma_desc *desc, *first;
unsigned int nopaged_len = skb_headlen(skb);
if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
/* This is a hard error, log it. */
pr_err("%s: BUG! Tx Ring full when queue awake\n",
__func__);
}
return NETDEV_TX_BUSY;
}
if (priv->tx_path_in_lpi_mode)
stmmac_disable_eee_mode(priv);
entry = priv->cur_tx % txsize;
#ifdef STMMAC_XMIT_DEBUG
if ((skb->len > ETH_FRAME_LEN) || nfrags)
pr_info("stmmac xmit:\n"
"\tskb addr %p - len: %d - nopaged_len: %d\n"
"\tn_frags: %d - ip_summed: %d - %s gso\n",
skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
!skb_is_gso(skb) ? "isn't" : "is");
#endif
if (unlikely(skb_is_gso(skb)))
return stmmac_sw_tso(priv, skb);
spin_lock(&priv->tx_lock);
if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
if (unlikely((!priv->plat->tx_coe) ||
(priv->no_csum_insertion)))
skb_checksum_help(skb);
else
csum_insertion = 1;
}
desc = priv->dma_tx + entry;
first = desc;
#ifdef STMMAC_XMIT_DEBUG
if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
"\t\tn_frags: %d, ip_summed: %d\n",
skb->len, nopaged_len, nfrags, skb->ip_summed);
#endif
priv->tx_skbuff[entry] = skb;
if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
desc = priv->dma_tx + entry;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
csum_insertion);
}
for (i = 0; i < nfrags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
int len = frag->size;
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
desc->des2 = dma_map_page(priv->device, frag->page,
frag->page_offset,
len, DMA_TO_DEVICE);
priv->tx_skbuff[entry] = NULL;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
wmb();
priv->hw->desc->set_tx_owner(desc);
}
/* Interrupt on completition only for the latest segment */
priv->hw->desc->close_tx_desc(desc);
#ifdef CONFIG_STMMAC_TIMER
/* Clean IC while using timer */
if (likely(priv->tm->enable))
priv->hw->desc->clear_tx_ic(desc);
#endif
wmb();
/* To avoid raise condition */
priv->hw->desc->set_tx_owner(first);
priv->cur_tx++;
#ifdef STMMAC_XMIT_DEBUG
if (netif_msg_pktdata(priv)) {
pr_info("stmmac xmit: current=%d, dirty=%d, entry=%d, "
"first=%p, nfrags=%d\n",
(priv->cur_tx % txsize), (priv->dirty_tx % txsize),
entry, first, nfrags);
display_ring(priv->dma_tx, txsize);
pr_info(">>> frame to be transmitted: ");
print_pkt(skb->data, skb->len);
}
#endif
if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
TX_DBG("%s: stop transmitted packets\n", __func__);
netif_stop_queue(dev);
}
dev->stats.tx_bytes += skb->len;
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
spin_unlock(&priv->tx_lock);
return NETDEV_TX_OK;
}
static inline void stmmac_rx_refill(struct stmmac_priv *priv)
{
unsigned int rxsize = priv->dma_rx_size;
int bfsize = priv->dma_buf_sz;
struct dma_desc *p = priv->dma_rx;
for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) {
unsigned int entry = priv->dirty_rx % rxsize;
if (likely(priv->rx_skbuff[entry] == NULL)) {
struct sk_buff *skb;
skb = __skb_dequeue(&priv->rx_recycle);
if (skb == NULL)
skb = netdev_alloc_skb_ip_align(priv->dev,
bfsize);
if (unlikely(skb == NULL))
break;
priv->rx_skbuff[entry] = skb;
priv->rx_skbuff_dma[entry] =
dma_map_single(priv->device, skb->data, bfsize,
DMA_FROM_DEVICE);
(p + entry)->des2 = priv->rx_skbuff_dma[entry];
if (unlikely(priv->plat->has_gmac))
priv->hw->ring->refill_desc3(bfsize, p + entry);
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
wmb();
priv->hw->desc->set_rx_owner(p + entry);
}
}
static int stmmac_rx(struct stmmac_priv *priv, int limit)
{
unsigned int rxsize = priv->dma_rx_size;
unsigned int entry = priv->cur_rx % rxsize;
unsigned int next_entry;
unsigned int count = 0;
struct dma_desc *p = priv->dma_rx + entry;
struct dma_desc *p_next;
#ifdef STMMAC_RX_DEBUG
if (netif_msg_hw(priv)) {
pr_debug(">>> stmmac_rx: descriptor ring:\n");
display_ring(priv->dma_rx, rxsize);
}
#endif
while ((!priv->hw->desc->get_rx_owner(p)) && (count < limit)) {
int status;
count++;
next_entry = (++priv->cur_rx) % rxsize;
p_next = priv->dma_rx + next_entry;
prefetch(p_next);
/* read the status of the incoming frame */
status = (priv->hw->desc->rx_status(&priv->dev->stats,
&priv->xstats, p));
if (unlikely(status == discard_frame))
priv->dev->stats.rx_errors++;
else {
struct sk_buff *skb;
int frame_len;
frame_len = priv->hw->desc->get_rx_frame_len(p);
/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
* Type frames (LLC/LLC-SNAP) */
if (unlikely(status != llc_snap))
frame_len -= ETH_FCS_LEN;
#ifdef STMMAC_RX_DEBUG
if (frame_len > ETH_FRAME_LEN)
pr_debug("\tRX frame size %d, COE status: %d\n",
frame_len, status);
if (netif_msg_hw(priv))
pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
p, entry, p->des2);
#endif
skb = priv->rx_skbuff[entry];
if (unlikely(!skb)) {
pr_err("%s: Inconsistent Rx descriptor chain\n",
priv->dev->name);
priv->dev->stats.rx_dropped++;
break;
}
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;
skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
priv->dma_buf_sz, DMA_FROM_DEVICE);
#ifdef STMMAC_RX_DEBUG
if (netif_msg_pktdata(priv)) {
pr_info(" frame received (%dbytes)", frame_len);
print_pkt(skb->data, frame_len);
}
#endif
skb->protocol = eth_type_trans(skb, priv->dev);
if (unlikely(!priv->rx_coe)) {
/* No csum for the old mac 10/100 devices */
skb->ip_summed = CHECKSUM_NONE;
netif_receive_skb(skb);
} else {
skb->ip_summed = CHECKSUM_UNNECESSARY;
napi_gro_receive(&priv->napi, skb);
}
priv->dev->stats.rx_packets++;
priv->dev->stats.rx_bytes += frame_len;
priv->dev->last_rx = jiffies;
}
entry = next_entry;
p = p_next; /* use prefetched values */
}
stmmac_rx_refill(priv);
priv->xstats.rx_pkt_n += count;
return count;
}
/**
* stmmac_poll - stmmac poll method (NAPI)
* @napi : pointer to the napi structure.
* @budget : maximum number of packets that the current CPU can receive from
* all interfaces.
* Description :
* This function implements the the reception process.
* Also it runs the TX completion thread
*/
static int stmmac_poll(struct napi_struct *napi, int budget)
{
struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi);
int work_done = 0;
priv->xstats.poll_n++;
stmmac_tx(priv);
work_done = stmmac_rx(priv, budget);
if (work_done < budget) {
napi_complete(napi);
stmmac_enable_irq(priv);
}
return work_done;
}
/**
* stmmac_tx_timeout
* @dev : Pointer to net device structure
* Description: this function is called when a packet transmission fails to
* complete within a reasonable tmrate. The driver will mark the error in the
* netdev structure and arrange for the device to be reset to a sane state
* in order to transmit a new packet.
*/
static void stmmac_tx_timeout(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
/* Clear Tx resources and restart transmitting again */
stmmac_tx_err(priv);
}
/* Configuration changes (passed on by ifconfig) */
static int stmmac_config(struct net_device *dev, struct ifmap *map)
{
if (dev->flags & IFF_UP) /* can't act on a running interface */
return -EBUSY;
/* Don't allow changing the I/O address */
if (map->base_addr != dev->base_addr) {
pr_warning("%s: can't change I/O address\n", dev->name);
return -EOPNOTSUPP;
}
/* Don't allow changing the IRQ */
if (map->irq != dev->irq) {
pr_warning("%s: can't change IRQ number %d\n",
dev->name, dev->irq);
return -EOPNOTSUPP;
}
/* ignore other fields */
return 0;
}
/**
* stmmac_multicast_list - entry point for multicast addressing
* @dev : pointer to the device structure
* Description:
* This function is a driver entry point which gets called by the kernel
* whenever multicast addresses must be enabled/disabled.
* Return value:
* void.
*/
static void stmmac_multicast_list(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
spin_lock(&priv->lock);
priv->hw->mac->set_filter(dev);
spin_unlock(&priv->lock);
}
/**
* stmmac_change_mtu - entry point to change MTU size for the device.
* @dev : device pointer.
* @new_mtu : the new MTU size for the device.
* Description: the Maximum Transfer Unit (MTU) is used by the network layer
* to drive packet transmission. Ethernet has an MTU of 1500 octets
* (ETH_DATA_LEN). This value can be changed with ifconfig.
* Return value:
* 0 on success and an appropriate (-)ve integer as defined in errno.h
* file on failure.
*/
static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
{
struct stmmac_priv *priv = netdev_priv(dev);
int max_mtu = ETH_DATA_LEN;
if (netif_running(dev)) {
pr_err("%s: must be stopped to change its MTU\n", dev->name);
return -EBUSY;
}
if (priv->plat->enh_desc)
max_mtu = JUMBO_LEN;
else
max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
if ((new_mtu < 46) || (new_mtu > max_mtu)) {
pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
return -EINVAL;
}
/* Some GMAC devices have a bugged Jumbo frame support that
* needs to have the Tx COE disabled for oversized frames
* (due to limited buffer sizes). In this case we disable
* the TX csum insertionin the TDES and not use SF. */
if ((priv->plat->bugged_jumbo) && (max_mtu > ETH_DATA_LEN))
priv->no_csum_insertion = 1;
else
priv->no_csum_insertion = 0;
dev->mtu = new_mtu;
return 0;
}
static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct stmmac_priv *priv = netdev_priv(dev);
if (unlikely(!dev)) {
pr_err("%s: invalid dev pointer\n", __func__);
return IRQ_NONE;
}
/* To handle GMAC own interrupts */
if (priv->plat->has_gmac) {
int status = priv->hw->mac->host_irq_status((void __iomem *)
dev->base_addr);
if (unlikely(status)) {
if (status & core_mmc_tx_irq)
priv->xstats.mmc_tx_irq_n++;
if (status & core_mmc_rx_irq)
priv->xstats.mmc_rx_irq_n++;
if (status & core_mmc_rx_csum_offload_irq)
priv->xstats.mmc_rx_csum_offload_irq_n++;
if (status & core_irq_receive_pmt_irq)
priv->xstats.irq_receive_pmt_irq_n++;
/* For LPI we need to save the tx status */
if (status & core_irq_tx_path_in_lpi_mode) {
priv->xstats.irq_tx_path_in_lpi_mode_n++;
priv->tx_path_in_lpi_mode = true;
}
if (status & core_irq_tx_path_exit_lpi_mode) {
priv->xstats.irq_tx_path_exit_lpi_mode_n++;
priv->tx_path_in_lpi_mode = false;
}
if (status & core_irq_rx_path_in_lpi_mode)
priv->xstats.irq_rx_path_in_lpi_mode_n++;
if (status & core_irq_rx_path_exit_lpi_mode)
priv->xstats.irq_rx_path_exit_lpi_mode_n++;
}
}
/* To handle DMA interrupts */
stmmac_dma_interrupt(priv);
return IRQ_HANDLED;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling receive - used by NETCONSOLE and other diagnostic tools
* to allow network I/O with interrupts disabled. */
static void stmmac_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
stmmac_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
/**
* stmmac_ioctl - Entry point for the Ioctl
* @dev: Device pointer.
* @rq: An IOCTL specefic structure, that can contain a pointer to
* a proprietary structure used to pass information to the driver.
* @cmd: IOCTL command
* Description:
* Currently there are no special functionality supported in IOCTL, just the
* phy_mii_ioctl(...) can be invoked.
*/
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret = -EOPNOTSUPP;
if (!netif_running(dev))
return -EINVAL;
switch (cmd) {
case SIOCGMIIPHY:
case SIOCGMIIREG:
case SIOCSMIIREG:
if (!priv->phydev)
return -EINVAL;
ret = phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
default:
break;
}
return ret;
}
#ifdef STMMAC_VLAN_TAG_USED
static void stmmac_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
{
struct stmmac_priv *priv = netdev_priv(dev);
DBG(probe, INFO, "%s: Setting vlgrp to %p\n", dev->name, grp);
spin_lock(&priv->lock);
priv->vlgrp = grp;
spin_unlock(&priv->lock);
}
#endif
#ifdef CONFIG_STMMAC_DEBUG_FS
static struct dentry *stmmac_fs_dir;
static struct dentry *stmmac_rings_status;
static struct dentry *stmmac_dma_cap;
static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
{
struct tmp_s {
u64 a;
unsigned int b;
unsigned int c;
};
int i;
struct net_device *dev = seq->private;
struct stmmac_priv *priv = netdev_priv(dev);
seq_printf(seq, "=======================\n");
seq_printf(seq, " RX descriptor ring\n");
seq_printf(seq, "=======================\n");
for (i = 0; i < priv->dma_rx_size; i++) {
struct tmp_s *x = (struct tmp_s *)(priv->dma_rx + i);
seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
i, (unsigned int)(x->a),
(unsigned int)((x->a) >> 32), x->b, x->c);
seq_printf(seq, "\n");
}
seq_printf(seq, "\n");
seq_printf(seq, "=======================\n");
seq_printf(seq, " TX descriptor ring\n");
seq_printf(seq, "=======================\n");
for (i = 0; i < priv->dma_tx_size; i++) {
struct tmp_s *x = (struct tmp_s *)(priv->dma_tx + i);
seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
i, (unsigned int)(x->a),
(unsigned int)((x->a) >> 32), x->b, x->c);
seq_printf(seq, "\n");
}
return 0;
}
static int stmmac_sysfs_ring_open(struct inode *inode, struct file *file)
{
return single_open(file, stmmac_sysfs_ring_read, inode->i_private);
}
static const struct file_operations stmmac_rings_status_fops = {
.owner = THIS_MODULE,
.open = stmmac_sysfs_ring_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v)
{
struct net_device *dev = seq->private;
struct stmmac_priv *priv = netdev_priv(dev);
if (!priv->hw_cap_support) {
seq_printf(seq, "DMA HW features not supported\n");
return 0;
}
seq_printf(seq, "==============================\n");
seq_printf(seq, "\tDMA HW features\n");
seq_printf(seq, "==============================\n");
seq_printf(seq, "\t10/100 Mbps %s\n",
(priv->dma_cap.mbps_10_100) ? "Y" : "N");
seq_printf(seq, "\t1000 Mbps %s\n",
(priv->dma_cap.mbps_1000) ? "Y" : "N");
seq_printf(seq, "\tHalf duple %s\n",
(priv->dma_cap.half_duplex) ? "Y" : "N");
seq_printf(seq, "\tHash Filter: %s\n",
(priv->dma_cap.hash_filter) ? "Y" : "N");
seq_printf(seq, "\tMultiple MAC address registers: %s\n",
(priv->dma_cap.multi_addr) ? "Y" : "N");
seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n",
(priv->dma_cap.pcs) ? "Y" : "N");
seq_printf(seq, "\tSMA (MDIO) Interface: %s\n",
(priv->dma_cap.sma_mdio) ? "Y" : "N");
seq_printf(seq, "\tPMT Remote wake up: %s\n",
(priv->dma_cap.pmt_remote_wake_up) ? "Y" : "N");
seq_printf(seq, "\tPMT Magic Frame: %s\n",
(priv->dma_cap.pmt_magic_frame) ? "Y" : "N");
seq_printf(seq, "\tRMON module: %s\n",
(priv->dma_cap.rmon) ? "Y" : "N");
seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n",
(priv->dma_cap.time_stamp) ? "Y" : "N");
seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n",
(priv->dma_cap.atime_stamp) ? "Y" : "N");
seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n",
(priv->dma_cap.eee) ? "Y" : "N");
seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N");
seq_printf(seq, "\tChecksum Offload in TX: %s\n",
(priv->dma_cap.tx_coe) ? "Y" : "N");
seq_printf(seq, "\tIP Checksum Offload (type1) in RX: %s\n",
(priv->dma_cap.rx_coe_type1) ? "Y" : "N");
seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n",
(priv->dma_cap.rx_coe_type2) ? "Y" : "N");
seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n",
(priv->dma_cap.rxfifo_over_2048) ? "Y" : "N");
seq_printf(seq, "\tNumber of Additional RX channel: %d\n",
priv->dma_cap.number_rx_channel);
seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
priv->dma_cap.number_tx_channel);
seq_printf(seq, "\tEnhanced descriptors: %s\n",
(priv->dma_cap.enh_desc) ? "Y" : "N");
return 0;
}
static int stmmac_sysfs_dma_cap_open(struct inode *inode, struct file *file)
{
return single_open(file, stmmac_sysfs_dma_cap_read, inode->i_private);
}
static const struct file_operations stmmac_dma_cap_fops = {
.owner = THIS_MODULE,
.open = stmmac_sysfs_dma_cap_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int stmmac_init_fs(struct net_device *dev)
{
/* Create debugfs entries */
stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
pr_err("ERROR %s, debugfs create directory failed\n",
STMMAC_RESOURCE_NAME);
return -ENOMEM;
}
/* Entry to report DMA RX/TX rings */
stmmac_rings_status = debugfs_create_file("descriptors_status",
S_IRUGO, stmmac_fs_dir, dev,
&stmmac_rings_status_fops);
if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
pr_info("ERROR creating stmmac ring debugfs file\n");
debugfs_remove(stmmac_fs_dir);
return -ENOMEM;
}
/* Entry to report the DMA HW features */
stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
dev, &stmmac_dma_cap_fops);
if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
pr_info("ERROR creating stmmac MMC debugfs file\n");
debugfs_remove(stmmac_rings_status);
debugfs_remove(stmmac_fs_dir);
return -ENOMEM;
}
return 0;
}
static void stmmac_exit_fs(void)
{
debugfs_remove(stmmac_rings_status);
debugfs_remove(stmmac_dma_cap);
debugfs_remove(stmmac_fs_dir);
}
#endif /* CONFIG_STMMAC_DEBUG_FS */
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
.ndo_set_multicast_list = stmmac_multicast_list,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_set_config = stmmac_config,
#ifdef STMMAC_VLAN_TAG_USED
.ndo_vlan_rx_register = stmmac_vlan_rx_register,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = stmmac_poll_controller,
#endif
.ndo_set_mac_address = eth_mac_addr,
};
/*
* stmmac_hw_init - Init the MAC device
* @priv : pointer to the private device structure.
* Description: this function detects which MAC device
* (GMAC/MAC10-100) has to attached, checks the HW capability
* (if supported) and sets the driver's features (for example
* to use the ring or chaine mode or support the normal/enh
* descriptor structure).
*/
static int stmmac_hw_init(struct stmmac_priv *priv)
{
int ret = 0;
struct mac_device_info *mac;
/* Identify the MAC HW device */
if (priv->plat->has_gmac)
mac = dwmac1000_setup(priv->ioaddr);
else
mac = dwmac100_setup(priv->ioaddr);
if (!mac)
return -ENOMEM;
priv->hw = mac;
/* To use the chained or ring mode */
priv->hw->ring = &ring_mode_ops;
/* Get and dump the chip ID */
stmmac_get_synopsys_id(priv);
/* Get the HW capability (new GMAC newer than 3.50a) */
priv->hw_cap_support = stmmac_get_hw_features(priv);
if (priv->hw_cap_support) {
pr_info(" DMA HW capability register supported");
/* We can override some gmac/dma configuration fields: e.g.
* enh_desc, tx_coe (e.g. that are passed through the
* platform) with the values from the HW capability
* register (if supported).
*/
priv->plat->enh_desc = priv->dma_cap.enh_desc;
priv->plat->tx_coe = priv->dma_cap.tx_coe;
priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up;
} else
pr_info(" No HW DMA feature register supported");
/* Select the enhnaced/normal descriptor structures */
stmmac_selec_desc_mode(priv);
priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
if (priv->rx_coe)
pr_info(" RX Checksum Offload Engine supported\n");
if (priv->plat->tx_coe)
pr_info(" TX Checksum insertion supported\n");
if (priv->plat->pmt) {
pr_info(" Wake-Up On Lan supported\n");
device_set_wakeup_capable(priv->device, 1);
}
return ret;
}
/**
* stmmac_dvr_probe
* @device: device pointer
* @plat_dat: platform data pointer
* @addr: iobase memory address
* Description: this is the main probe function used to
* call the alloc_etherdev, allocate the priv structure,
* init the MDIO bus etc.
*/
struct stmmac_priv *stmmac_dvr_probe(struct device *device,
struct plat_stmmacenet_data *plat_dat,
void __iomem *addr)
{
int ret = 0;
struct net_device *ndev = NULL;
struct stmmac_priv *priv;
ndev = alloc_etherdev(sizeof(struct stmmac_priv));
if (!ndev) {
pr_err("%s: ERROR: allocating the device\n", __func__);
return NULL;
}
SET_NETDEV_DEV(ndev, device);
priv = netdev_priv(ndev);
priv->device = device;
priv->dev = ndev;
ether_setup(ndev);
stmmac_set_ethtool_ops(ndev);
priv->pause = pause;
priv->plat = plat_dat;
priv->ioaddr = addr;
priv->dev->base_addr = (unsigned long)addr;
/* Verify driver arguments */
stmmac_verify_args();
/* Override with kernel parameters if supplied XXX CRS XXX
* this needs to have multiple instances */
if ((phyaddr >= 0) && (phyaddr <= 31))
priv->plat->phy_addr = phyaddr;
/* Init MAC and get the capabilities */
stmmac_hw_init(priv);
ndev->netdev_ops = &stmmac_netdev_ops;
ndev->features |= /* NETIF_F_SG | */ NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
ndev->features |= NETIF_F_HW_VLAN_RX;
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);
if (flow_ctrl)
priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
spin_lock_init(&priv->lock);
spin_lock_init(&priv->tx_lock);
ret = register_netdev(ndev);
if (ret) {
pr_err("%s: ERROR %i registering the device\n", __func__, ret);
goto netdev_error;
}
ret = stmmac_mdio_register(ndev);
if (ret < 0) {
pr_err("%s: MDIO bus (id: %d) registration failed",
__func__, priv->plat->bus_id);
goto exit_error;
}
return priv;
exit_error:
unregister_netdev(ndev);
netdev_error:
netif_napi_del(&priv->napi);
free_netdev(ndev);
return NULL;
}
/**
* stmmac_dvr_remove
* @ndev: net device pointer
* Description: this function resets the TX/RX processes, disables the MAC RX/TX
* changes the link status, releases the DMA descriptor rings,
* unregisters the MDIO bus.
*/
int stmmac_dvr_remove(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
pr_info("%s:\n\tremoving driver", __func__);
priv->hw->dma->stop_rx(priv->ioaddr);
priv->hw->dma->stop_tx(priv->ioaddr);
stmmac_set_mac(priv->ioaddr, false);
netif_carrier_off(ndev);
stmmac_mdio_unregister(ndev);
unregister_netdev(ndev);
free_netdev(ndev);
return 0;
}
#ifdef CONFIG_PM
int stmmac_suspend(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
int dis_ic = 0;
if (!ndev || !netif_running(ndev))
return 0;
if (priv->phydev)
phy_stop(priv->phydev);
spin_lock(&priv->lock);
netif_device_detach(ndev);
netif_stop_queue(ndev);
#ifdef CONFIG_STMMAC_TIMER
priv->tm->timer_stop(priv->tm->timer_callb);
if (likely(priv->tm->enable))
dis_ic = 1;
#endif
napi_disable(&priv->napi);
/* Stop TX/RX DMA */
priv->hw->dma->stop_tx(priv->ioaddr);
priv->hw->dma->stop_rx(priv->ioaddr);
/* Clear the Rx/Tx descriptors */
priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
dis_ic);
priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
/* If the wake-up On Lan can be done by the PHY device
* (that supports WoL+) there is no reason to program the PMT
* registers. This means that to enable Power down mode programming
* the PMT regs either the phy doesn't support WoL+ or the PHY
* supports that but not the WoL mode required by the user.
*/
if (device_may_wakeup(priv->device) && (!priv->phy_wol_plus))
priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
else
stmmac_set_mac(priv->ioaddr, false);
spin_unlock(&priv->lock);
return 0;
}
int stmmac_resume(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
if (!netif_running(ndev))
return 0;
spin_lock(&priv->lock);
if (device_may_wakeup(priv->device) && (!priv->phy_wol_plus))
/* Power Down bit, into the PM register, is cleared
* automatically as soon as a magic packet or a Wake-up frame
* is received. Anyway, it's better to manually clear
* this bit because it can generate problems while resuming
* from another devices (e.g. serial console). */
priv->hw->mac->pmt(priv->ioaddr, 0);
netif_device_attach(ndev);
/* Enable the MAC and DMA */
stmmac_set_mac(priv->ioaddr, true);
priv->hw->dma->start_tx(priv->ioaddr);
priv->hw->dma->start_rx(priv->ioaddr);
#ifdef CONFIG_STMMAC_TIMER
if (likely(priv->tm->enable))
priv->tm->timer_start(priv->tm->timer_callb, tmrate);
#endif
napi_enable(&priv->napi);
netif_start_queue(ndev);
spin_unlock(&priv->lock);
if (priv->phydev)
phy_start(priv->phydev);
return 0;
}
int stmmac_freeze(struct net_device *ndev)
{
if (!ndev || !netif_running(ndev))
return 0;
return _stmmac_release(ndev, true);
}
int stmmac_restore(struct net_device *ndev)
{
if (!ndev || !netif_running(ndev))
return 0;
return _stmmac_open(ndev, true);
}
#endif /* CONFIG_PM */
#ifndef MODULE
static int __init stmmac_cmdline_opt(char *str)
{
char *opt;
if (!str || !*str)
return -EINVAL;
while ((opt = strsep(&str, ",")) != NULL) {
if (!strncmp(opt, "debug:", 6)) {
if (strict_strtoul(opt + 6, 0, (unsigned long *)&debug))
goto err;
} else if (!strncmp(opt, "phyaddr:", 8)) {
if (strict_strtoul(opt + 8, 0,
(unsigned long *)&phyaddr))
goto err;
} else if (!strncmp(opt, "dma_txsize:", 11)) {
if (strict_strtoul(opt + 11, 0,
(unsigned long *)&dma_txsize))
goto err;
} else if (!strncmp(opt, "dma_rxsize:", 11)) {
if (strict_strtoul(opt + 11, 0,
(unsigned long *)&dma_rxsize))
goto err;
} else if (!strncmp(opt, "buf_sz:", 7)) {
if (strict_strtoul(opt + 7, 0,
(unsigned long *)&buf_sz))
goto err;
} else if (!strncmp(opt, "tc:", 3)) {
if (strict_strtoul(opt + 3, 0, (unsigned long *)&tc))
goto err;
} else if (!strncmp(opt, "watchdog:", 9)) {
if (strict_strtoul(opt + 9, 0,
(unsigned long *)&watchdog))
goto err;
} else if (!strncmp(opt, "flow_ctrl:", 10)) {
if (strict_strtoul(opt + 10, 0,
(unsigned long *)&flow_ctrl))
goto err;
} else if (!strncmp(opt, "pause:", 6)) {
if (strict_strtoul(opt + 6, 0, (unsigned long *)&pause))
goto err;
} else if (!strncmp(opt, "wol_plus_en:", 12)) {
if (strict_strtoul(opt + 12, 0,
(unsigned long *)&wol_plus_en))
goto err;
#ifdef CONFIG_STMMAC_TIMER
} else if (!strncmp(opt, "tmrate:", 7)) {
if (strict_strtoul(opt + 7, 0,
(unsigned long *)&tmrate))
goto err;
#endif
}
}
return 0;
err:
pr_err("%s: ERROR broken module parameter conversion", __func__);
return -EINVAL;
}
__setup("stmmaceth=", stmmac_cmdline_opt);
#endif
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");