kernel: update stmmac ethernet driver from latest linux-sh4-2.6.32.y - _stm24_0217

This commit is contained in:
Jaroslav Kysela 2016-02-11 21:19:20 +01:00
parent ccc89f44ae
commit dcaf0bf211
34 changed files with 2989 additions and 591 deletions

View File

@ -277,6 +277,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!netdev)
return true;
/* PHY supports WoL+ that has been enabled by ethtool.
* So we can call the suspend function that is expected
* able to program internal registers to wake-up the system.
*/
if (phydev->wol)
return true;
/*
* Don't suspend PHY if the attched netdev parent may wakeup.
* The parent may point to a PCI device, as in tg3 driver.

View File

@ -299,6 +299,36 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
}
EXPORT_SYMBOL(phy_ethtool_gset);
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{
u32 support = phydev->drv->wol_supported;
if (wol->wolopts & ~support)
return -EINVAL;
phydev->wol = wol->wolopts;
if (wol->wolopts) {
device_set_wakeup_enable(&phydev->dev, 1);
enable_irq_wake(phydev->irq);
} else {
device_set_wakeup_enable(&phydev->dev, 0);
disable_irq_wake(phydev->irq);
}
return 0;
}
EXPORT_SYMBOL(phy_ethtool_set_wol);
int phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{
if (device_can_wakeup(&phydev->dev)) {
wol->supported = phydev->drv->wol_supported;
wol->wolopts = phydev->wol;
}
return 0;
}
EXPORT_SYMBOL(phy_ethtool_get_wol);
/**
* phy_mii_ioctl - generic PHY MII ioctl interface
* @phydev: the phy_device struct
@ -510,7 +540,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
{
struct phy_device *phydev = phy_dat;
if (PHY_HALTED == phydev->state)
if ((PHY_HALTED == phydev->state) && (!device_may_wakeup(&phydev->dev)))
return IRQ_NONE; /* It can't be ours. */
/* The MDIO bus is not allowed to be written in interrupt
@ -964,3 +994,35 @@ static void phy_state_machine(struct work_struct *work)
schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
}
int phy_read_page(struct phy_device *phydev, u16 regnum, int page)
{
int ret, old;
old = phy_read(phydev, 20);
/* Write the page in 0.20 reg */
phy_write(phydev, 20, page);
/* Read data from user page for the regnum */
ret = phy_read(phydev, regnum);
/* Restore page0 */
phy_write(phydev, 20, old);
return ret;
}
EXPORT_SYMBOL(phy_read_page);
int phy_write_page(struct phy_device *phydev, u16 regnum, int page, int data)
{
int old = phy_read(phydev, 20);
/* Write the page in 0.20 reg */
phy_write(phydev, 20, page);
/* Write date to page for regnum */
phy_write(phydev, regnum, data);
/* Restore page0 */
phy_write(phydev, 20, old);
return 0;
}
EXPORT_SYMBOL(phy_write_page);

View File

@ -30,6 +30,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/mdio.h>
#include <asm/io.h>
#include <asm/irq.h>
@ -874,6 +875,140 @@ int genphy_resume(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_resume);
static inline void mmd_phy_cl45(struct mii_bus *bus, int prtad, int devad,
int addr)
{
/* Write the desired MMD Devad */
bus->write(bus, addr, MII_MMD_CRTL, devad);
/* Write the desired MMD register address */
bus->write(bus, addr, MII_MMD_DATA, prtad);
/* Select the Function : DATA with no post increment */
bus->write(bus, addr, MII_MMD_CRTL,
(devad | MII_MMD_CTRL_FUNC_DATA_NOINCR));
}
/**
* read_phy_mmd - reads data from the MMD register (clause 22 to access to
* clause 45)
* @bus: the target MII bus
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
*
* Description: Reads data from the MMD regisetrs of the
* phy addr. To read these register we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Read reg 14 // Read MMD data
*/
static int read_phy_mmd(struct mii_bus *bus, int prtad, int devad, int addr)
{
u32 ret;
mmd_phy_cl45(bus, prtad, devad, addr);
/* Read the content of the MMD's selected register */
ret = bus->read(bus, addr, MII_MMD_DATA);
if (ret < 0)
return -EIO;
return ret;
}
/**
* write_phy_mmd - writes data to the MMD register (clause 22 to access to
* clause 45)
* @bus: the target MII bus
* @prtad: MMD Address
* @devad: MMD DEVAD
* @addr: PHY address on the MII bus
* @data: data to write in the MMD register
*
* Description: write data from the MMD regisetrs of the
* phy addr. To read these register we have:
* 1) Write reg 13 // DEVAD
* 2) Write reg 14 // MMD Address
* 3) Write reg 13 // MMD Data Command for MMD DEVAD
* 3) Write reg 14 // Write MMD data
*/
static void write_phy_mmd(struct mii_bus *bus, int prtad, int devad, int addr,
u32 data)
{
mmd_phy_cl45(bus, prtad, devad, addr);
/* Write the data into MMD's selected register */
bus->write(bus, addr, MII_MMD_DATA, data);
}
/* phy_check_eee
* @dev: device to probe and init
*
* Description: check if the Energy-Efficient Ethernet (EEE)
* is supported by looking at the MMD registers 3.20 and 3.60/61
*/
int phy_check_eee(struct phy_device *phydev)
{
int ret = -EPROTONOSUPPORT;
/* According to 802.3az,the EEE is supported only in full duplex-mode.
* Also EEE feature is active when core is operating with MII, GMII
* or RGMII */
if ((phydev->duplex == DUPLEX_FULL) &&
((phydev->interface == PHY_INTERFACE_MODE_MII) ||
(phydev->interface == PHY_INTERFACE_MODE_GMII) ||
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
int eee_cap, eee_link;
/* EEE ability must be supported in both local and remote
* PHY devices. */
eee_cap = read_phy_mmd(phydev->bus, MDIO_EEE_PART_LINK,
MDIO_MMD_AN, phydev->addr);
if (eee_cap < 0)
return eee_cap;
eee_link = read_phy_mmd(phydev->bus, MDIO_EEE_CAP,
MDIO_MMD_PCS, phydev->addr);
if (eee_link < 0)
return eee_link;
if (eee_cap && eee_link) {
/* Configure the PHY to stop receiving xMII clock
* while it is signaling LPI */
int pcs_ctrl = read_phy_mmd(phydev->bus, MDIO_CTRL1,
MDIO_MMD_PCS,
phydev->addr);
if (pcs_ctrl < 0)
return pcs_ctrl;
pcs_ctrl |= MDIO_PCS_CLK_STOP_ENABLE;
write_phy_mmd(phydev->bus, MDIO_CTRL1, MDIO_MMD_PCS,
phydev->addr, pcs_ctrl);
ret = 0; /* EEE supported */
}
}
return ret;
}
EXPORT_SYMBOL(phy_get_eee_err);
/* phy_get_eee_err
* @dev: device to probe and init
*
* Description: it is to report the number of time where the PHY
* failed to complete its normal wake sequence.
*/
int phy_get_eee_err(struct phy_device *phydev)
{
return read_phy_mmd(phydev->bus, MDIO_EEE_WK_ERR, MDIO_MMD_PCS,
phydev->addr);
}
EXPORT_SYMBOL(phy_check_eee);
/**
* phy_probe - probe and init a PHY device
* @dev: device to probe and init
@ -900,6 +1035,13 @@ static int phy_probe(struct device *dev)
/* Disable the interrupt if the PHY doesn't support it */
if (!(phydrv->flags & PHY_HAS_INTERRUPT))
phydev->irq = PHY_POLL;
else {
/* Check if the PHY is WoL capable but driver cannot work
* in polling mode.
*/
if (phydrv->wol_supported)
device_set_wakeup_capable(dev, 1);
}
mutex_lock(&phydev->lock);

View File

@ -3,7 +3,7 @@ config STMMAC_ETH
select MII
select PHYLIB
select CRC32
depends on NETDEVICES
depends on NETDEVICES && HAS_IOMEM
help
This is the driver for the Ethernet IPs are built around a
Synopsys IP Core and only tested on the STMicroelectronics
@ -11,6 +11,42 @@ config STMMAC_ETH
if STMMAC_ETH
choice
prompt "STMMAC bus support"
config STMMAC_PLATFORM
bool "Platform bus support"
depends on STMMAC_ETH
---help---
This selects the platform specific bus support for
the stmmac device driver. This is the driver used
on many embedded STM platforms based on ARM and SuperH
processors.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config STMMAC_PCI
bool "PCI bus support (EXPERIMENTAL)"
depends on STMMAC_ETH && PCI && EXPERIMENTAL
---help---
This is to select the Synopsys DWMAC available on PCI devices,
if you have a controller with this interface, say Y or M here.
This PCI support is tested on XLINX XC2V3000 FF1152AMT0221
D1215994A VIRTEX FPGA board.
If unsure, say N.
endchoice
config STMMAC_DEBUG_FS
bool "Enable monitoring via sysFS "
default n
depends on STMMAC_ETH && DEBUG_FS
help
The stmmac entry in /sys reports DMA TX/RX rings
or (if supported) the HW cap register.
config STMMAC_DA
bool "STMMAC DMA arbitration scheme"
default n
@ -44,4 +80,22 @@ config STMMAC_RTC_TIMER
endchoice
choice
prompt "Select the DMA TX/RX descriptor operating modes"
depends on STMMAC_ETH
help
This driver supports DMA descriptor to operate both in dual buffer
(RING) and linked-list(CHAINED) mode. In RING mode each descriptor
points to two data buffer pointers whereas in CHAINED mode they
points to only one data buffer pointer.
config STMMAC_RING
bool "Enable Descriptor Ring Mode"
config STMMAC_CHAINED
bool "Enable Descriptor Chained Mode"
endchoice
endif

View File

@ -1,5 +1,10 @@
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y)
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
mmc_core.o $(stmmac-y)

View File

@ -0,0 +1,137 @@
/*******************************************************************************
Specialised functions for managing Chained mode
Copyright(C) 2011 STMicroelectronics Ltd
It defines all the functions used to handle the normal/enhanced
descriptors in case of the DMA is configured to work in chained or
in ring mode.
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>
*******************************************************************************/
#include "stmmac.h"
unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_priv *priv = (struct stmmac_priv *) p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
struct dma_desc *desc = priv->dma_tx + entry;
unsigned int nopaged_len = skb_headlen(skb);
unsigned int bmax;
unsigned int i = 1, len;
if (priv->plat->enh_desc)
bmax = BUF_SIZE_8KiB;
else
bmax = BUF_SIZE_2KiB;
len = nopaged_len - bmax;
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
while (len != 0) {
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
if (len > bmax) {
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
csum);
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
len -= bmax;
i++;
} else {
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
priv->hw->desc->prepare_tx_desc(desc, 0, len,
csum);
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
len = 0;
}
}
return entry;
}
static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
{
unsigned int ret = 0;
if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
(!enh_desc && (len > BUF_SIZE_2KiB))) {
ret = 1;
}
return ret;
}
static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
{
}
static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
{
}
static void stmmac_clean_desc3(struct dma_desc *p)
{
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size)
{
/*
* In chained mode the des3 points to the next element in the ring.
* The latest element has to point to the head.
*/
int i;
struct dma_desc *p = des;
dma_addr_t dma_phy = phy_addr;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_desc);
p->des3 = (unsigned int)dma_phy;
p++;
}
p->des3 = (unsigned int)phy_addr;
}
static int stmmac_set_16kib_bfsize(int mtu)
{
/* Not supported */
return 0;
}
const struct stmmac_ring_mode_ops ring_mode_ops = {
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
.init_desc3 = stmmac_init_desc3,
.init_dma_chain = stmmac_init_dma_chain,
.clean_desc3 = stmmac_clean_desc3,
.set_16kib_bfsize = stmmac_set_16kib_bfsize,
};

