kernel: update stmmac ethernet driver from latest linux-sh4-2.6.32.y - _stm24_0217
This commit is contained in:
parent
ccc89f44ae
commit
dcaf0bf211
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
137
kernel/drivers/net/stmmac/chain_mode.c
Normal file
137
kernel/drivers/net/stmmac/chain_mode.c
Normal 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,
|
||||
};
|
@ -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;
|
||||
|
@ -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;
|
||||
|
126
kernel/drivers/net/stmmac/descs_com.h
Normal file
126
kernel/drivers/net/stmmac/descs_com.h
Normal 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
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
131
kernel/drivers/net/stmmac/mmc.h
Normal file
131
kernel/drivers/net/stmmac/mmc.h
Normal 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);
|
266
kernel/drivers/net/stmmac/mmc_core.c
Normal file
266
kernel/drivers/net/stmmac/mmc_core.c
Normal 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);
|
||||
}
|
@ -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)
|
||||
|
126
kernel/drivers/net/stmmac/ring_mode.c
Normal file
126
kernel/drivers/net/stmmac/ring_mode.c
Normal 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,
|
||||
};
|
@ -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);
|
||||
|
||||
|
@ -44,24 +44,26 @@ struct stmmac_stats {
|
||||
{ #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
|
||||
offsetof(struct stmmac_priv, xstats.m)}
|
||||
|
||||
static const struct stmmac_stats stmmac_gstrings_stats[] = {
|
||||
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,
|
||||
priv->ioaddr);
|
||||
/* 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 ==
|
||||
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
|
||||
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
@ -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;
|
||||
|
||||
|
219
kernel/drivers/net/stmmac/stmmac_pci.c
Normal file
219
kernel/drivers/net/stmmac/stmmac_pci.c
Normal 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");
|
234
kernel/drivers/net/stmmac/stmmac_platform.c
Normal file
234
kernel/drivers/net/stmmac/stmmac_platform.c
Normal 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");
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user