View File

@ -22,13 +22,18 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/init.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define STMMAC_VLAN_TAG_USED
#include <linux/if_vlan.h>
#endif
#include "descs.h"
#include "mmc.h"
#undef CHIP_DEBUG_PRINT
/* Turn-on extra printk debug for MAC core, dma and descriptors */
@ -48,7 +53,7 @@ struct stmmac_extra_stats {
unsigned long tx_underflow ____cacheline_aligned;
unsigned long tx_carrier;
unsigned long tx_losscarrier;
unsigned long tx_heartbeat;
unsigned long vlan_tag;
unsigned long tx_deferred;
unsigned long tx_vlan;
unsigned long tx_jabber;
@ -57,11 +62,12 @@ struct stmmac_extra_stats {
unsigned long tx_ip_header_error;
/* Receive errors */
unsigned long rx_desc;
unsigned long rx_partial;
unsigned long rx_runt;
unsigned long rx_toolong;
unsigned long sa_filter_fail;
unsigned long overflow_error;
unsigned long ipc_csum_error;
unsigned long rx_collision;
unsigned long rx_crc;
unsigned long dribbling_bit;
unsigned long rx_length;
unsigned long rx_mii;
unsigned long rx_multicast;
@ -89,6 +95,16 @@ struct stmmac_extra_stats {
unsigned long poll_n;
unsigned long sched_timer_n;
unsigned long normal_irq_n;
unsigned long mmc_tx_irq_n;
unsigned long mmc_rx_irq_n;
unsigned long mmc_rx_csum_offload_irq_n;
/* EEE */
unsigned long irq_receive_pmt_irq_n;
unsigned long irq_tx_path_in_lpi_mode_n;
unsigned long irq_tx_path_exit_lpi_mode_n;
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
};
#define HASH_TABLE_SIZE 64
@ -102,6 +118,36 @@ struct stmmac_extra_stats {
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
/* DAM HW feature register fields */
#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
#define DMA_HW_FEAT_ADDMACADRSEL 0x00000020 /* Multiple MAC Addr Reg */
#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 Timestamp */
#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 Adv Timestamp */
#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP csum Offload(Type 1) in Rx */
#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP csum Offload(Type 2) in Rx */
#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. of additional Rx Channels */
#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. of additional Tx Channels */
#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate (Enhanced Descriptor) */
#define DMA_HW_FEAT_INTTSEN 0x02000000 /* Timestamping with Internal
System Time */
#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN Insertion */
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */
enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
@ -115,6 +161,48 @@ enum tx_dma_irq_status {
handle_tx_rx = 3,
};
enum core_specific_irq_mask {
core_mmc_tx_irq = 1,
core_mmc_rx_irq = 2,
core_mmc_rx_csum_offload_irq = 4,
core_irq_receive_pmt_irq = 8,
core_irq_tx_path_in_lpi_mode = 16,
core_irq_tx_path_exit_lpi_mode = 32,
core_irq_rx_path_in_lpi_mode = 64,
core_irq_rx_path_exit_lpi_mode = 128,
};
/* DMA HW capabilities */
struct dma_features {
unsigned int mbps_10_100;
unsigned int mbps_1000;
unsigned int half_duplex;
unsigned int hash_filter;
unsigned int multi_addr;
unsigned int pcs;
unsigned int sma_mdio;
unsigned int pmt_remote_wake_up;
unsigned int pmt_magic_frame;
unsigned int rmon;
/* IEEE 1588-2002*/
unsigned int time_stamp;
/* IEEE 1588-2008*/
unsigned int atime_stamp;
/* 802.3az - Energy-Efficient Ethernet (EEE) */
unsigned int eee;
unsigned int av;
/* TX and RX csum */
unsigned int tx_coe;
unsigned int rx_coe_type1;
unsigned int rx_coe_type2;
unsigned int rxfifo_over_2048;
/* TX and RX number of channels */
unsigned int number_rx_channel;
unsigned int number_tx_channel;
/* Alternate (enhanced) DESC mode*/
unsigned int enh_desc;
};
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
#define BUF_SIZE_16KiB 16384
#define BUF_SIZE_8KiB 8192
@ -130,17 +218,6 @@ enum tx_dma_irq_status {
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
/* MAC Management Counters register */
#define MMC_CONTROL 0x00000100 /* MMC Control */
#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
#define MMC_CONTROL_MAX_FRM_SHIFT 3
#define MMC_CONTROL_MAX_FRAME 0x7FF
struct stmmac_desc_ops {
/* DMA RX descriptor ring initialization */
void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
@ -198,6 +275,8 @@ struct stmmac_dma_ops {
void (*stop_rx) (void __iomem *ioaddr);
int (*dma_interrupt) (void __iomem *ioaddr,
struct stmmac_extra_stats *x);
/* If supported then get the optional core features */
unsigned int (*get_hw_feature) (void __iomem *ioaddr);
};
struct stmmac_ops {
@ -208,7 +287,7 @@ struct stmmac_ops {
/* Dump MAC registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Handle extra events on specific interrupts hw dependent */
void (*host_irq_status) (void __iomem *ioaddr);
int (*host_irq_status) (void __iomem *ioaddr);
/* Multicast filter setting */
void (*set_filter) (struct net_device *dev);
/* Flow control setting */
@ -221,6 +300,10 @@ struct stmmac_ops {
unsigned int reg_n);
void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
unsigned int reg_n);
void (*set_eee_mode) (void __iomem *ioaddr, u32 lpi_ctrl_status);
void (*reset_eee_mode) (void __iomem *ioaddr, u32 lpi_ctrl_status);
void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
void (*set_eee_pls) (void __iomem *ioaddr, int link, u32 lpi_ctrl_status);
};
struct mac_link {
@ -234,12 +317,25 @@ struct mii_regs {
unsigned int data; /* MII Data */
};
struct stmmac_ring_mode_ops {
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
void (*refill_desc3) (int bfsize, struct dma_desc *p);
void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size);
void (*clean_desc3) (struct dma_desc *p);
int (*set_16kib_bfsize) (int mtu);
};
struct mac_device_info {
const struct stmmac_ops *mac;
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_ring_mode_ops *ring;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
unsigned int synopsys_uid;
};
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
@ -249,4 +345,8 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
unsigned int high, unsigned int low);
extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int high, unsigned int low);
extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
extern const struct stmmac_ring_mode_ops ring_mode_ops;

View File

@ -25,33 +25,34 @@ struct dma_desc {
union {
struct {
/* RDES0 */
u32 reserved1:1;
u32 payload_csum_error:1;
u32 crc_error:1;
u32 dribbling:1;
u32 mii_error:1;
u32 receive_watchdog:1;
u32 frame_type:1;
u32 collision:1;
u32 frame_too_long:1;
u32 ipc_csum_error:1;
u32 last_descriptor:1;
u32 first_descriptor:1;
u32 multicast_frame:1;
u32 run_frame:1;
u32 vlan_tag:1;
u32 overflow_error:1;
u32 length_error:1;
u32 partial_frame_error:1;
u32 sa_filter_fail:1;
u32 descriptor_error:1;
u32 error_summary:1;
u32 frame_length:14;
u32 filtering_fail:1;
u32 da_filter_fail:1;
u32 own:1;
/* RDES1 */
u32 buffer1_size:11;
u32 buffer2_size:11;
u32 reserved2:2;
u32 reserved1:2;
u32 second_address_chained:1;
u32 end_ring:1;
u32 reserved3:5;
u32 reserved2:5;
u32 disable_ic:1;
} rx;
struct {
/* RDES0 */
@ -91,24 +92,28 @@ struct dma_desc {
u32 underflow_error:1;
u32 excessive_deferral:1;
u32 collision_count:4;
u32 heartbeat_fail:1;
u32 vlan_frame:1;
u32 excessive_collisions:1;
u32 late_collision:1;
u32 no_carrier:1;
u32 loss_carrier:1;
u32 reserved1:3;
u32 payload_error:1;
u32 frame_flushed:1;
u32 jabber_timeout:1;
u32 error_summary:1;
u32 reserved2:15;
u32 ip_header_error:1;
u32 time_stamp_status:1;
u32 reserved1:13;
u32 own:1;
/* TDES1 */
u32 buffer1_size:11;
u32 buffer2_size:11;
u32 reserved3:1;
u32 time_stamp_enable:1;
u32 disable_padding:1;
u32 second_address_chained:1;
u32 end_ring:1;
u32 crc_disable:1;
u32 reserved4:2;
u32 checksum_insertion:2;
u32 first_segment:1;
u32 last_segment:1;
u32 interrupt:1;

View File

@ -0,0 +1,126 @@
/*******************************************************************************
Header File to describe Normal/enhanced descriptor functions used for RING
and CHAINED modes.
Copyright(C) 2011 STMicroelectronics Ltd
It defines all the functions used to handle the normal/enhanced
descriptors in case of the DMA is configured to work in chained or
in ring mode.
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>
*******************************************************************************/
#if defined(CONFIG_STMMAC_RING)
static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
{
p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
if (end)
p->des01.erx.end_ring = 1;
}
static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
{
if (end)
p->des01.etx.end_ring = 1;
}
static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
{
p->des01.etx.end_ring = ter;
}
static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_4KiB)) {
p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
} else
p->des01.etx.buffer1_size = len;
}
static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
{
p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
if (end)
p->des01.rx.end_ring = 1;
}
static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
{
if (end)
p->des01.tx.end_ring = 1;
}
static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
{
p->des01.tx.end_ring = ter;
}
static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_2KiB)) {
p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
} else
p->des01.tx.buffer1_size = len;
}
#else
static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
{
p->des01.erx.second_address_chained = 1;
}
static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
{
p->des01.etx.second_address_chained = 1;
}
static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
{
p->des01.etx.second_address_chained = 1;
}
static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
{
p->des01.etx.buffer1_size = len;
}
static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
{
p->des01.rx.second_address_chained = 1;
}
static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
{
p->des01.tx.second_address_chained = 1;
}
static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
{
p->des01.tx.second_address_chained = 1;
}
static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
{
p->des01.tx.buffer1_size = len;
}
#endif

View File

@ -36,6 +36,7 @@
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
enum dwmac1000_irq_status {
lpiis_irq = 0x400,
time_stamp_irq = 0x0200,
mmc_rx_csum_offload_irq = 0x0080,
mmc_tx_irq = 0x0040,
@ -60,6 +61,25 @@ enum power_event {
power_down = 0x00000001,
};
/* Energy Efficient Ethernet (EEE)
*
* LPI status, timer and control register offset
*/
#define LPI_CTRL_STATUS 0x0030
#define LPI_TIMER_CTRL 0x0034
/* LPI control and status defines */
#define LPI_CTRL_STATUS_LPITXA 0x00080000 /* Enable LPI TX Automate */
#define LPI_CTRL_STATUS_PLSEN 0x00040000 /* Enable PHY Link Status */
#define LPI_CTRL_STATUS_PLS 0x00020000 /* PHY Link Status */
#define LPI_CTRL_STATUS_LPIEN 0x00010000 /* LPI Enable */
#define LPI_CTRL_STATUS_RLPIST 0x00000200 /* Receive LPI state */
#define LPI_CTRL_STATUS_TLPIST 0x00000100 /* Transmit LPI state */
#define LPI_CTRL_STATUS_RLPIEX 0x00000008 /* Receive LPI Exit */
#define LPI_CTRL_STATUS_RLPIEN 0x00000004 /* Receive LPI Entry */
#define LPI_CTRL_STATUS_TLPIEX 0x00000002 /* Transmit LPI Exit */
#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
/* GMAC HW ADDR regs */
#define GMAC_ADDR_HIGH(reg) (0x00000040+(reg * 8))
#define GMAC_ADDR_LOW(reg) (0x00000044+(reg * 8))
@ -99,7 +119,7 @@ enum inter_frame_gap {
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
GMAC_CONTROL_JE | GMAC_CONTROL_BE)
GMAC_CONTROL_JE | GMAC_CONTROL_BE | GMAC_CONTROL_DCRS)
/* GMAC Frame Filter defines */
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */

View File

@ -35,11 +35,6 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
value |= GMAC_CORE_INIT;
writel(value, ioaddr + GMAC_CONTROL);
/* STBus Bridge Configuration */
/*writel(0xc5608, ioaddr + 0x00007000);*/
/* Freeze MMC counters */
writel(0x8, ioaddr + GMAC_MMC_CTRL);
/* Mask GMAC interrupts */
writel(0x207, ioaddr + GMAC_INT_MASK);
@ -191,27 +186,98 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
writel(pmt, ioaddr + GMAC_PMT);
}
static void dwmac1000_irq_status(void __iomem *ioaddr)
static int dwmac1000_irq_status(void __iomem *ioaddr)
{
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
int status = 0;
/* Not used events (e.g. MMC interrupts) are not handled. */
if ((intr_status & mmc_tx_irq))
CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
if ((intr_status & mmc_tx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
readl(ioaddr + GMAC_MMC_TX_INTR));
if (unlikely(intr_status & mmc_rx_irq))
CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
status |= core_mmc_tx_irq;
}
if (unlikely(intr_status & mmc_rx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
readl(ioaddr + GMAC_MMC_RX_INTR));
if (unlikely(intr_status & mmc_rx_csum_offload_irq))
CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
status |= core_mmc_rx_irq;
}
if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
status |= core_mmc_rx_csum_offload_irq;
}
if (unlikely(intr_status & pmt_irq)) {
CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n");
CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
/* clear the PMT bits 5 and 6 by reading the PMT
* status register. */
readl(ioaddr + GMAC_PMT);
status |= core_irq_receive_pmt_irq;
}
/* MAC trx/rx EEE LPI entry/exit interrupts */
if (intr_status & lpiis_irq) {
/* Clean LPI interrupt by reading the Reg 12 */
u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
status |= core_irq_tx_path_in_lpi_mode;
}
if (lpi_status & LPI_CTRL_STATUS_TLPIEX) {
CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
status |= core_irq_tx_path_exit_lpi_mode;
}
if (lpi_status & LPI_CTRL_STATUS_RLPIEN) {
CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
status |= core_irq_rx_path_in_lpi_mode;
}
if (lpi_status & LPI_CTRL_STATUS_RLPIEX) {
CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
status |= core_irq_rx_path_exit_lpi_mode;
}
}
return status;
}
static void dwmac1000_set_eee_mode(void __iomem *ioaddr, u32 lpi_ctl_status)
{
/* Enable the link status receive on RGMII, SGMII ore SMII
* receive path and instruct the transmit to enter in LPI
* state. */
lpi_ctl_status |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
writel(lpi_ctl_status, ioaddr + LPI_CTRL_STATUS);
}
static void dwmac1000_reset_eee_mode(void __iomem *ioaddr, u32 lpi_ctl_status)
{
lpi_ctl_status &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
writel(lpi_ctl_status, ioaddr + LPI_CTRL_STATUS);
}
static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link,
u32 lpi_ctl_status)
{
if (link)
lpi_ctl_status |= LPI_CTRL_STATUS_PLS;
else
lpi_ctl_status &= ~LPI_CTRL_STATUS_PLS;
writel(lpi_ctl_status, ioaddr + LPI_CTRL_STATUS);
}
static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
{
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
/* Program the timers in the LPI timer control register:
* LS: minimum time (ms) for which the link
* status from PHY should be ok before transmitting
* the LPI pattern.
* TW: minimum time (us) for which the core waits
* after it has stopped transmitting the LPI pattern.
*/
writel(value, ioaddr + LPI_TIMER_CTRL);
}
static const struct stmmac_ops dwmac1000_ops = {
@ -224,15 +290,16 @@ static const struct stmmac_ops dwmac1000_ops = {
.pmt = dwmac1000_pmt,
.set_umac_addr = dwmac1000_set_umac_addr,
.get_umac_addr = dwmac1000_get_umac_addr,
.set_eee_mode = dwmac1000_set_eee_mode,
.reset_eee_mode = dwmac1000_reset_eee_mode,
.set_eee_timer = dwmac1000_set_eee_timer,
.set_eee_pls = dwmac1000_set_eee_pls,
};
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
{
struct mac_device_info *mac;
u32 uid = readl(ioaddr + GMAC_VERSION);
pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
u32 hwid = readl(ioaddr + GMAC_VERSION);
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
if (!mac)
@ -246,6 +313,7 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
mac->link.speed = GMAC_CONTROL_FES;
mac->mii.addr = GMAC_MII_ADDR;
mac->mii.data = GMAC_MII_DATA;
mac->synopsys_uid = hwid;
return mac;
}

View File

@ -118,13 +118,6 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
writel(csr6, ioaddr + DMA_CONTROL);
}
/* Not yet implemented --- no RMON module */
static void dwmac1000_dma_diagnostic_fr(void *data,
struct stmmac_extra_stats *x, void __iomem *ioaddr)
{
return;
}
static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
{
int i;
@ -139,11 +132,15 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
}
}
static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
{
return readl(ioaddr + DMA_HW_FEATURE);
}
const struct stmmac_dma_ops dwmac1000_dma_ops = {
.init = dwmac1000_dma_init,
.dump_regs = dwmac1000_dump_dma_regs,
.dma_mode = dwmac1000_dma_operation_mode,
.dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
.enable_dma_transmission = dwmac_enable_dma_transmission,
.enable_dma_irq = dwmac_enable_dma_irq,
.disable_dma_irq = dwmac_disable_dma_irq,
@ -152,4 +149,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
.start_rx = dwmac_dma_start_rx,
.stop_rx = dwmac_dma_stop_rx,
.dma_interrupt = dwmac_dma_interrupt,
.get_hw_feature = dwmac1000_get_hw_feature,
};

View File

@ -69,22 +69,11 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
readl(ioaddr + MAC_VLAN1));
pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
readl(ioaddr + MAC_VLAN2));
pr_info("\n\tMAC management counter registers\n");
pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
}
static void dwmac100_irq_status(void __iomem *ioaddr)
static int dwmac100_irq_status(void __iomem *ioaddr)
{
return;
return 0;
}
static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
@ -200,6 +189,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
mac->link.speed = 0;
mac->mii.addr = MAC_MII_ADDR;
mac->mii.data = MAC_MII_DATA;
mac->synopsys_uid = 0;
return mac;
}

View File

@ -40,10 +40,11 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
/* DMA SW reset */
value |= DMA_BUS_MODE_SFT_RESET;
writel(value, ioaddr + DMA_BUS_MODE);
limit = 15000;
limit = 10;
while (limit--) {
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
break;
mdelay(10);
}
if (limit < 0)
return -EBUSY;

View File

@ -34,6 +34,7 @@
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
/* DMA Control register defines */
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
@ -68,6 +69,7 @@
#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
/* DMA Status register defines */
#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */

View File

@ -238,6 +238,19 @@ void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
writel(data, ioaddr + low);
}
/* Enable disable MAC RX/TX */
void stmmac_set_mac(void __iomem *ioaddr, bool enable)
{
u32 value = readl(ioaddr + MAC_CTRL_REG);
if (enable)
value |= MAC_RNABLE_RX | MAC_ENABLE_TX;
else
value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX);
writel(value, ioaddr + MAC_CTRL_REG);
}
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
unsigned int high, unsigned int low)
{

View File

@ -23,6 +23,7 @@
*******************************************************************************/
#include "common.h"
#include "descs_com.h"
static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
@ -200,7 +201,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(p->des01.erx.dribbling)) {
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
ret = discard_frame;
x->dribbling_bit++;
}
if (unlikely(p->des01.erx.sa_filter_fail)) {
CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
@ -233,10 +234,9 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
for (i = 0; i < ring_size; i++) {
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
/* To support jumbo frames */
p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
if (i == ring_size - 1)
p->des01.erx.end_ring = 1;
ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
if (disable_rx_ic)
p->des01.erx.disable_ic = 1;
p++;
@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
for (i = 0; i < ring_size; i++) {
p->des01.etx.own = 0;
if (i == ring_size - 1)
p->des01.etx.end_ring = 1;
ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
p++;
}
}
@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
int ter = p->des01.etx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
p->des01.etx.end_ring = ter;
enh_desc_end_tx_desc(p, ter);
}
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.etx.first_segment = is_fs;
if (unlikely(len > BUF_SIZE_4KiB)) {
p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
} else {
p->des01.etx.buffer1_size = len;
}
enh_set_tx_desc_len(p, len);
if (likely(csum_flag))
p->des01.etx.checksum_insertion = cic_full;
}

View File

@ -0,0 +1,131 @@
/*******************************************************************************
MMC Header file
Copyright (C) 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>
*******************************************************************************/
/* MMC control register */
/* When set, all counter are reset */
#define MMC_CNTRL_COUNTER_RESET 0x1
/* When set, do not roll over zero
* after reaching the max value*/
#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
* current value.*/
#define MMC_CNTRL_PRESET 0x10
#define MMC_CNTRL_FULL_HALF_PRESET 0x20
struct stmmac_counters {
unsigned int mmc_tx_octetcount_gb;
unsigned int mmc_tx_framecount_gb;
unsigned int mmc_tx_broadcastframe_g;
unsigned int mmc_tx_multicastframe_g;
unsigned int mmc_tx_64_octets_gb;
unsigned int mmc_tx_65_to_127_octets_gb;
unsigned int mmc_tx_128_to_255_octets_gb;
unsigned int mmc_tx_256_to_511_octets_gb;
unsigned int mmc_tx_512_to_1023_octets_gb;
unsigned int mmc_tx_1024_to_max_octets_gb;
unsigned int mmc_tx_unicast_gb;
unsigned int mmc_tx_multicast_gb;
unsigned int mmc_tx_broadcast_gb;
unsigned int mmc_tx_underflow_error;
unsigned int mmc_tx_singlecol_g;
unsigned int mmc_tx_multicol_g;
unsigned int mmc_tx_deferred;
unsigned int mmc_tx_latecol;
unsigned int mmc_tx_exesscol;
unsigned int mmc_tx_carrier_error;
unsigned int mmc_tx_octetcount_g;
unsigned int mmc_tx_framecount_g;
unsigned int mmc_tx_excessdef;
unsigned int mmc_tx_pause_frame;
unsigned int mmc_tx_vlan_frame_g;
/* MMC RX counter registers */
unsigned int mmc_rx_framecount_gb;
unsigned int mmc_rx_octetcount_gb;
unsigned int mmc_rx_octetcount_g;
unsigned int mmc_rx_broadcastframe_g;
unsigned int mmc_rx_multicastframe_g;
unsigned int mmc_rx_crc_errror;
unsigned int mmc_rx_align_error;
unsigned int mmc_rx_run_error;
unsigned int mmc_rx_jabber_error;
unsigned int mmc_rx_undersize_g;
unsigned int mmc_rx_oversize_g;
unsigned int mmc_rx_64_octets_gb;
unsigned int mmc_rx_65_to_127_octets_gb;
unsigned int mmc_rx_128_to_255_octets_gb;
unsigned int mmc_rx_256_to_511_octets_gb;
unsigned int mmc_rx_512_to_1023_octets_gb;
unsigned int mmc_rx_1024_to_max_octets_gb;
unsigned int mmc_rx_unicast_g;
unsigned int mmc_rx_length_error;
unsigned int mmc_rx_autofrangetype;
unsigned int mmc_rx_pause_frames;
unsigned int mmc_rx_fifo_overflow;
unsigned int mmc_rx_vlan_frames_gb;
unsigned int mmc_rx_watchdog_error;
/* IPC */
unsigned int mmc_rx_ipc_intr_mask;
unsigned int mmc_rx_ipc_intr;
/* IPv4 */
unsigned int mmc_rx_ipv4_gd;
unsigned int mmc_rx_ipv4_hderr;
unsigned int mmc_rx_ipv4_nopay;
unsigned int mmc_rx_ipv4_frag;
unsigned int mmc_rx_ipv4_udsbl;
unsigned int mmc_rx_ipv4_gd_octets;
unsigned int mmc_rx_ipv4_hderr_octets;
unsigned int mmc_rx_ipv4_nopay_octets;
unsigned int mmc_rx_ipv4_frag_octets;
unsigned int mmc_rx_ipv4_udsbl_octets;
/* IPV6 */
unsigned int mmc_rx_ipv6_gd_octets;
unsigned int mmc_rx_ipv6_hderr_octets;
unsigned int mmc_rx_ipv6_nopay_octets;
unsigned int mmc_rx_ipv6_gd;
unsigned int mmc_rx_ipv6_hderr;
unsigned int mmc_rx_ipv6_nopay;
/* Protocols */
unsigned int mmc_rx_udp_gd;
unsigned int mmc_rx_udp_err;
unsigned int mmc_rx_tcp_gd;
unsigned int mmc_rx_tcp_err;
unsigned int mmc_rx_icmp_gd;
unsigned int mmc_rx_icmp_err;
unsigned int mmc_rx_udp_gd_octets;
unsigned int mmc_rx_udp_err_octets;
unsigned int mmc_rx_tcp_gd_octets;
unsigned int mmc_rx_tcp_err_octets;
unsigned int mmc_rx_icmp_gd_octets;
unsigned int mmc_rx_icmp_err_octets;
};
extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);

View File

@ -0,0 +1,266 @@
/*******************************************************************************
DWMAC Management Counters
Copyright (C) 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>
*******************************************************************************/
#include <linux/kernel.h>
#include <linux/io.h>
#include "mmc.h"
/* MAC Management Counters register offset */
#define MMC_CNTRL 0x00000100 /* MMC Control */
#define MMC_RX_INTR 0x00000104 /* MMC RX Interrupt */
#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
#define MMC_DEFAUL_MASK 0xffffffff
/* MMC TX counter registers */
/* Note:
* _GB register stands for good and bad frames
* _G is for good only.
*/
#define MMC_TX_OCTETCOUNT_GB 0x00000114
#define MMC_TX_FRAMECOUNT_GB 0x00000118
#define MMC_TX_BROADCASTFRAME_G 0x0000011c
#define MMC_TX_MULTICASTFRAME_G 0x00000120
#define MMC_TX_64_OCTETS_GB 0x00000124
#define MMC_TX_65_TO_127_OCTETS_GB 0x00000128
#define MMC_TX_128_TO_255_OCTETS_GB 0x0000012c
#define MMC_TX_256_TO_511_OCTETS_GB 0x00000130
#define MMC_TX_512_TO_1023_OCTETS_GB 0x00000134
#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x00000138
#define MMC_TX_UNICAST_GB 0x0000013c
#define MMC_TX_MULTICAST_GB 0x00000140
#define MMC_TX_BROADCAST_GB 0x00000144
#define MMC_TX_UNDERFLOW_ERROR 0x00000148
#define MMC_TX_SINGLECOL_G 0x0000014c
#define MMC_TX_MULTICOL_G 0x00000150
#define MMC_TX_DEFERRED 0x00000154
#define MMC_TX_LATECOL 0x00000158
#define MMC_TX_EXESSCOL 0x0000015c
#define MMC_TX_CARRIER_ERROR 0x00000160
#define MMC_TX_OCTETCOUNT_G 0x00000164
#define MMC_TX_FRAMECOUNT_G 0x00000168
#define MMC_TX_EXCESSDEF 0x0000016c
#define MMC_TX_PAUSE_FRAME 0x00000170
#define MMC_TX_VLAN_FRAME_G 0x00000174
/* MMC RX counter registers */
#define MMC_RX_FRAMECOUNT_GB 0x00000180
#define MMC_RX_OCTETCOUNT_GB 0x00000184
#define MMC_RX_OCTETCOUNT_G 0x00000188
#define MMC_RX_BROADCASTFRAME_G 0x0000018c
#define MMC_RX_MULTICASTFRAME_G 0x00000190
#define MMC_RX_CRC_ERRROR 0x00000194
#define MMC_RX_ALIGN_ERROR 0x00000198
#define MMC_RX_RUN_ERROR 0x0000019C
#define MMC_RX_JABBER_ERROR 0x000001A0
#define MMC_RX_UNDERSIZE_G 0x000001A4
#define MMC_RX_OVERSIZE_G 0x000001A8
#define MMC_RX_64_OCTETS_GB 0x000001AC
#define MMC_RX_65_TO_127_OCTETS_GB 0x000001b0
#define MMC_RX_128_TO_255_OCTETS_GB 0x000001b4
#define MMC_RX_256_TO_511_OCTETS_GB 0x000001b8
#define MMC_RX_512_TO_1023_OCTETS_GB 0x000001bc
#define MMC_RX_1024_TO_MAX_OCTETS_GB 0x000001c0
#define MMC_RX_UNICAST_G 0x000001c4
#define MMC_RX_LENGTH_ERROR 0x000001c8
#define MMC_RX_AUTOFRANGETYPE 0x000001cc
#define MMC_RX_PAUSE_FRAMES 0x000001d0
#define MMC_RX_FIFO_OVERFLOW 0x000001d4
#define MMC_RX_VLAN_FRAMES_GB 0x000001d8
#define MMC_RX_WATCHDOG_ERROR 0x000001dc
/* IPC*/
#define MMC_RX_IPC_INTR_MASK 0x00000200
#define MMC_RX_IPC_INTR 0x00000208
/* IPv4*/
#define MMC_RX_IPV4_GD 0x00000210
#define MMC_RX_IPV4_HDERR 0x00000214
#define MMC_RX_IPV4_NOPAY 0x00000218
#define MMC_RX_IPV4_FRAG 0x0000021C
#define MMC_RX_IPV4_UDSBL 0x00000220
#define MMC_RX_IPV4_GD_OCTETS 0x00000250
#define MMC_RX_IPV4_HDERR_OCTETS 0x00000254
#define MMC_RX_IPV4_NOPAY_OCTETS 0x00000258
#define MMC_RX_IPV4_FRAG_OCTETS 0x0000025c
#define MMC_RX_IPV4_UDSBL_OCTETS 0x00000260
/* IPV6*/
#define MMC_RX_IPV6_GD_OCTETS 0x00000264
#define MMC_RX_IPV6_HDERR_OCTETS 0x00000268
#define MMC_RX_IPV6_NOPAY_OCTETS 0x0000026c
#define MMC_RX_IPV6_GD 0x00000224
#define MMC_RX_IPV6_HDERR 0x00000228
#define MMC_RX_IPV6_NOPAY 0x0000022c
/* Protocols*/
#define MMC_RX_UDP_GD 0x00000230
#define MMC_RX_UDP_ERR 0x00000234
#define MMC_RX_TCP_GD 0x00000238
#define MMC_RX_TCP_ERR 0x0000023c
#define MMC_RX_ICMP_GD 0x00000240
#define MMC_RX_ICMP_ERR 0x00000244
#define MMC_RX_UDP_GD_OCTETS 0x00000270
#define MMC_RX_UDP_ERR_OCTETS 0x00000274
#define MMC_RX_TCP_GD_OCTETS 0x00000278
#define MMC_RX_TCP_ERR_OCTETS 0x0000027c
#define MMC_RX_ICMP_GD_OCTETS 0x00000280
#define MMC_RX_ICMP_ERR_OCTETS 0x00000284
void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode)
{
u32 value = readl(ioaddr + MMC_CNTRL);
value |= (mode & 0x3F);
writel(value, ioaddr + MMC_CNTRL);
pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n",
MMC_CNTRL, value);
}
/* To mask all all interrupts.*/
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
{
writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK);
writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK);
}
/* This reads the MAC core counters (if actaully supported).
* by default the MMC core is programmed to reset each
* counter after a read. So all the field of the mmc struct
* have to be incremented.
*/
void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc)
{
mmc->mmc_tx_octetcount_gb += readl(ioaddr + MMC_TX_OCTETCOUNT_GB);
mmc->mmc_tx_framecount_gb += readl(ioaddr + MMC_TX_FRAMECOUNT_GB);
mmc->mmc_tx_broadcastframe_g += readl(ioaddr + MMC_TX_BROADCASTFRAME_G);
mmc->mmc_tx_multicastframe_g += readl(ioaddr + MMC_TX_MULTICASTFRAME_G);
mmc->mmc_tx_64_octets_gb += readl(ioaddr + MMC_TX_64_OCTETS_GB);
mmc->mmc_tx_65_to_127_octets_gb +=
readl(ioaddr + MMC_TX_65_TO_127_OCTETS_GB);
mmc->mmc_tx_128_to_255_octets_gb +=
readl(ioaddr + MMC_TX_128_TO_255_OCTETS_GB);
mmc->mmc_tx_256_to_511_octets_gb +=
readl(ioaddr + MMC_TX_256_TO_511_OCTETS_GB);
mmc->mmc_tx_512_to_1023_octets_gb +=
readl(ioaddr + MMC_TX_512_TO_1023_OCTETS_GB);
mmc->mmc_tx_1024_to_max_octets_gb +=
readl(ioaddr + MMC_TX_1024_TO_MAX_OCTETS_GB);
mmc->mmc_tx_unicast_gb += readl(ioaddr + MMC_TX_UNICAST_GB);
mmc->mmc_tx_multicast_gb += readl(ioaddr + MMC_TX_MULTICAST_GB);
mmc->mmc_tx_broadcast_gb += readl(ioaddr + MMC_TX_BROADCAST_GB);
mmc->mmc_tx_underflow_error += readl(ioaddr + MMC_TX_UNDERFLOW_ERROR);
mmc->mmc_tx_singlecol_g += readl(ioaddr + MMC_TX_SINGLECOL_G);
mmc->mmc_tx_multicol_g += readl(ioaddr + MMC_TX_MULTICOL_G);
mmc->mmc_tx_deferred += readl(ioaddr + MMC_TX_DEFERRED);
mmc->mmc_tx_latecol += readl(ioaddr + MMC_TX_LATECOL);
mmc->mmc_tx_exesscol += readl(ioaddr + MMC_TX_EXESSCOL);
mmc->mmc_tx_carrier_error += readl(ioaddr + MMC_TX_CARRIER_ERROR);
mmc->mmc_tx_octetcount_g += readl(ioaddr + MMC_TX_OCTETCOUNT_G);
mmc->mmc_tx_framecount_g += readl(ioaddr + MMC_TX_FRAMECOUNT_G);
mmc->mmc_tx_excessdef += readl(ioaddr + MMC_TX_EXCESSDEF);
mmc->mmc_tx_pause_frame += readl(ioaddr + MMC_TX_PAUSE_FRAME);
mmc->mmc_tx_vlan_frame_g += readl(ioaddr + MMC_TX_VLAN_FRAME_G);
/* MMC RX counter registers */
mmc->mmc_rx_framecount_gb += readl(ioaddr + MMC_RX_FRAMECOUNT_GB);
mmc->mmc_rx_octetcount_gb += readl(ioaddr + MMC_RX_OCTETCOUNT_GB);
mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
mmc->mmc_rx_crc_errror += readl(ioaddr + MMC_RX_CRC_ERRROR);
mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
mmc->mmc_rx_undersize_g += readl(ioaddr + MMC_RX_UNDERSIZE_G);
mmc->mmc_rx_oversize_g += readl(ioaddr + MMC_RX_OVERSIZE_G);
mmc->mmc_rx_64_octets_gb += readl(ioaddr + MMC_RX_64_OCTETS_GB);
mmc->mmc_rx_65_to_127_octets_gb +=
readl(ioaddr + MMC_RX_65_TO_127_OCTETS_GB);
mmc->mmc_rx_128_to_255_octets_gb +=
readl(ioaddr + MMC_RX_128_TO_255_OCTETS_GB);
mmc->mmc_rx_256_to_511_octets_gb +=
readl(ioaddr + MMC_RX_256_TO_511_OCTETS_GB);
mmc->mmc_rx_512_to_1023_octets_gb +=
readl(ioaddr + MMC_RX_512_TO_1023_OCTETS_GB);
mmc->mmc_rx_1024_to_max_octets_gb +=
readl(ioaddr + MMC_RX_1024_TO_MAX_OCTETS_GB);
mmc->mmc_rx_unicast_g += readl(ioaddr + MMC_RX_UNICAST_G);
mmc->mmc_rx_length_error += readl(ioaddr + MMC_RX_LENGTH_ERROR);
mmc->mmc_rx_autofrangetype += readl(ioaddr + MMC_RX_AUTOFRANGETYPE);
mmc->mmc_rx_pause_frames += readl(ioaddr + MMC_RX_PAUSE_FRAMES);
mmc->mmc_rx_fifo_overflow += readl(ioaddr + MMC_RX_FIFO_OVERFLOW);
mmc->mmc_rx_vlan_frames_gb += readl(ioaddr + MMC_RX_VLAN_FRAMES_GB);
mmc->mmc_rx_watchdog_error += readl(ioaddr + MMC_RX_WATCHDOG_ERROR);
/* IPC */
mmc->mmc_rx_ipc_intr_mask += readl(ioaddr + MMC_RX_IPC_INTR_MASK);
mmc->mmc_rx_ipc_intr += readl(ioaddr + MMC_RX_IPC_INTR);
/* IPv4 */
mmc->mmc_rx_ipv4_gd += readl(ioaddr + MMC_RX_IPV4_GD);
mmc->mmc_rx_ipv4_hderr += readl(ioaddr + MMC_RX_IPV4_HDERR);
mmc->mmc_rx_ipv4_nopay += readl(ioaddr + MMC_RX_IPV4_NOPAY);
mmc->mmc_rx_ipv4_frag += readl(ioaddr + MMC_RX_IPV4_FRAG);
mmc->mmc_rx_ipv4_udsbl += readl(ioaddr + MMC_RX_IPV4_UDSBL);
mmc->mmc_rx_ipv4_gd_octets += readl(ioaddr + MMC_RX_IPV4_GD_OCTETS);
mmc->mmc_rx_ipv4_hderr_octets +=
readl(ioaddr + MMC_RX_IPV4_HDERR_OCTETS);
mmc->mmc_rx_ipv4_nopay_octets +=
readl(ioaddr + MMC_RX_IPV4_NOPAY_OCTETS);
mmc->mmc_rx_ipv4_frag_octets += readl(ioaddr + MMC_RX_IPV4_FRAG_OCTETS);
mmc->mmc_rx_ipv4_udsbl_octets +=
readl(ioaddr + MMC_RX_IPV4_UDSBL_OCTETS);
/* IPV6 */
mmc->mmc_rx_ipv6_gd_octets += readl(ioaddr + MMC_RX_IPV6_GD_OCTETS);
mmc->mmc_rx_ipv6_hderr_octets +=
readl(ioaddr + MMC_RX_IPV6_HDERR_OCTETS);
mmc->mmc_rx_ipv6_nopay_octets +=
readl(ioaddr + MMC_RX_IPV6_NOPAY_OCTETS);
mmc->mmc_rx_ipv6_gd += readl(ioaddr + MMC_RX_IPV6_GD);
mmc->mmc_rx_ipv6_hderr += readl(ioaddr + MMC_RX_IPV6_HDERR);
mmc->mmc_rx_ipv6_nopay += readl(ioaddr + MMC_RX_IPV6_NOPAY);
/* Protocols */
mmc->mmc_rx_udp_gd += readl(ioaddr + MMC_RX_UDP_GD);
mmc->mmc_rx_udp_err += readl(ioaddr + MMC_RX_UDP_ERR);
mmc->mmc_rx_tcp_gd += readl(ioaddr + MMC_RX_TCP_GD);
mmc->mmc_rx_tcp_err += readl(ioaddr + MMC_RX_TCP_ERR);
mmc->mmc_rx_icmp_gd += readl(ioaddr + MMC_RX_ICMP_GD);
mmc->mmc_rx_icmp_err += readl(ioaddr + MMC_RX_ICMP_ERR);
mmc->mmc_rx_udp_gd_octets += readl(ioaddr + MMC_RX_UDP_GD_OCTETS);
mmc->mmc_rx_udp_err_octets += readl(ioaddr + MMC_RX_UDP_ERR_OCTETS);
mmc->mmc_rx_tcp_gd_octets += readl(ioaddr + MMC_RX_TCP_GD_OCTETS);
mmc->mmc_rx_tcp_err_octets += readl(ioaddr + MMC_RX_TCP_ERR_OCTETS);
mmc->mmc_rx_icmp_gd_octets += readl(ioaddr + MMC_RX_ICMP_GD_OCTETS);
mmc->mmc_rx_icmp_err_octets += readl(ioaddr + MMC_RX_ICMP_ERR_OCTETS);
}

View File

@ -23,6 +23,7 @@
*******************************************************************************/
#include "common.h"
#include "descs_com.h"
static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr)
@ -49,11 +50,12 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
stats->collisions += p->des01.tx.collision_count;
ret = -1;
}
if (unlikely(p->des01.tx.heartbeat_fail)) {
x->tx_heartbeat++;
stats->tx_heartbeat_errors++;
ret = -1;
if (p->des01.etx.vlan_frame) {
CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
x->tx_vlan++;
}
if (unlikely(p->des01.tx.deferred))
x->tx_deferred++;
@ -67,12 +69,12 @@ static int ndesc_get_tx_len(struct dma_desc *p)
/* This function verifies if each incoming frame has some errors
* and, if required, updates the multicast statistics.
* In case of success, it returns csum_none becasue the device
* is not able to compute the csum in HW. */
* In case of success, it returns good_frame because the GMAC device
* is supposed to be able to compute the csum in HW. */
static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
int ret = csum_none;
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(p->des01.rx.last_descriptor == 0)) {
@ -85,12 +87,12 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
if (unlikely(p->des01.rx.error_summary)) {
if (unlikely(p->des01.rx.descriptor_error))
x->rx_desc++;
if (unlikely(p->des01.rx.partial_frame_error))
x->rx_partial++;
if (unlikely(p->des01.rx.run_frame))
x->rx_runt++;
if (unlikely(p->des01.rx.frame_too_long))
x->rx_toolong++;
if (unlikely(p->des01.rx.sa_filter_fail))
x->sa_filter_fail++;
if (unlikely(p->des01.rx.overflow_error))
x->overflow_error++;
if (unlikely(p->des01.rx.ipc_csum_error))
x->ipc_csum_error++;
if (unlikely(p->des01.rx.collision)) {
x->rx_collision++;
stats->collisions++;
@ -102,7 +104,7 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
ret = discard_frame;
}
if (unlikely(p->des01.rx.dribbling))
ret = discard_frame;
x->dribbling_bit++;
if (unlikely(p->des01.rx.length_error)) {
x->rx_length++;
@ -112,10 +114,10 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->rx_mii++;
ret = discard_frame;
}
if (p->des01.rx.multicast_frame) {
x->rx_multicast++;
stats->multicast++;
}
#ifdef STMMAC_VLAN_TAG_USED
if (p->des01.rx.vlan_tag)
x->vlan_tag++;
#endif
return ret;
}
@ -126,8 +128,9 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
for (i = 0; i < ring_size; i++) {
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
if (i == ring_size - 1)
p->des01.rx.end_ring = 1;
ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
if (disable_rx_ic)
p->des01.rx.disable_ic = 1;
p++;
@ -139,8 +142,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
int i;
for (i = 0; i < ring_size; i++) {
p->des01.tx.own = 0;
if (i == ring_size - 1)
p->des01.tx.end_ring = 1;
ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
p++;
}
}
@ -175,15 +177,17 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
int ter = p->des01.tx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
/* set termination field */
p->des01.tx.end_ring = ter;
ndesc_end_tx_desc(p, ter);
}
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
int csum_flag)
{
p->des01.tx.first_segment = is_fs;
p->des01.tx.buffer1_size = len;
norm_set_tx_desc_len(p, len);
if (likely(csum_flag))
p->des01.tx.checksum_insertion = cic_full;
}
static void ndesc_clear_tx_ic(struct dma_desc *p)

View File

@ -0,0 +1,126 @@
/*******************************************************************************
Specialised functions for managing Ring mode
Copyright(C) 2011 STMicroelectronics Ltd
It defines all the functions used to handle the normal/enhanced
descriptors in case of the DMA is configured to work in chained or
in ring mode.
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>
*******************************************************************************/
#include "stmmac.h"
static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
struct stmmac_priv *priv = (struct stmmac_priv *) p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
struct dma_desc *desc = priv->dma_tx + entry;
unsigned int nopaged_len = skb_headlen(skb);
unsigned int bmax, len;
if (priv->plat->enh_desc)
bmax = BUF_SIZE_8KiB;
else
bmax = BUF_SIZE_2KiB;
len = nopaged_len - bmax;
if (nopaged_len > BUF_SIZE_8KiB) {
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
csum);
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
}
return entry;
}
static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
{
unsigned int ret = 0;
if (len >= BUF_SIZE_4KiB)
ret = 1;
return ret;
}
static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
{
/* Fill DES3 in case of RING mode */
if (bfsize >= BUF_SIZE_8KiB)
p->des3 = p->des2 + BUF_SIZE_8KiB;
}
/* In ring mode we need to fill the desc3 because it is used
* as buffer */
static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
{
if (unlikely(des3_as_data_buf))
p->des3 = p->des2 + BUF_SIZE_8KiB;
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size)
{
}
static void stmmac_clean_desc3(struct dma_desc *p)
{
if (unlikely(p->des3))
p->des3 = 0;
}
static int stmmac_set_16kib_bfsize(int mtu)
{
int ret = 0;
if (unlikely(mtu >= BUF_SIZE_8KiB))
ret = BUF_SIZE_16KiB;
return ret;
}
const struct stmmac_ring_mode_ops ring_mode_ops = {
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
.init_desc3 = stmmac_init_desc3,
.init_dma_chain = stmmac_init_dma_chain,
.clean_desc3 = stmmac_clean_desc3,
.set_16kib_bfsize = stmmac_set_16kib_bfsize,
};

View File

@ -20,9 +20,11 @@
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
#define DRV_MODULE_VERSION "Nov_2010"
#define STMMAC_RESOURCE_NAME "stmmaceth"
#define DRV_MODULE_VERSION "Feb_2012"
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/pm_runtime.h>
#include "common.h"
#ifdef CONFIG_STMMAC_TIMER
#include "stmmac_timer.h"
@ -70,8 +72,9 @@ struct stmmac_priv {
u32 msg_enable;
spinlock_t lock;
spinlock_t tx_lock;
int wolopts;
int wolenabled;
int wol_irq;
#ifdef CONFIG_STMMAC_TIMER
struct stmmac_timer *tm;
#endif
@ -79,10 +82,33 @@ struct stmmac_priv {
struct vlan_group *vlgrp;
#endif
struct plat_stmmacenet_data *plat;
struct stmmac_counters mmc;
struct dma_features dma_cap;
int hw_cap_support;
struct timer_list eee_ctrl_timer;
bool tx_path_in_lpi_mode;
bool eee_enabled;
int lpi_irq;
int phy_wol_plus;
u32 lpi_ctl_status;
};
extern int phyaddr;
extern int stmmac_mdio_unregister(struct net_device *ndev);
extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
int stmmac_resume(struct net_device *ndev);
int stmmac_suspend(struct net_device *ndev);
int stmmac_dvr_remove(struct net_device *ndev);
struct stmmac_priv *stmmac_dvr_probe(struct device *device,
struct plat_stmmacenet_data *plat_dat,
void __iomem *addr);
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);

View File

@ -45,23 +45,25 @@ struct stmmac_stats {
offsetof(struct stmmac_priv, xstats.m)}
static const struct stmmac_stats stmmac_gstrings_stats[] = {
/* Transmit errors */
STMMAC_STAT(tx_underflow),
STMMAC_STAT(tx_carrier),
STMMAC_STAT(tx_losscarrier),
STMMAC_STAT(tx_heartbeat),
STMMAC_STAT(vlan_tag),
STMMAC_STAT(tx_deferred),
STMMAC_STAT(tx_vlan),
STMMAC_STAT(rx_vlan),
STMMAC_STAT(tx_jabber),
STMMAC_STAT(tx_frame_flushed),
STMMAC_STAT(tx_payload_error),
STMMAC_STAT(tx_ip_header_error),
/* Receive errors */
STMMAC_STAT(rx_desc),
STMMAC_STAT(rx_partial),
STMMAC_STAT(rx_runt),
STMMAC_STAT(rx_toolong),
STMMAC_STAT(sa_filter_fail),
STMMAC_STAT(overflow_error),
STMMAC_STAT(ipc_csum_error),
STMMAC_STAT(rx_collision),
STMMAC_STAT(rx_crc),
STMMAC_STAT(dribbling_bit),
STMMAC_STAT(rx_length),
STMMAC_STAT(rx_mii),
STMMAC_STAT(rx_multicast),
@ -71,6 +73,8 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(sa_rx_filter_fail),
STMMAC_STAT(rx_missed_cntr),
STMMAC_STAT(rx_overflow_cntr),
STMMAC_STAT(rx_vlan),
/* Tx/Rx IRQ errors */
STMMAC_STAT(tx_undeflow_irq),
STMMAC_STAT(tx_process_stopped_irq),
STMMAC_STAT(tx_jabber_irq),
@ -80,28 +84,128 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(rx_watchdog_irq),
STMMAC_STAT(tx_early_irq),
STMMAC_STAT(fatal_bus_error_irq),
/* Extra info */
STMMAC_STAT(threshold),
STMMAC_STAT(tx_pkt_n),
STMMAC_STAT(rx_pkt_n),
STMMAC_STAT(poll_n),
STMMAC_STAT(sched_timer_n),
STMMAC_STAT(normal_irq_n),
STMMAC_STAT(normal_irq_n),
STMMAC_STAT(mmc_tx_irq_n),
STMMAC_STAT(mmc_rx_irq_n),
STMMAC_STAT(mmc_rx_csum_offload_irq_n),
STMMAC_STAT(irq_receive_pmt_irq_n),
STMMAC_STAT(irq_tx_path_in_lpi_mode_n),
STMMAC_STAT(irq_tx_path_exit_lpi_mode_n),
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
/* HW MAC Management counters (if supported) */
#define STMMAC_MMC_STAT(m) \
{ #m, FIELD_SIZEOF(struct stmmac_counters, m), \
offsetof(struct stmmac_priv, mmc.m)}
static const struct stmmac_stats stmmac_mmc[] = {
STMMAC_MMC_STAT(mmc_tx_octetcount_gb),
STMMAC_MMC_STAT(mmc_tx_framecount_gb),
STMMAC_MMC_STAT(mmc_tx_broadcastframe_g),
STMMAC_MMC_STAT(mmc_tx_multicastframe_g),
STMMAC_MMC_STAT(mmc_tx_64_octets_gb),
STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb),
STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb),
STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb),
STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb),
STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb),
STMMAC_MMC_STAT(mmc_tx_unicast_gb),
STMMAC_MMC_STAT(mmc_tx_multicast_gb),
STMMAC_MMC_STAT(mmc_tx_broadcast_gb),
STMMAC_MMC_STAT(mmc_tx_underflow_error),
STMMAC_MMC_STAT(mmc_tx_singlecol_g),
STMMAC_MMC_STAT(mmc_tx_multicol_g),
STMMAC_MMC_STAT(mmc_tx_deferred),
STMMAC_MMC_STAT(mmc_tx_latecol),
STMMAC_MMC_STAT(mmc_tx_exesscol),
STMMAC_MMC_STAT(mmc_tx_carrier_error),
STMMAC_MMC_STAT(mmc_tx_octetcount_g),
STMMAC_MMC_STAT(mmc_tx_framecount_g),
STMMAC_MMC_STAT(mmc_tx_excessdef),
STMMAC_MMC_STAT(mmc_tx_pause_frame),
STMMAC_MMC_STAT(mmc_tx_vlan_frame_g),
STMMAC_MMC_STAT(mmc_rx_framecount_gb),
STMMAC_MMC_STAT(mmc_rx_octetcount_gb),
STMMAC_MMC_STAT(mmc_rx_octetcount_g),
STMMAC_MMC_STAT(mmc_rx_broadcastframe_g),
STMMAC_MMC_STAT(mmc_rx_multicastframe_g),
STMMAC_MMC_STAT(mmc_rx_crc_errror),
STMMAC_MMC_STAT(mmc_rx_align_error),
STMMAC_MMC_STAT(mmc_rx_run_error),
STMMAC_MMC_STAT(mmc_rx_jabber_error),
STMMAC_MMC_STAT(mmc_rx_undersize_g),
STMMAC_MMC_STAT(mmc_rx_oversize_g),
STMMAC_MMC_STAT(mmc_rx_64_octets_gb),
STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb),
STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb),
STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb),
STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb),
STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb),
STMMAC_MMC_STAT(mmc_rx_unicast_g),
STMMAC_MMC_STAT(mmc_rx_length_error),
STMMAC_MMC_STAT(mmc_rx_autofrangetype),
STMMAC_MMC_STAT(mmc_rx_pause_frames),
STMMAC_MMC_STAT(mmc_rx_fifo_overflow),
STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb),
STMMAC_MMC_STAT(mmc_rx_watchdog_error),
STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask),
STMMAC_MMC_STAT(mmc_rx_ipc_intr),
STMMAC_MMC_STAT(mmc_rx_ipv4_gd),
STMMAC_MMC_STAT(mmc_rx_ipv4_hderr),
STMMAC_MMC_STAT(mmc_rx_ipv4_nopay),
STMMAC_MMC_STAT(mmc_rx_ipv4_frag),
STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl),
STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets),
STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets),
STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets),
STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets),
STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets),
STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets),
STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets),
STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets),
STMMAC_MMC_STAT(mmc_rx_ipv6_gd),
STMMAC_MMC_STAT(mmc_rx_ipv6_hderr),
STMMAC_MMC_STAT(mmc_rx_ipv6_nopay),
STMMAC_MMC_STAT(mmc_rx_udp_gd),
STMMAC_MMC_STAT(mmc_rx_udp_err),
STMMAC_MMC_STAT(mmc_rx_tcp_gd),
STMMAC_MMC_STAT(mmc_rx_tcp_err),
STMMAC_MMC_STAT(mmc_rx_icmp_gd),
STMMAC_MMC_STAT(mmc_rx_icmp_err),
STMMAC_MMC_STAT(mmc_rx_udp_gd_octets),
STMMAC_MMC_STAT(mmc_rx_udp_err_octets),
STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets),
STMMAC_MMC_STAT(mmc_rx_tcp_err_octets),
STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets),
STMMAC_MMC_STAT(mmc_rx_icmp_err_octets),
};
#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct stmmac_priv *priv = netdev_priv(dev);
if (!priv->plat->has_gmac)
strcpy(info->driver, MAC100_ETHTOOL_NAME);
info->n_stats = STMMAC_STATS_LEN;
if (priv->plat->has_gmac)
info->n_stats += STMMAC_MMC_STATS_LEN;
else
strcpy(info->driver, GMAC_ETHTOOL_NAME);
strcpy(info->driver, MAC100_ETHTOOL_NAME);
strcpy(info->version, DRV_MODULE_VERSION);
info->fw_version[0] = '\0';
info->n_stats = STMMAC_STATS_LEN;
}
static int stmmac_ethtool_getsettings(struct net_device *dev,
@ -197,16 +301,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
}
}
static int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
{
if (data)
netdev->features |= NETIF_F_HW_CSUM;
else
netdev->features &= ~NETIF_F_HW_CSUM;
return 0;
}
static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
@ -267,24 +361,53 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *dummy, u64 *data)
{
struct stmmac_priv *priv = netdev_priv(dev);
int i;
int i, j = 0;
/* Update HW stats if supported */
priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
/* Update the DMA HW counters for dwmac10/100 */
if (!priv->plat->has_gmac)
priv->hw->dma->dma_diagnostic_fr(&dev->stats,
(void *) &priv->xstats,
priv->ioaddr);
else {
/* If supported, for new GMAC chips expose the MMC counters */
if (priv->dma_cap.rmon) {
dwmac_mmc_read(priv->ioaddr, &priv->mmc);
for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
char *p;
p = (char *)priv + stmmac_mmc[i].stat_offset;
data[j++] = (stmmac_mmc[i].sizeof_stat ==
sizeof(u64)) ? (*(u64 *)p) :
(*(u32 *)p);
}
}
if (priv->eee_enabled) {
int val = phy_get_eee_err(priv->phydev);
if (val)
priv->xstats.phy_eee_wakeup_error_n = val;
}
}
for (i = 0; i < STMMAC_STATS_LEN; i++) {
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
data[i] = (stmmac_gstrings_stats[i].sizeof_stat ==
data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
}
}
static int stmmac_get_sset_count(struct net_device *netdev, int sset)
{
struct stmmac_priv *priv = netdev_priv(netdev);
int len;
switch (sset) {
case ETH_SS_STATS:
return STMMAC_STATS_LEN;
len = STMMAC_STATS_LEN;
if (priv->dma_cap.rmon)
len += STMMAC_MMC_STATS_LEN;
return len;
default:
return -EOPNOTSUPP;
}
@ -294,9 +417,16 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
u8 *p = data;
struct stmmac_priv *priv = netdev_priv(dev);
switch (stringset) {
case ETH_SS_STATS:
if (priv->dma_cap.rmon)
for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
memcpy(p, stmmac_mmc[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < STMMAC_STATS_LEN; i++) {
memcpy(p, stmmac_gstrings_stats[i].stat_string,
ETH_GSTRING_LEN);
@ -319,6 +449,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
wol->supported = WAKE_MAGIC | WAKE_UCAST;
wol->wolopts = priv->wolopts;
}
/* FIXME: get WoL from PHY that supports Wol+ */
spin_unlock_irq(&priv->lock);
}
@ -327,6 +458,24 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct stmmac_priv *priv = netdev_priv(dev);
u32 support = WAKE_MAGIC | WAKE_UCAST;
if (priv->phy_wol_plus & wol->wolopts) {
int ret;
pr_info("stmmac: use Phy WoL+\n");
spin_lock_irq(&priv->lock);
ret = phy_ethtool_set_wol(priv->phydev, wol);
spin_unlock_irq(&priv->lock);
return ret;
}
/* By default almost all GMAC devices support the WoL via
* magic frame but we can disable it if the HW capability
* register shows no support for pmt_magic_frame. */
if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
wol->wolopts &= ~WAKE_MAGIC;
if (!device_can_wakeup(priv->device))
return -EINVAL;
@ -336,10 +485,10 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts) {
pr_info("stmmac: wakeup enable\n");
device_set_wakeup_enable(priv->device, 1);
enable_irq_wake(dev->irq);
enable_irq_wake(priv->wol_irq);
} else {
device_set_wakeup_enable(priv->device, 0);
disable_irq_wake(dev->irq);
disable_irq_wake(priv->wol_irq);
}
spin_lock_irq(&priv->lock);
@ -349,6 +498,50 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
static int ethtool_op_get_eee(struct net_device *dev, struct ethtool_value *eee)
{
struct stmmac_priv *priv = netdev_priv(dev);
if (!priv->dma_cap.eee)
return -EOPNOTSUPP;
eee->data = priv->eee_enabled;
return 0;
}
static int ethtool_op_set_eee(struct net_device *dev, struct ethtool_value *eee)
{
struct stmmac_priv *priv = netdev_priv(dev);
if ((!eee->data) && (priv->eee_enabled)) {
stmmac_disable_eee_mode(priv);
priv->eee_enabled = eee->data;
} else if ((eee->data) && (!priv->eee_enabled))
/* We are asking for enabling the EEE but this
* has to be verified by invoking the eee_init function.
* For this reason we cannot set eee_enabled to
* eee->data, directly. */
priv->eee_enabled = stmmac_eee_init(priv);
return 0;
}
static int stmmac_ethtool_begin(struct net_device *netdev)
{
struct stmmac_priv *priv = netdev_priv(netdev);
pm_runtime_get_sync(priv->device);
return 0;
}
static void stmmac_ethtool_complete(struct net_device *netdev)
{
struct stmmac_priv *priv = netdev_priv(netdev);
pm_runtime_put(priv->device);
}
static struct ethtool_ops stmmac_ethtool_ops = {
.begin = stmmac_check_if_running,
.get_drvinfo = stmmac_ethtool_getdrvinfo,
@ -361,7 +554,7 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_rx_csum = stmmac_ethtool_get_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = stmmac_ethtool_set_tx_csum,
.set_tx_csum = ethtool_op_set_tx_ipv6_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_pauseparam = stmmac_get_pauseparam,
@ -373,6 +566,10 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_sset_count = stmmac_get_sset_count,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_eee = ethtool_op_get_eee,
.set_eee = ethtool_op_set_eee,
.begin = stmmac_ethtool_begin,
.complete = stmmac_ethtool_complete,
};
void stmmac_set_ethtool_ops(struct net_device *netdev)

File diff suppressed because it is too large Load Diff

View File

@ -107,6 +107,7 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
*/
static int stmmac_mdio_reset(struct mii_bus *bus)
{
#if defined(CONFIG_STMMAC_PLATFORM)
struct net_device *ndev = bus->priv;
struct stmmac_priv *priv = netdev_priv(ndev);
unsigned int mii_address = priv->hw->mii.addr;
@ -121,7 +122,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
* on MDC, so perform a dummy mdio read.
*/
writel(0, priv->ioaddr + mii_address);
#endif
return 0;
}
@ -183,7 +184,9 @@ int stmmac_mdio_register(struct net_device *ndev)
if ((mdio_bus_data->irqs == NULL) &&
(mdio_bus_data->probed_phy_irq > 0)) {
irqlist[addr] = mdio_bus_data->probed_phy_irq;
phydev->irq = mdio_bus_data->probed_phy_irq;
if (!phydev->drv ||
(phydev->drv->flags & PHY_HAS_INTERRUPT))
phydev->irq = irqlist[addr];
}
/*
@ -217,8 +220,15 @@ int stmmac_mdio_register(struct net_device *ndev)
}
}
if (!found)
if (!found) {
pr_warning("%s: No PHY found\n", ndev->name);
/* Un-register the Bus and report an error */
mdiobus_unregister(new_bus);
priv->mii->priv = NULL;
mdiobus_free(new_bus);
priv->mii = NULL;
return -ENODEV;
}
return 0;

View File

@ -0,0 +1,219 @@
/*******************************************************************************
This contains the functions to handle the pci driver.
Copyright (C) 2011-2012 Vayavya Labs Pvt 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: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
*******************************************************************************/
#include <linux/pci.h>
#include "stmmac.h"
struct plat_stmmacenet_data plat_dat;
struct stmmac_mdio_bus_data mdio_data;
static void stmmac_default_data(void)
{
memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data));
plat_dat.bus_id = 1;
plat_dat.phy_addr = 0;
plat_dat.interface = PHY_INTERFACE_MODE_GMII;
plat_dat.pbl = 32;
plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
plat_dat.has_gmac = 1;
plat_dat.force_sf_dma_mode = 1;
mdio_data.bus_id = 1;
mdio_data.phy_reset = NULL;
mdio_data.phy_mask = 0;
plat_dat.mdio_bus_data = &mdio_data;
}
/**
* stmmac_pci_probe
*
* @pdev: pci device pointer
* @id: pointer to table of device id/id's.
*
* Description: This probing function gets called for all PCI devices which
* match the ID table and are not "owned" by other driver yet. This function
* gets passed a "struct pci_dev *" for each device whose entry in the ID table
* matches the device. The probe functions returns zero when the driver choose
* to take "ownership" of the device or an error code(-ve no) otherwise.
*/
static int __devinit stmmac_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret = 0;
void __iomem *addr = NULL;
struct stmmac_priv *priv = NULL;
int i;
/* Enable pci device */
ret = pci_enable_device(pdev);
if (ret) {
pr_err("%s : ERROR: failed to enable %s device\n", __func__,
pci_name(pdev));
return ret;
}
if (pci_request_regions(pdev, STMMAC_RESOURCE_NAME)) {
pr_err("%s: ERROR: failed to get PCI region\n", __func__);
ret = -ENODEV;
goto err_out_req_reg_failed;
}
/* Get the base address of device */
for (i = 0; i <= 5; i++) {
if (pci_resource_len(pdev, i) == 0)
continue;
addr = pci_iomap(pdev, i, 0);
if (addr == NULL) {
pr_err("%s: ERROR: cannot map regiser memory, aborting",
__func__);
ret = -EIO;
goto err_out_map_failed;
}
break;
}
pci_set_master(pdev);
stmmac_default_data();
priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
if (!priv) {
pr_err("%s: main driver probe failed", __func__);
goto err_out;
}
priv->dev->irq = pdev->irq;
priv->wol_irq = pdev->irq;
pci_set_drvdata(pdev, priv->dev);
pr_debug("STMMAC platform driver registration completed");
return 0;
err_out:
pci_clear_master(pdev);
err_out_map_failed:
pci_release_regions(pdev);
err_out_req_reg_failed:
pci_disable_device(pdev);
return ret;
}
/**
* stmmac_dvr_remove
*
* @pdev: platform device pointer
* Description: this function calls the main to free the net resources
* and releases the PCI resources.
*/
static void __devexit stmmac_pci_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev);
stmmac_dvr_remove(ndev);
pci_set_drvdata(pdev, NULL);
pci_iounmap(pdev, priv->ioaddr);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
#ifdef CONFIG_PM
static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *ndev = pci_get_drvdata(pdev);
int ret;
ret = stmmac_suspend(ndev);
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return ret;
}
static int stmmac_pci_resume(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
return stmmac_resume(ndev);
}
#endif
#define STMMAC_VENDOR_ID 0x700
#define STMMAC_DEVICE_ID 0x1108
static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
{
PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, {
}
};
MODULE_DEVICE_TABLE(pci, stmmac_id_table);
static struct pci_driver stmmac_driver = {
.name = STMMAC_RESOURCE_NAME,
.id_table = stmmac_id_table,
.probe = stmmac_pci_probe,
.remove = __devexit_p(stmmac_pci_remove),
#ifdef CONFIG_PM
.suspend = stmmac_pci_suspend,
.resume = stmmac_pci_resume,
#endif
};
/**
* stmmac_init_module - Entry point for the driver
* Description: This function is the entry point for the driver.
*/
static int __init stmmac_init_module(void)
{
int ret;
ret = pci_register_driver(&stmmac_driver);
if (ret < 0)
pr_err("%s: ERROR: driver registration failed\n", __func__);
return ret;
}
/**
* stmmac_cleanup_module - Cleanup routine for the driver
* Description: This function is the cleanup routine for the driver.
*/
static void __exit stmmac_cleanup_module(void)
{
pci_unregister_driver(&stmmac_driver);
}
module_init(stmmac_init_module);
module_exit(stmmac_cleanup_module);
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,234 @@
/*******************************************************************************
This contains the functions to handle the platform driver.
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>
*******************************************************************************/
#include <linux/platform_device.h>
#include <linux/io.h>
#include "stmmac.h"
/**
* stmmac_pltfr_probe
* @pdev: platform device pointer
* Description: platform_device probe function. It allocates
* the necessary resources and invokes the main to init
* the net device, register the mdio bus etc.
*/
static int stmmac_pltfr_probe(struct platform_device *pdev)
{
int ret = 0;
struct resource *res;
void __iomem *addr = NULL;
struct stmmac_priv *priv = NULL;
struct plat_stmmacenet_data *plat_dat;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
pr_err("%s: ERROR: memory allocation failed"
"cannot get the I/O addr 0x%x\n",
__func__, (unsigned int)res->start);
return -EBUSY;
}
addr = ioremap(res->start, resource_size(res));
if (!addr) {
pr_err("%s: ERROR: memory mapping failed", __func__);
ret = -ENOMEM;
goto out_release_region;
}
plat_dat = pdev->dev.platform_data;
/* Custom initialisation (if needed)*/
if (plat_dat->init) {
ret = plat_dat->init(pdev);
if (unlikely(ret))
goto out_unmap;
}
priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
if (!priv) {
pr_err("%s: main driver probe failed", __func__);
goto out_unmap;
}
/* Get the MAC information */
priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
if (priv->dev->irq == -ENXIO) {
pr_err("%s: ERROR: MAC IRQ configuration "
"information not found\n", __func__);
ret = -ENXIO;
goto out_unmap;
}
/*
* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
* The external wake up irq can be passed through the platform code
* named as "eth_wake_irq"
*
* In case the wake up interrupt is not passed from the platform
* so the driver will continue to use the mac irq (ndev->irq)
*/
priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
if (priv->wol_irq == -ENXIO)
priv->wol_irq = priv->dev->irq;
priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
platform_set_drvdata(pdev, priv->dev);
pm_runtime_set_active(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pr_debug("STMMAC platform driver registration completed");
return 0;
out_unmap:
iounmap(addr);
platform_set_drvdata(pdev, NULL);
out_release_region:
release_mem_region(res->start, resource_size(res));
return ret;
}
/**
* stmmac_pltfr_remove
* @pdev: platform device pointer
* Description: this function calls the main to free the net resources
* and calls the platforms hook and release the resources (e.g. mem).
*/
static int stmmac_pltfr_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct stmmac_priv *priv = netdev_priv(ndev);
struct resource *res;
int ret = stmmac_dvr_remove(ndev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (priv->plat->exit)
priv->plat->exit(pdev);
if (priv->plat->exit)
priv->plat->exit(pdev);
platform_set_drvdata(pdev, NULL);
iounmap((void *)priv->ioaddr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
return ret;
}
#ifdef CONFIG_PM
static int stmmac_pltfr_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
return stmmac_suspend(ndev);
}
static int stmmac_pltfr_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
return stmmac_resume(ndev);
}
int stmmac_pltfr_freeze(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
return stmmac_freeze(ndev);
}
int stmmac_pltfr_restore(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
return stmmac_restore(ndev);
}
#if 0
int stmmac_pltfr_idle(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct stmmac_priv *priv = netdev_priv(ndev);
struct phy_device *phydev = priv->phydev;
#ifdef CONFIG_PM_RUNTIME
if (!phydev->link)
pm_schedule_suspend(dev, MSEC_PER_SEC * 5);
#endif
return -EBUSY;
}
#endif
SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend, stmmac_pltfr_resume);
#else
static const struct dev_pm_ops stmmac_pltfr_pm_ops;
#endif /* CONFIG_PM */
static struct platform_driver stmmac_driver = {
.probe = stmmac_pltfr_probe,
.remove = stmmac_pltfr_remove,
.driver = {
.name = STMMAC_RESOURCE_NAME,
.owner = THIS_MODULE,
.pm = &stmmac_pltfr_pm_ops,
},
};
/**
* stmmac_init_module - Entry point for the driver
* Description: This function is the entry point for the driver.
*/
static int __init stmmac_init_module(void)
{
return platform_driver_register(&stmmac_driver);
}
/**
* stmmac_cleanup_module - Cleanup routine for the driver
* Description: This function is the cleanup routine for the driver.
*/
static void __exit stmmac_cleanup_module(void)
{
platform_driver_unregister(&stmmac_driver);
}
module_init(stmmac_init_module);
module_exit(stmmac_cleanup_module);
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
MODULE_LICENSE("GPL");

View File

@ -497,6 +497,8 @@ struct ethtool_ops {
u32 (*get_priv_flags)(struct net_device *);
int (*set_priv_flags)(struct net_device *, u32);
int (*get_sset_count)(struct net_device *, int);
int (*get_eee) (struct net_device *, struct ethtool_value *);
int (*set_eee) (struct net_device *, struct ethtool_value *);
/* the following hooks are obsolete */
int (*self_test_count)(struct net_device *);/* use get_sset_count */
@ -561,6 +563,8 @@ struct ethtool_ops {
#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */
#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */
#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */
#define ETHTOOL_GEEE 0x00000041 /* Get EEE */
#define ETHTOOL_SEEE 0x00000042 /* Set EEE */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@ -663,6 +667,7 @@ struct ethtool_ops {
#define WAKE_ARP (1 << 4)
#define WAKE_MAGIC (1 << 5)
#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
#define WAKE_DOWN_SPEED (1 << 7)
/* L3-L4 network traffic flow types */
#define TCP_V4_FLOW 0x01

View File

@ -42,7 +42,11 @@
#define MDIO_PKGID2 15
#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */
#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */
#define MDIO_EEE_CAP 20 /* EEE Capability register */
#define MDIO_EEE_WK_ERR 22 /* EEE wake error counter */
#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */
#define MDIO_EEE_ADV 60 /* EEE advertisement */
#define MDIO_EEE_PART_LINK 61 /* EEE link partner ability */
/* Media-dependent registers. */
#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */
@ -80,6 +84,7 @@
#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART
#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE
#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */
#define MDIO_PCS_CLK_STOP_ENABLE 0x400 /* Stop the clock during LPI */
/* 10 Gb/s */
#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00)

View File

@ -21,6 +21,8 @@
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
#define MII_MMD_CRTL 0x0d /* MMD Access Control Register */
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
#define MII_ESTATUS 0x0f /* Extended Status */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
@ -139,6 +141,15 @@
#define FLOW_CTRL_TX 0x01
#define FLOW_CTRL_RX 0x02
/* MMD Access Control register fields */
#define MII_MMD_CRTL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
#define MII_MMD_CRTL_FUNC_ADDR 0x0000 /* Address */
#define MII_MMD_CTRL_FUNC_DATA_NOINCR 0x4000 /* no post increment */
#define MII_MMD_CTRL_FUNC_DATA_INCR_ON_RDWT 0x8000 /* post increment on
* reads & writes */
#define MII_MMD_CTRL_FUNC_DATA_INCR_ON_WT 0xC000 /* post increment on
* writes only */
/* This structure is used in all SIOCxMIIxxx ioctl calls */
struct mii_ioctl_data {
__u16 phy_id;

View File

@ -248,6 +248,7 @@ enum phy_state {
* changes in the link state.
* adjust_state: Callback for the enet driver to respond to
* changes in the state machine.
* wol: which WoL mode will be used to wake-up the system via ethtool.
*
* speed, duplex, pause, supported, advertising, and
* autoneg are used like in mii_if_info
@ -321,6 +322,7 @@ struct phy_device {
struct mutex lock;
struct net_device *attached_dev;
int wol;
void (*adjust_link)(struct net_device *dev);
@ -339,6 +341,8 @@ struct phy_device {
* by this PHY
* flags: A bitfield defining certain other features this PHY
* supports (like interrupts)
* wol: to define which Wake-up modes are supported (e.g. WoL
* via magic packet).
*
* The drivers must implement config_aneg and read_status. All
* other functions are optional. Note that none of these
@ -354,6 +358,7 @@ struct phy_driver {
unsigned int phy_id_mask;
u32 features;
u32 flags;
u32 wol_supported;
/*
* Called to initialize the PHY,
@ -442,6 +447,9 @@ static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
}
int phy_read_page(struct phy_device *phydev, u16 regnum, int page);
int phy_write_page(struct phy_device *phydev, u16 regnum, int page, int data);
int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_device_register(struct phy_device *phy);
@ -489,6 +497,9 @@ void phy_start_machine(struct phy_device *phydev,
void phy_stop_machine(struct phy_device *phydev);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
int phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
int phy_start_interrupts(struct phy_device *phydev);
@ -504,6 +515,9 @@ int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask,
int (*run)(struct phy_device *));
int phy_scan_fixups(struct phy_device *phydev);
int phy_check_eee(struct phy_device *phydev);
int phy_get_eee_err(struct phy_device *phydev);
int __init mdio_bus_init(void);
void mdio_bus_exit(void);

View File

@ -26,6 +26,8 @@
#ifndef __STMMAC_PLATFORM_DATA
#define __STMMAC_PLATFORM_DATA
#include <linux/platform_device.h>
/* Platfrom data for platform device structure's platform_data field */
struct stmmac_mdio_bus_data {
@ -48,6 +50,7 @@ struct plat_stmmacenet_data {
int tx_coe;
int bugged_jumbo;
int pmt;
int force_sf_dma_mode;
void (*fix_mac_speed)(void *priv, unsigned int speed);
void (*bus_setup)(void __iomem *ioaddr);
int (*init)(struct platform_device *pdev);

View File

@ -357,6 +357,32 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
return dev->ethtool_ops->set_wol(dev, &wol);
}
static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->get_eee)
return -EOPNOTSUPP;
dev->ethtool_ops->get_eee(dev, &edata);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
static int ethtool_set_eee(struct net_device *dev, char __user *useraddr)
{
struct ethtool_value edata;
if (!dev->ethtool_ops->set_eee)
return -EOPNOTSUPP;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
return dev->ethtool_ops->set_eee(dev, &edata);
}
static int ethtool_nway_reset(struct net_device *dev)
{
if (!dev->ethtool_ops->nway_reset)
@ -1012,6 +1038,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
rc = ethtool_set_value_void(dev, useraddr,
dev->ethtool_ops->set_msglevel);
break;
case ETHTOOL_GEEE:
rc = ethtool_get_eee(dev, useraddr);
break;
case ETHTOOL_SEEE:
rc = ethtool_set_eee(dev, useraddr);
break;
case ETHTOOL_NWAY_RST:
rc = ethtool_nway_reset(dev);
break;

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.32.42
# Wed Apr 8 14:52:06 2015
# Thu Feb 11 20:59:25 2016
#
CONFIG_SUPERH=y
CONFIG_SUPERH32=y
@ -740,8 +740,13 @@ CONFIG_PHYLIB=y
CONFIG_MII=y
CONFIG_NETDEV_1000=y
CONFIG_STMMAC_ETH=y
CONFIG_STMMAC_PLATFORM=y
# CONFIG_STMMAC_PCI is not set
CONFIG_STMMAC_DEBUG_FS=y
# CONFIG_STMMAC_DA is not set
# CONFIG_STMMAC_TIMER is not set
CONFIG_STMMAC_RING=y
# CONFIG_STMMAC_CHAINED is not set
CONFIG_NETDEV_10000=y
# CONFIG_WLAN is not set
@ -1333,8 +1338,11 @@ CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set