mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
23
drivers/net/ethernet/stmicro/Kconfig
Normal file
23
drivers/net/ethernet/stmicro/Kconfig
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# STMicroelectronics device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_STMICRO
|
||||
bool "STMicroelectronics devices"
|
||||
default y
|
||||
depends on HAS_IOMEM
|
||||
---help---
|
||||
If you have a network (Ethernet) card belonging to this class, say Y
|
||||
and read the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about STMicroelectronics cards. If you say Y, you will
|
||||
be asked for your specific card in the following questions.
|
||||
|
||||
if NET_VENDOR_STMICRO
|
||||
|
||||
source "drivers/net/ethernet/stmicro/stmmac/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_STMICRO
|
5
drivers/net/ethernet/stmicro/Makefile
Normal file
5
drivers/net/ethernet/stmicro/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for the STMicroelectronics device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_STMMAC_ETH) += stmmac/
|
100
drivers/net/ethernet/stmicro/stmmac/Kconfig
Normal file
100
drivers/net/ethernet/stmicro/stmmac/Kconfig
Normal file
|
@ -0,0 +1,100 @@
|
|||
config STMMAC_ETH
|
||||
tristate "STMicroelectronics 10/100/1000 Ethernet driver"
|
||||
depends on HAS_IOMEM && HAS_DMA
|
||||
select MII
|
||||
select PHYLIB
|
||||
select CRC32
|
||||
select PTP_1588_CLOCK
|
||||
select RESET_CONTROLLER
|
||||
---help---
|
||||
This is the driver for the Ethernet IPs are built around a
|
||||
Synopsys IP Core and only tested on the STMicroelectronics
|
||||
platforms.
|
||||
|
||||
if STMMAC_ETH
|
||||
|
||||
config STMMAC_PLATFORM
|
||||
bool "STMMAC Platform bus support"
|
||||
depends on STMMAC_ETH
|
||||
default y
|
||||
---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 DWMAC_MESON
|
||||
bool "Amlogic Meson dwmac support"
|
||||
depends on STMMAC_PLATFORM && ARCH_MESON
|
||||
help
|
||||
Support for Ethernet controller on Amlogic Meson SoCs.
|
||||
|
||||
This selects the Amlogic Meson SoC glue layer support for
|
||||
the stmmac device driver. This driver is used for Meson6 and
|
||||
Meson8 SoCs.
|
||||
|
||||
config DWMAC_SOCFPGA
|
||||
bool "SOCFPGA dwmac support"
|
||||
depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST)
|
||||
help
|
||||
Support for ethernet controller on Altera SOCFPGA
|
||||
|
||||
This selects the Altera SOCFPGA SoC glue layer support
|
||||
for the stmmac device driver. This driver is used for
|
||||
arria5 and cyclone5 FPGA SoCs.
|
||||
|
||||
config DWMAC_SUNXI
|
||||
bool "Allwinner GMAC support"
|
||||
depends on STMMAC_PLATFORM && ARCH_SUNXI
|
||||
default y
|
||||
---help---
|
||||
Support for Allwinner A20/A31 GMAC ethernet controllers.
|
||||
|
||||
This selects Allwinner SoC glue layer support for the
|
||||
stmmac device driver. This driver is used for A20/A31
|
||||
GMAC ethernet controller.
|
||||
|
||||
config DWMAC_STI
|
||||
bool "STi GMAC support"
|
||||
depends on STMMAC_PLATFORM && ARCH_STI
|
||||
default y
|
||||
---help---
|
||||
Support for ethernet controller on STi SOCs.
|
||||
|
||||
This selects STi SoC glue layer support for the stmmac
|
||||
device driver. This driver is used on for the STi series
|
||||
SOCs GMAC ethernet controller.
|
||||
|
||||
config STMMAC_PCI
|
||||
bool "STMMAC PCI bus support"
|
||||
depends on STMMAC_ETH && PCI
|
||||
---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.
|
||||
|
||||
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
|
||||
---help---
|
||||
Selecting this option, rx has priority over Tx (only for Giga
|
||||
Ethernet device).
|
||||
By default, the DMA arbitration scheme is based on Round-robin
|
||||
(rx:tx priority is 1:1).
|
||||
|
||||
endif
|
11
drivers/net/ethernet/stmicro/stmmac/Makefile
Normal file
11
drivers/net/ethernet/stmicro/stmmac/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
|
||||
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
|
||||
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
|
||||
stmmac-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
|
||||
stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
|
||||
stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
|
||||
stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
|
||||
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
|
||||
chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
|
||||
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
|
||||
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
|
166
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
Normal file
166
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*******************************************************************************
|
||||
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"
|
||||
|
||||
static 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);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
|
||||
|
||||
while (len != 0) {
|
||||
priv->tx_skbuff[entry] = NULL;
|
||||
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);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
|
||||
STMMAC_CHAIN_MODE);
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
len -= bmax;
|
||||
i++;
|
||||
} else {
|
||||
desc->des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i), len,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
||||
STMMAC_CHAIN_MODE);
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
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_init_dma_chain(void *des, dma_addr_t phy_addr,
|
||||
unsigned int size, unsigned int extend_desc)
|
||||
{
|
||||
/*
|
||||
* In chained mode the des3 points to the next element in the ring.
|
||||
* The latest element has to point to the head.
|
||||
*/
|
||||
int i;
|
||||
dma_addr_t dma_phy = phy_addr;
|
||||
|
||||
if (extend_desc) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_extended_desc);
|
||||
p->basic.des3 = (unsigned int)dma_phy;
|
||||
p++;
|
||||
}
|
||||
p->basic.des3 = (unsigned int)phy_addr;
|
||||
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)des;
|
||||
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 void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
if (priv->hwts_rx_en && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = (unsigned int)(priv->dma_rx_phy +
|
||||
(((priv->dirty_rx) + 1) %
|
||||
priv->dma_rx_size) *
|
||||
sizeof(struct dma_desc));
|
||||
}
|
||||
|
||||
static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = (unsigned int)(priv->dma_tx_phy +
|
||||
(((priv->dirty_tx + 1) %
|
||||
priv->dma_tx_size) *
|
||||
sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
const struct stmmac_mode_ops chain_mode_ops = {
|
||||
.init = stmmac_init_dma_chain,
|
||||
.is_jumbo_frm = stmmac_is_jumbo_frm,
|
||||
.jumbo_frm = stmmac_jumbo_frm,
|
||||
.refill_desc3 = stmmac_refill_desc3,
|
||||
.clean_desc3 = stmmac_clean_desc3,
|
||||
};
|
466
drivers/net/ethernet/stmicro/stmmac/common.h
Normal file
466
drivers/net/ethernet/stmicro/stmmac/common.h
Normal file
|
@ -0,0 +1,466 @@
|
|||
/*******************************************************************************
|
||||
STMMAC Common Header File
|
||||
|
||||
Copyright (C) 2007-2009 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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.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"
|
||||
|
||||
/* Synopsys Core versions */
|
||||
#define DWMAC_CORE_3_40 0x34
|
||||
#define DWMAC_CORE_3_50 0x35
|
||||
|
||||
#undef FRAME_FILTER_DEBUG
|
||||
/* #define FRAME_FILTER_DEBUG */
|
||||
|
||||
struct stmmac_extra_stats {
|
||||
/* Transmit errors */
|
||||
unsigned long tx_underflow ____cacheline_aligned;
|
||||
unsigned long tx_carrier;
|
||||
unsigned long tx_losscarrier;
|
||||
unsigned long vlan_tag;
|
||||
unsigned long tx_deferred;
|
||||
unsigned long tx_vlan;
|
||||
unsigned long tx_jabber;
|
||||
unsigned long tx_frame_flushed;
|
||||
unsigned long tx_payload_error;
|
||||
unsigned long tx_ip_header_error;
|
||||
/* Receive errors */
|
||||
unsigned long rx_desc;
|
||||
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;
|
||||
unsigned long rx_gmac_overflow;
|
||||
unsigned long rx_watchdog;
|
||||
unsigned long da_rx_filter_fail;
|
||||
unsigned long sa_rx_filter_fail;
|
||||
unsigned long rx_missed_cntr;
|
||||
unsigned long rx_overflow_cntr;
|
||||
unsigned long rx_vlan;
|
||||
/* Tx/Rx IRQ error info */
|
||||
unsigned long tx_undeflow_irq;
|
||||
unsigned long tx_process_stopped_irq;
|
||||
unsigned long tx_jabber_irq;
|
||||
unsigned long rx_overflow_irq;
|
||||
unsigned long rx_buf_unav_irq;
|
||||
unsigned long rx_process_stopped_irq;
|
||||
unsigned long rx_watchdog_irq;
|
||||
unsigned long tx_early_irq;
|
||||
unsigned long fatal_bus_error_irq;
|
||||
/* Tx/Rx IRQ Events */
|
||||
unsigned long rx_early_irq;
|
||||
unsigned long threshold;
|
||||
unsigned long tx_pkt_n;
|
||||
unsigned long rx_pkt_n;
|
||||
unsigned long normal_irq_n;
|
||||
unsigned long rx_normal_irq_n;
|
||||
unsigned long napi_poll;
|
||||
unsigned long tx_normal_irq_n;
|
||||
unsigned long tx_clean;
|
||||
unsigned long tx_reset_ic_bit;
|
||||
unsigned long irq_receive_pmt_irq_n;
|
||||
/* MMC info */
|
||||
unsigned long mmc_tx_irq_n;
|
||||
unsigned long mmc_rx_irq_n;
|
||||
unsigned long mmc_rx_csum_offload_irq_n;
|
||||
/* EEE */
|
||||
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;
|
||||
/* Extended RDES status */
|
||||
unsigned long ip_hdr_err;
|
||||
unsigned long ip_payload_err;
|
||||
unsigned long ip_csum_bypassed;
|
||||
unsigned long ipv4_pkt_rcvd;
|
||||
unsigned long ipv6_pkt_rcvd;
|
||||
unsigned long rx_msg_type_ext_no_ptp;
|
||||
unsigned long rx_msg_type_sync;
|
||||
unsigned long rx_msg_type_follow_up;
|
||||
unsigned long rx_msg_type_delay_req;
|
||||
unsigned long rx_msg_type_delay_resp;
|
||||
unsigned long rx_msg_type_pdelay_req;
|
||||
unsigned long rx_msg_type_pdelay_resp;
|
||||
unsigned long rx_msg_type_pdelay_follow_up;
|
||||
unsigned long ptp_frame_type;
|
||||
unsigned long ptp_ver;
|
||||
unsigned long timestamp_dropped;
|
||||
unsigned long av_pkt_rcvd;
|
||||
unsigned long av_tagged_pkt_rcvd;
|
||||
unsigned long vlan_tag_priority_val;
|
||||
unsigned long l3_filter_match;
|
||||
unsigned long l4_filter_match;
|
||||
unsigned long l3_l4_filter_no_match;
|
||||
/* PCS */
|
||||
unsigned long irq_pcs_ane_n;
|
||||
unsigned long irq_pcs_link_n;
|
||||
unsigned long irq_rgmii_n;
|
||||
unsigned long pcs_link;
|
||||
unsigned long pcs_duplex;
|
||||
unsigned long pcs_speed;
|
||||
};
|
||||
|
||||
/* CSR Frequency Access Defines*/
|
||||
#define CSR_F_35M 35000000
|
||||
#define CSR_F_60M 60000000
|
||||
#define CSR_F_100M 100000000
|
||||
#define CSR_F_150M 150000000
|
||||
#define CSR_F_250M 250000000
|
||||
#define CSR_F_300M 300000000
|
||||
|
||||
#define MAC_CSR_H_FRQ_MASK 0x20
|
||||
|
||||
#define HASH_TABLE_SIZE 64
|
||||
#define PAUSE_TIME 0x200
|
||||
|
||||
/* Flow Control defines */
|
||||
#define FLOW_OFF 0
|
||||
#define FLOW_RX 1
|
||||
#define FLOW_TX 2
|
||||
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
|
||||
|
||||
/* PCS defines */
|
||||
#define STMMAC_PCS_RGMII (1 << 0)
|
||||
#define STMMAC_PCS_SGMII (1 << 1)
|
||||
#define STMMAC_PCS_TBI (1 << 2)
|
||||
#define STMMAC_PCS_RTBI (1 << 3)
|
||||
|
||||
#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_ADDMAC 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 */
|
||||
#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 PTPv2 */
|
||||
#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 COE (Type 1) in Rx */
|
||||
#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP COE (Type 2) in Rx */
|
||||
#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
|
||||
#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. additional Rx Channels */
|
||||
#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. additional Tx Channels */
|
||||
#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate Descriptor */
|
||||
/* Timestamping with Internal System Time */
|
||||
#define DMA_HW_FEAT_INTTSEN 0x02000000
|
||||
#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
|
||||
#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN */
|
||||
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
|
||||
#define DEFAULT_DMA_PBL 8
|
||||
|
||||
/* Max/Min RI Watchdog Timer count value */
|
||||
#define MAX_DMA_RIWT 0xff
|
||||
#define MIN_DMA_RIWT 0x20
|
||||
/* Tx coalesce parameters */
|
||||
#define STMMAC_COAL_TX_TIMER 40000
|
||||
#define STMMAC_MAX_COAL_TX_TICK 100000
|
||||
#define STMMAC_TX_MAX_FRAMES 256
|
||||
#define STMMAC_TX_FRAMES 64
|
||||
|
||||
/* Rx IPC status */
|
||||
enum rx_frame_status {
|
||||
good_frame = 0,
|
||||
discard_frame = 1,
|
||||
csum_none = 2,
|
||||
llc_snap = 4,
|
||||
};
|
||||
|
||||
enum dma_irq_status {
|
||||
tx_hard_error = 0x1,
|
||||
tx_hard_error_bump_tc = 0x2,
|
||||
handle_rx = 0x4,
|
||||
handle_tx = 0x8,
|
||||
};
|
||||
|
||||
#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 0)
|
||||
#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 1)
|
||||
#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 2)
|
||||
#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 3)
|
||||
|
||||
#define CORE_PCS_ANE_COMPLETE (1 << 5)
|
||||
#define CORE_PCS_LINK_STATUS (1 << 6)
|
||||
#define CORE_RGMII_IRQ (1 << 7)
|
||||
|
||||
struct rgmii_adv {
|
||||
unsigned int pause;
|
||||
unsigned int duplex;
|
||||
unsigned int lp_pause;
|
||||
unsigned int lp_duplex;
|
||||
};
|
||||
|
||||
#define STMMAC_PCS_PAUSE 1
|
||||
#define STMMAC_PCS_ASYM_PAUSE 2
|
||||
|
||||
/* 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
|
||||
#define BUF_SIZE_4KiB 4096
|
||||
#define BUF_SIZE_2KiB 2048
|
||||
|
||||
/* Power Down and WOL */
|
||||
#define PMT_NOT_SUPPORTED 0
|
||||
#define PMT_SUPPORTED 1
|
||||
|
||||
/* Common MAC defines */
|
||||
#define MAC_CTRL_REG 0x00000000 /* MAC Control */
|
||||
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
|
||||
|
||||
/* Default LPI timers */
|
||||
#define STMMAC_DEFAULT_LIT_LS 0x3E8
|
||||
#define STMMAC_DEFAULT_TWT_LS 0x1E
|
||||
|
||||
#define STMMAC_CHAIN_MODE 0x1
|
||||
#define STMMAC_RING_MODE 0x2
|
||||
|
||||
#define JUMBO_LEN 9000
|
||||
|
||||
struct stmmac_desc_ops {
|
||||
/* DMA RX descriptor ring initialization */
|
||||
void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end);
|
||||
/* DMA TX descriptor ring initialization */
|
||||
void (*init_tx_desc) (struct dma_desc *p, int mode, int end);
|
||||
|
||||
/* Invoked by the xmit function to prepare the tx descriptor */
|
||||
void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode);
|
||||
/* Set/get the owner of the descriptor */
|
||||
void (*set_tx_owner) (struct dma_desc *p);
|
||||
int (*get_tx_owner) (struct dma_desc *p);
|
||||
/* Invoked by the xmit function to close the tx descriptor */
|
||||
void (*close_tx_desc) (struct dma_desc *p);
|
||||
/* Clean the tx descriptor as soon as the tx irq is received */
|
||||
void (*release_tx_desc) (struct dma_desc *p, int mode);
|
||||
/* Clear interrupt on tx frame completion. When this bit is
|
||||
* set an interrupt happens as soon as the frame is transmitted */
|
||||
void (*clear_tx_ic) (struct dma_desc *p);
|
||||
/* Last tx segment reports the transmit status */
|
||||
int (*get_tx_ls) (struct dma_desc *p);
|
||||
/* Return the transmit status looking at the TDES1 */
|
||||
int (*tx_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr);
|
||||
/* Get the buffer size from the descriptor */
|
||||
int (*get_tx_len) (struct dma_desc *p);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*get_rx_owner) (struct dma_desc *p);
|
||||
void (*set_rx_owner) (struct dma_desc *p);
|
||||
/* Get the receive frame size */
|
||||
int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
|
||||
/* Return the reception status looking at the RDES1 */
|
||||
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p);
|
||||
void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p);
|
||||
/* Set tx timestamp enable bit */
|
||||
void (*enable_tx_timestamp) (struct dma_desc *p);
|
||||
/* get tx timestamp status */
|
||||
int (*get_tx_timestamp_status) (struct dma_desc *p);
|
||||
/* get timestamp value */
|
||||
u64(*get_timestamp) (void *desc, u32 ats);
|
||||
/* get rx timestamp status */
|
||||
int (*get_rx_timestamp_status) (void *desc, u32 ats);
|
||||
};
|
||||
|
||||
struct stmmac_dma_ops {
|
||||
/* DMA core initialization */
|
||||
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds);
|
||||
/* Dump DMA registers */
|
||||
void (*dump_regs) (void __iomem *ioaddr);
|
||||
/* Set tx/rx threshold in the csr6 register
|
||||
* An invalid value enables the store-and-forward mode */
|
||||
void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
void (*enable_dma_transmission) (void __iomem *ioaddr);
|
||||
void (*enable_dma_irq) (void __iomem *ioaddr);
|
||||
void (*disable_dma_irq) (void __iomem *ioaddr);
|
||||
void (*start_tx) (void __iomem *ioaddr);
|
||||
void (*stop_tx) (void __iomem *ioaddr);
|
||||
void (*start_rx) (void __iomem *ioaddr);
|
||||
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);
|
||||
/* Program the HW RX Watchdog */
|
||||
void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
|
||||
};
|
||||
|
||||
struct mac_device_info;
|
||||
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
void (*core_init)(struct mac_device_info *hw, int mtu);
|
||||
/* Enable and verify that the IPC module is supported */
|
||||
int (*rx_ipc)(struct mac_device_info *hw);
|
||||
/* Dump MAC registers */
|
||||
void (*dump_regs)(struct mac_device_info *hw);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*host_irq_status)(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x);
|
||||
/* Multicast filter setting */
|
||||
void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Flow control setting */
|
||||
void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time);
|
||||
/* Set power management mode (e.g. magic frame) */
|
||||
void (*pmt)(struct mac_device_info *hw, unsigned long mode);
|
||||
/* Set/Get Unicast MAC addresses */
|
||||
void (*set_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*set_eee_mode)(struct mac_device_info *hw);
|
||||
void (*reset_eee_mode)(struct mac_device_info *hw);
|
||||
void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
|
||||
void (*set_eee_pls)(struct mac_device_info *hw, int link);
|
||||
void (*ctrl_ane)(struct mac_device_info *hw, bool restart);
|
||||
void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv);
|
||||
};
|
||||
|
||||
struct stmmac_hwtimestamp {
|
||||
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
|
||||
void (*config_sub_second_increment) (void __iomem *ioaddr);
|
||||
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
|
||||
int (*config_addend) (void __iomem *ioaddr, u32 addend);
|
||||
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub);
|
||||
u64(*get_systime) (void __iomem *ioaddr);
|
||||
};
|
||||
|
||||
struct mac_link {
|
||||
int port;
|
||||
int duplex;
|
||||
int speed;
|
||||
};
|
||||
|
||||
struct mii_regs {
|
||||
unsigned int addr; /* MII Address */
|
||||
unsigned int data; /* MII Data */
|
||||
};
|
||||
|
||||
struct stmmac_mode_ops {
|
||||
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
|
||||
unsigned int extend_desc);
|
||||
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
|
||||
int (*jumbo_frm)(void *priv, struct sk_buff *skb, int csum);
|
||||
int (*set_16kib_bfsize)(int mtu);
|
||||
void (*init_desc3)(struct dma_desc *p);
|
||||
void (*refill_desc3) (void *priv, struct dma_desc *p);
|
||||
void (*clean_desc3) (void *priv, struct dma_desc *p);
|
||||
};
|
||||
|
||||
struct mac_device_info {
|
||||
const struct stmmac_ops *mac;
|
||||
const struct stmmac_desc_ops *desc;
|
||||
const struct stmmac_dma_ops *dma;
|
||||
const struct stmmac_mode_ops *mode;
|
||||
const struct stmmac_hwtimestamp *ptp;
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
struct mac_link link;
|
||||
unsigned int synopsys_uid;
|
||||
void __iomem *pcsr; /* vpointer to device CSRs */
|
||||
int multicast_filter_bins;
|
||||
int unicast_filter_entries;
|
||||
int mcast_bits_log2;
|
||||
unsigned int rx_csum;
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
|
||||
int perfect_uc_entries);
|
||||
struct mac_device_info *dwmac100_setup(void __iomem *ioaddr);
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
extern const struct stmmac_mode_ops ring_mode_ops;
|
||||
extern const struct stmmac_mode_ops chain_mode_ops;
|
||||
|
||||
#endif /* __COMMON_H__ */
|
219
drivers/net/ethernet/stmicro/stmmac/descs.h
Normal file
219
drivers/net/ethernet/stmicro/stmmac/descs.h
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*******************************************************************************
|
||||
Header File to describe the DMA descriptors.
|
||||
Enhanced descriptors have been in case of DWMAC1000 Cores.
|
||||
|
||||
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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESCS_H__
|
||||
#define __DESCS_H__
|
||||
|
||||
/* Basic descriptor structure for normal and alternate descriptors */
|
||||
struct dma_desc {
|
||||
/* Receive descriptor */
|
||||
union {
|
||||
struct {
|
||||
/* RDES0 */
|
||||
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 ipc_csum_error:1;
|
||||
u32 last_descriptor:1;
|
||||
u32 first_descriptor:1;
|
||||
u32 vlan_tag:1;
|
||||
u32 overflow_error:1;
|
||||
u32 length_error:1;
|
||||
u32 sa_filter_fail:1;
|
||||
u32 descriptor_error:1;
|
||||
u32 error_summary:1;
|
||||
u32 frame_length:14;
|
||||
u32 da_filter_fail:1;
|
||||
u32 own:1;
|
||||
/* RDES1 */
|
||||
u32 buffer1_size:11;
|
||||
u32 buffer2_size:11;
|
||||
u32 reserved1:2;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 reserved2:5;
|
||||
u32 disable_ic:1;
|
||||
|
||||
} rx;
|
||||
struct {
|
||||
/* RDES0 */
|
||||
u32 rx_mac_addr:1;
|
||||
u32 crc_error:1;
|
||||
u32 dribbling:1;
|
||||
u32 error_gmii:1;
|
||||
u32 receive_watchdog:1;
|
||||
u32 frame_type:1;
|
||||
u32 late_collision:1;
|
||||
u32 ipc_csum_error:1;
|
||||
u32 last_descriptor:1;
|
||||
u32 first_descriptor:1;
|
||||
u32 vlan_tag:1;
|
||||
u32 overflow_error:1;
|
||||
u32 length_error:1;
|
||||
u32 sa_filter_fail:1;
|
||||
u32 descriptor_error:1;
|
||||
u32 error_summary:1;
|
||||
u32 frame_length:14;
|
||||
u32 da_filter_fail:1;
|
||||
u32 own:1;
|
||||
/* RDES1 */
|
||||
u32 buffer1_size:13;
|
||||
u32 reserved1:1;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 buffer2_size:13;
|
||||
u32 reserved2:2;
|
||||
u32 disable_ic:1;
|
||||
} erx; /* -- enhanced -- */
|
||||
|
||||
/* Transmit descriptor */
|
||||
struct {
|
||||
/* TDES0 */
|
||||
u32 deferred:1;
|
||||
u32 underflow_error:1;
|
||||
u32 excessive_deferral:1;
|
||||
u32 collision_count:4;
|
||||
u32 vlan_frame:1;
|
||||
u32 excessive_collisions:1;
|
||||
u32 late_collision:1;
|
||||
u32 no_carrier:1;
|
||||
u32 loss_carrier:1;
|
||||
u32 payload_error:1;
|
||||
u32 frame_flushed:1;
|
||||
u32 jabber_timeout:1;
|
||||
u32 error_summary:1;
|
||||
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 time_stamp_enable:1;
|
||||
u32 disable_padding:1;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 crc_disable:1;
|
||||
u32 checksum_insertion:2;
|
||||
u32 first_segment:1;
|
||||
u32 last_segment:1;
|
||||
u32 interrupt:1;
|
||||
} tx;
|
||||
struct {
|
||||
/* TDES0 */
|
||||
u32 deferred:1;
|
||||
u32 underflow_error:1;
|
||||
u32 excessive_deferral:1;
|
||||
u32 collision_count:4;
|
||||
u32 vlan_frame:1;
|
||||
u32 excessive_collisions:1;
|
||||
u32 late_collision:1;
|
||||
u32 no_carrier:1;
|
||||
u32 loss_carrier:1;
|
||||
u32 payload_error:1;
|
||||
u32 frame_flushed:1;
|
||||
u32 jabber_timeout:1;
|
||||
u32 error_summary:1;
|
||||
u32 ip_header_error:1;
|
||||
u32 time_stamp_status:1;
|
||||
u32 reserved1:2;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 checksum_insertion:2;
|
||||
u32 reserved2:1;
|
||||
u32 time_stamp_enable:1;
|
||||
u32 disable_padding:1;
|
||||
u32 crc_disable:1;
|
||||
u32 first_segment:1;
|
||||
u32 last_segment:1;
|
||||
u32 interrupt:1;
|
||||
u32 own:1;
|
||||
/* TDES1 */
|
||||
u32 buffer1_size:13;
|
||||
u32 reserved3:3;
|
||||
u32 buffer2_size:13;
|
||||
u32 reserved4:3;
|
||||
} etx; /* -- enhanced -- */
|
||||
} des01;
|
||||
unsigned int des2;
|
||||
unsigned int des3;
|
||||
};
|
||||
|
||||
/* Extended descriptor structure (supported by new SYNP GMAC generations) */
|
||||
struct dma_extended_desc {
|
||||
struct dma_desc basic;
|
||||
union {
|
||||
struct {
|
||||
u32 ip_payload_type:3;
|
||||
u32 ip_hdr_err:1;
|
||||
u32 ip_payload_err:1;
|
||||
u32 ip_csum_bypassed:1;
|
||||
u32 ipv4_pkt_rcvd:1;
|
||||
u32 ipv6_pkt_rcvd:1;
|
||||
u32 msg_type:4;
|
||||
u32 ptp_frame_type:1;
|
||||
u32 ptp_ver:1;
|
||||
u32 timestamp_dropped:1;
|
||||
u32 reserved:1;
|
||||
u32 av_pkt_rcvd:1;
|
||||
u32 av_tagged_pkt_rcvd:1;
|
||||
u32 vlan_tag_priority_val:3;
|
||||
u32 reserved3:3;
|
||||
u32 l3_filter_match:1;
|
||||
u32 l4_filter_match:1;
|
||||
u32 l3_l4_filter_no_match:2;
|
||||
u32 reserved4:4;
|
||||
} erx;
|
||||
struct {
|
||||
u32 reserved;
|
||||
} etx;
|
||||
} des4;
|
||||
unsigned int des5; /* Reserved */
|
||||
unsigned int des6; /* Tx/Rx Timestamp Low */
|
||||
unsigned int des7; /* Tx/Rx Timestamp High */
|
||||
};
|
||||
|
||||
/* Transmit checksum insertion control */
|
||||
enum tdes_csum_insertion {
|
||||
cic_disabled = 0, /* Checksum Insertion Control */
|
||||
cic_only_ip = 1, /* Only IP header */
|
||||
/* IP header but pseudoheader is not calculated */
|
||||
cic_no_pseudoheader = 2,
|
||||
cic_full = 3, /* IP header and pseudoheader */
|
||||
};
|
||||
|
||||
/* Extended RDES4 definitions */
|
||||
#define RDES_EXT_NO_PTP 0
|
||||
#define RDES_EXT_SYNC 0x1
|
||||
#define RDES_EXT_FOLLOW_UP 0x2
|
||||
#define RDES_EXT_DELAY_REQ 0x3
|
||||
#define RDES_EXT_DELAY_RESP 0x4
|
||||
#define RDES_EXT_PDELAY_REQ 0x5
|
||||
#define RDES_EXT_PDELAY_RESP 0x6
|
||||
#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
|
||||
|
||||
#endif /* __DESCS_H__ */
|
134
drivers/net/ethernet/stmicro/stmmac/descs_com.h
Normal file
134
drivers/net/ethernet/stmicro/stmmac/descs_com.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*******************************************************************************
|
||||
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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESC_COM_H__
|
||||
#define __DESC_COM_H__
|
||||
|
||||
/* Specific functions used for Ring mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_ring(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(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des01.etx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.etx.end_ring = ter;
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_ring(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;
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_ring(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(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des01.tx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.tx.end_ring = ter;
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_ring(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;
|
||||
}
|
||||
|
||||
/* Specific functions used for Chain mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.erx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ehn_desc_tx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.etx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.etx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des01.etx.buffer1_size = len;
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.rx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_tx_set_on_chain(struct dma_desc *p, int ring_size)
|
||||
{
|
||||
p->des01.tx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.tx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des01.tx.buffer1_size = len;
|
||||
}
|
||||
#endif /* __DESC_COM_H__ */
|
67
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
Normal file
67
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Amlogic Meson DWMAC glue layer
|
||||
*
|
||||
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/stmmac.h>
|
||||
|
||||
#define ETHMAC_SPEED_100 BIT(1)
|
||||
|
||||
struct meson_dwmac {
|
||||
struct device *dev;
|
||||
void __iomem *reg;
|
||||
};
|
||||
|
||||
static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed)
|
||||
{
|
||||
struct meson_dwmac *dwmac = priv;
|
||||
unsigned int val;
|
||||
|
||||
val = readl(dwmac->reg);
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
val &= ~ETHMAC_SPEED_100;
|
||||
break;
|
||||
case SPEED_100:
|
||||
val |= ETHMAC_SPEED_100;
|
||||
break;
|
||||
}
|
||||
|
||||
writel(val, dwmac->reg);
|
||||
}
|
||||
|
||||
static void *meson6_dwmac_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_dwmac *dwmac;
|
||||
struct resource *res;
|
||||
|
||||
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
||||
if (!dwmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dwmac->reg))
|
||||
return dwmac->reg;
|
||||
|
||||
return dwmac;
|
||||
}
|
||||
|
||||
const struct stmmac_of_data meson6_dwmac_data = {
|
||||
.setup = meson6_dwmac_setup,
|
||||
.fix_mac_speed = meson6_dwmac_fix_mac_speed,
|
||||
};
|
261
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
Normal file
261
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
/* Copyright Altera Corporation (C) 2014. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Adopted from dwmac-sti.c
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include "stmmac.h"
|
||||
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
|
||||
|
||||
#define EMAC_SPLITTER_CTRL_REG 0x0
|
||||
#define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3
|
||||
#define EMAC_SPLITTER_CTRL_SPEED_10 0x2
|
||||
#define EMAC_SPLITTER_CTRL_SPEED_100 0x3
|
||||
#define EMAC_SPLITTER_CTRL_SPEED_1000 0x0
|
||||
|
||||
struct socfpga_dwmac {
|
||||
int interface;
|
||||
u32 reg_offset;
|
||||
u32 reg_shift;
|
||||
struct device *dev;
|
||||
struct regmap *sys_mgr_base_addr;
|
||||
struct reset_control *stmmac_rst;
|
||||
void __iomem *splitter_base;
|
||||
};
|
||||
|
||||
static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
|
||||
{
|
||||
struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
|
||||
void __iomem *splitter_base = dwmac->splitter_base;
|
||||
u32 val;
|
||||
|
||||
if (!splitter_base)
|
||||
return;
|
||||
|
||||
val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG);
|
||||
val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK;
|
||||
|
||||
switch (speed) {
|
||||
case 1000:
|
||||
val |= EMAC_SPLITTER_CTRL_SPEED_1000;
|
||||
break;
|
||||
case 100:
|
||||
val |= EMAC_SPLITTER_CTRL_SPEED_100;
|
||||
break;
|
||||
case 10:
|
||||
val |= EMAC_SPLITTER_CTRL_SPEED_10;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
|
||||
}
|
||||
|
||||
static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
struct regmap *sys_mgr_base_addr;
|
||||
u32 reg_offset, reg_shift;
|
||||
int ret;
|
||||
struct device_node *np_splitter;
|
||||
struct resource res_splitter;
|
||||
|
||||
dwmac->stmmac_rst = devm_reset_control_get(dev,
|
||||
STMMAC_RESOURCE_NAME);
|
||||
if (IS_ERR(dwmac->stmmac_rst)) {
|
||||
dev_info(dev, "Could not get reset control!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dwmac->interface = of_get_phy_mode(np);
|
||||
|
||||
sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
|
||||
if (IS_ERR(sys_mgr_base_addr)) {
|
||||
dev_info(dev, "No sysmgr-syscon node found\n");
|
||||
return PTR_ERR(sys_mgr_base_addr);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset);
|
||||
if (ret) {
|
||||
dev_info(dev, "Could not read reg_offset from sysmgr-syscon!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, ®_shift);
|
||||
if (ret) {
|
||||
dev_info(dev, "Could not read reg_shift from sysmgr-syscon!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0);
|
||||
if (np_splitter) {
|
||||
if (of_address_to_resource(np_splitter, 0, &res_splitter)) {
|
||||
dev_info(dev, "Missing emac splitter address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dwmac->splitter_base = devm_ioremap_resource(dev, &res_splitter);
|
||||
if (IS_ERR(dwmac->splitter_base)) {
|
||||
dev_info(dev, "Failed to mapping emac splitter\n");
|
||||
return PTR_ERR(dwmac->splitter_base);
|
||||
}
|
||||
}
|
||||
|
||||
dwmac->reg_offset = reg_offset;
|
||||
dwmac->reg_shift = reg_shift;
|
||||
dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
|
||||
dwmac->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
|
||||
{
|
||||
struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
|
||||
int phymode = dwmac->interface;
|
||||
u32 reg_offset = dwmac->reg_offset;
|
||||
u32 reg_shift = dwmac->reg_shift;
|
||||
u32 ctrl, val;
|
||||
|
||||
switch (phymode) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_MII:
|
||||
case PHY_INTERFACE_MODE_GMII:
|
||||
val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
|
||||
break;
|
||||
default:
|
||||
dev_err(dwmac->dev, "bad phy mode %d\n", phymode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Overwrite val to GMII if splitter core is enabled. The phymode here
|
||||
* is the actual phy mode on phy hardware, but phy interface from
|
||||
* EMAC core is GMII.
|
||||
*/
|
||||
if (dwmac->splitter_base)
|
||||
val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
|
||||
|
||||
regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
|
||||
ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
|
||||
ctrl |= val << reg_shift;
|
||||
|
||||
regmap_write(sys_mgr_base_addr, reg_offset, ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *socfpga_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
struct socfpga_dwmac *dwmac;
|
||||
|
||||
dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
|
||||
if (!dwmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = socfpga_dwmac_parse_data(dwmac, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to parse OF data\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ret = socfpga_dwmac_setup(dwmac);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return dwmac;
|
||||
}
|
||||
|
||||
static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct socfpga_dwmac *dwmac = priv;
|
||||
|
||||
/* On socfpga platform exit, assert and hold reset to the
|
||||
* enet controller - the default state after a hard reset.
|
||||
*/
|
||||
if (dwmac->stmmac_rst)
|
||||
reset_control_assert(dwmac->stmmac_rst);
|
||||
}
|
||||
|
||||
static int socfpga_dwmac_init(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct socfpga_dwmac *dwmac = priv;
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct stmmac_priv *stpriv = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (ndev)
|
||||
stpriv = netdev_priv(ndev);
|
||||
|
||||
/* Assert reset to the enet controller before changing the phy mode */
|
||||
if (dwmac->stmmac_rst)
|
||||
reset_control_assert(dwmac->stmmac_rst);
|
||||
|
||||
/* Setup the phy mode in the system manager registers according to
|
||||
* devicetree configuration
|
||||
*/
|
||||
ret = socfpga_dwmac_setup(dwmac);
|
||||
|
||||
/* Deassert reset for the phy configuration to be sampled by
|
||||
* the enet controller, and operation to start in requested mode
|
||||
*/
|
||||
if (dwmac->stmmac_rst)
|
||||
reset_control_deassert(dwmac->stmmac_rst);
|
||||
|
||||
/* Before the enet controller is suspended, the phy is suspended.
|
||||
* This causes the phy clock to be gated. The enet controller is
|
||||
* resumed before the phy, so the clock is still gated "off" when
|
||||
* the enet controller is resumed. This code makes sure the phy
|
||||
* is "resumed" before reinitializing the enet controller since
|
||||
* the enet controller depends on an active phy clock to complete
|
||||
* a DMA reset. A DMA reset will "time out" if executed
|
||||
* with no phy clock input on the Synopsys enet controller.
|
||||
* Verified through Synopsys Case #8000711656.
|
||||
*
|
||||
* Note that the phy clock is also gated when the phy is isolated.
|
||||
* Phy "suspend" and "isolate" controls are located in phy basic
|
||||
* control register 0, and can be modified by the phy driver
|
||||
* framework.
|
||||
*/
|
||||
if (stpriv && stpriv->phydev)
|
||||
phy_resume(stpriv->phydev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct stmmac_of_data socfpga_gmac_data = {
|
||||
.setup = socfpga_dwmac_probe,
|
||||
.init = socfpga_dwmac_init,
|
||||
.exit = socfpga_dwmac_exit,
|
||||
.fix_mac_speed = socfpga_dwmac_fix_mac_speed,
|
||||
};
|
366
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
Normal file
366
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
/**
|
||||
* dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
|
||||
*
|
||||
* Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
|
||||
* Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
|
||||
* Contributors: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
|
||||
#define DWMAC_125MHZ 125000000
|
||||
#define DWMAC_50MHZ 50000000
|
||||
#define DWMAC_25MHZ 25000000
|
||||
#define DWMAC_2_5MHZ 2500000
|
||||
|
||||
#define IS_PHY_IF_MODE_RGMII(iface) (iface == PHY_INTERFACE_MODE_RGMII || \
|
||||
iface == PHY_INTERFACE_MODE_RGMII_ID || \
|
||||
iface == PHY_INTERFACE_MODE_RGMII_RXID || \
|
||||
iface == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
|
||||
#define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \
|
||||
iface == PHY_INTERFACE_MODE_GMII)
|
||||
|
||||
/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families) */
|
||||
|
||||
/**
|
||||
* Below table summarizes the clock requirement and clock sources for
|
||||
* supported phy interface modes with link speeds.
|
||||
* ________________________________________________
|
||||
*| PHY_MODE | 1000 Mbit Link | 100 Mbit Link |
|
||||
* ------------------------------------------------
|
||||
*| MII | n/a | 25Mhz |
|
||||
*| | | txclk |
|
||||
* ------------------------------------------------
|
||||
*| GMII | 125Mhz | 25Mhz |
|
||||
*| | clk-125/txclk | txclk |
|
||||
* ------------------------------------------------
|
||||
*| RGMII | 125Mhz | 25Mhz |
|
||||
*| | clk-125/txclk | clkgen |
|
||||
*| | clkgen | |
|
||||
* ------------------------------------------------
|
||||
*| RMII | n/a | 25Mhz |
|
||||
*| | |clkgen/phyclk-in |
|
||||
* ------------------------------------------------
|
||||
*
|
||||
* Register Configuration
|
||||
*-------------------------------
|
||||
* src |BIT(8)| BIT(7)| BIT(6)|
|
||||
*-------------------------------
|
||||
* txclk | 0 | n/a | 1 |
|
||||
*-------------------------------
|
||||
* ck_125| 0 | n/a | 0 |
|
||||
*-------------------------------
|
||||
* phyclk| 1 | 0 | n/a |
|
||||
*-------------------------------
|
||||
* clkgen| 1 | 1 | n/a |
|
||||
*-------------------------------
|
||||
*/
|
||||
|
||||
#define STIH4XX_RETIME_SRC_MASK GENMASK(8, 6)
|
||||
#define STIH4XX_ETH_SEL_TX_RETIME_CLK BIT(8)
|
||||
#define STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7)
|
||||
#define STIH4XX_ETH_SEL_TXCLK_NOT_CLK125 BIT(6)
|
||||
|
||||
/* STiD127 register definitions */
|
||||
|
||||
/**
|
||||
*-----------------------
|
||||
* src |BIT(6)| BIT(7)|
|
||||
*-----------------------
|
||||
* MII | 1 | n/a |
|
||||
*-----------------------
|
||||
* RMII | n/a | 1 |
|
||||
* clkgen| | |
|
||||
*-----------------------
|
||||
* RMII | n/a | 0 |
|
||||
* phyclk| | |
|
||||
*-----------------------
|
||||
* RGMII | 1 | n/a |
|
||||
* clkgen| | |
|
||||
*-----------------------
|
||||
*/
|
||||
|
||||
#define STID127_RETIME_SRC_MASK GENMASK(7, 6)
|
||||
#define STID127_ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7)
|
||||
#define STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK BIT(6)
|
||||
|
||||
#define ENMII_MASK GENMASK(5, 5)
|
||||
#define ENMII BIT(5)
|
||||
#define EN_MASK GENMASK(1, 1)
|
||||
#define EN BIT(1)
|
||||
|
||||
/**
|
||||
* 3 bits [4:2]
|
||||
* 000-GMII/MII
|
||||
* 001-RGMII
|
||||
* 010-SGMII
|
||||
* 100-RMII
|
||||
*/
|
||||
#define MII_PHY_SEL_MASK GENMASK(4, 2)
|
||||
#define ETH_PHY_SEL_RMII BIT(4)
|
||||
#define ETH_PHY_SEL_SGMII BIT(3)
|
||||
#define ETH_PHY_SEL_RGMII BIT(2)
|
||||
#define ETH_PHY_SEL_GMII 0x0
|
||||
#define ETH_PHY_SEL_MII 0x0
|
||||
|
||||
struct sti_dwmac {
|
||||
int interface; /* MII interface */
|
||||
bool ext_phyclk; /* Clock from external PHY */
|
||||
u32 tx_retime_src; /* TXCLK Retiming*/
|
||||
struct clk *clk; /* PHY clock */
|
||||
int ctrl_reg; /* GMAC glue-logic control register */
|
||||
int clk_sel_reg; /* GMAC ext clk selection register */
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
u32 speed;
|
||||
};
|
||||
|
||||
static u32 phy_intf_sels[] = {
|
||||
[PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII,
|
||||
[PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII,
|
||||
[PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII,
|
||||
[PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII,
|
||||
[PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII,
|
||||
[PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII,
|
||||
};
|
||||
|
||||
enum {
|
||||
TX_RETIME_SRC_NA = 0,
|
||||
TX_RETIME_SRC_TXCLK = 1,
|
||||
TX_RETIME_SRC_CLK_125,
|
||||
TX_RETIME_SRC_PHYCLK,
|
||||
TX_RETIME_SRC_CLKGEN,
|
||||
};
|
||||
|
||||
static u32 stih4xx_tx_retime_val[] = {
|
||||
[TX_RETIME_SRC_TXCLK] = STIH4XX_ETH_SEL_TXCLK_NOT_CLK125,
|
||||
[TX_RETIME_SRC_CLK_125] = 0x0,
|
||||
[TX_RETIME_SRC_PHYCLK] = STIH4XX_ETH_SEL_TX_RETIME_CLK,
|
||||
[TX_RETIME_SRC_CLKGEN] = STIH4XX_ETH_SEL_TX_RETIME_CLK
|
||||
| STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
|
||||
};
|
||||
|
||||
static void stih4xx_fix_retime_src(void *priv, u32 spd)
|
||||
{
|
||||
struct sti_dwmac *dwmac = priv;
|
||||
u32 src = dwmac->tx_retime_src;
|
||||
u32 reg = dwmac->ctrl_reg;
|
||||
u32 freq = 0;
|
||||
|
||||
if (dwmac->interface == PHY_INTERFACE_MODE_MII) {
|
||||
src = TX_RETIME_SRC_TXCLK;
|
||||
} else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
|
||||
if (dwmac->ext_phyclk) {
|
||||
src = TX_RETIME_SRC_PHYCLK;
|
||||
} else {
|
||||
src = TX_RETIME_SRC_CLKGEN;
|
||||
freq = DWMAC_50MHZ;
|
||||
}
|
||||
} else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) {
|
||||
/* On GiGa clk source can be either ext or from clkgen */
|
||||
if (spd == SPEED_1000) {
|
||||
freq = DWMAC_125MHZ;
|
||||
} else {
|
||||
/* Switch to clkgen for these speeds */
|
||||
src = TX_RETIME_SRC_CLKGEN;
|
||||
if (spd == SPEED_100)
|
||||
freq = DWMAC_25MHZ;
|
||||
else if (spd == SPEED_10)
|
||||
freq = DWMAC_2_5MHZ;
|
||||
}
|
||||
}
|
||||
|
||||
if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk && freq)
|
||||
clk_set_rate(dwmac->clk, freq);
|
||||
|
||||
regmap_update_bits(dwmac->regmap, reg, STIH4XX_RETIME_SRC_MASK,
|
||||
stih4xx_tx_retime_val[src]);
|
||||
}
|
||||
|
||||
static void stid127_fix_retime_src(void *priv, u32 spd)
|
||||
{
|
||||
struct sti_dwmac *dwmac = priv;
|
||||
u32 reg = dwmac->ctrl_reg;
|
||||
u32 freq = 0;
|
||||
u32 val = 0;
|
||||
|
||||
if (dwmac->interface == PHY_INTERFACE_MODE_MII) {
|
||||
val = STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK;
|
||||
} else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
|
||||
if (!dwmac->ext_phyclk) {
|
||||
val = STID127_ETH_SEL_INTERNAL_NOTEXT_PHYCLK;
|
||||
freq = DWMAC_50MHZ;
|
||||
}
|
||||
} else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) {
|
||||
val = STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK;
|
||||
if (spd == SPEED_1000)
|
||||
freq = DWMAC_125MHZ;
|
||||
else if (spd == SPEED_100)
|
||||
freq = DWMAC_25MHZ;
|
||||
else if (spd == SPEED_10)
|
||||
freq = DWMAC_2_5MHZ;
|
||||
}
|
||||
|
||||
if (dwmac->clk && freq)
|
||||
clk_set_rate(dwmac->clk, freq);
|
||||
|
||||
regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val);
|
||||
}
|
||||
|
||||
static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac)
|
||||
{
|
||||
struct regmap *regmap = dwmac->regmap;
|
||||
int iface = dwmac->interface;
|
||||
struct device *dev = dwmac->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 reg = dwmac->ctrl_reg;
|
||||
u32 val;
|
||||
|
||||
if (dwmac->clk)
|
||||
clk_prepare_enable(dwmac->clk);
|
||||
|
||||
if (of_property_read_bool(np, "st,gmac_en"))
|
||||
regmap_update_bits(regmap, reg, EN_MASK, EN);
|
||||
|
||||
regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]);
|
||||
|
||||
val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
|
||||
regmap_update_bits(regmap, reg, ENMII_MASK, val);
|
||||
}
|
||||
|
||||
static int stix4xx_init(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct sti_dwmac *dwmac = priv;
|
||||
u32 spd = dwmac->speed;
|
||||
|
||||
sti_dwmac_ctrl_init(dwmac);
|
||||
|
||||
stih4xx_fix_retime_src(priv, spd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stid127_init(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct sti_dwmac *dwmac = priv;
|
||||
u32 spd = dwmac->speed;
|
||||
|
||||
sti_dwmac_ctrl_init(dwmac);
|
||||
|
||||
stid127_fix_retime_src(priv, spd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sti_dwmac_exit(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct sti_dwmac *dwmac = priv;
|
||||
|
||||
if (dwmac->clk)
|
||||
clk_disable_unprepare(dwmac->clk);
|
||||
}
|
||||
static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct regmap *regmap;
|
||||
int err;
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
|
||||
if (!res)
|
||||
return -ENODATA;
|
||||
dwmac->ctrl_reg = res->start;
|
||||
|
||||
/* clk selection from extra syscfg register */
|
||||
dwmac->clk_sel_reg = -ENXIO;
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf");
|
||||
if (res)
|
||||
dwmac->clk_sel_reg = res->start;
|
||||
|
||||
regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
dwmac->dev = dev;
|
||||
dwmac->interface = of_get_phy_mode(np);
|
||||
dwmac->regmap = regmap;
|
||||
dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
|
||||
dwmac->tx_retime_src = TX_RETIME_SRC_NA;
|
||||
dwmac->speed = SPEED_100;
|
||||
|
||||
if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
|
||||
const char *rs;
|
||||
dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
|
||||
|
||||
err = of_property_read_string(np, "st,tx-retime-src", &rs);
|
||||
if (err < 0)
|
||||
dev_warn(dev, "Use internal clock source\n");
|
||||
|
||||
if (!strcasecmp(rs, "clk_125"))
|
||||
dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
|
||||
else if (!strcasecmp(rs, "txclk"))
|
||||
dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
|
||||
|
||||
dwmac->speed = SPEED_1000;
|
||||
}
|
||||
|
||||
dwmac->clk = devm_clk_get(dev, "sti-ethclk");
|
||||
if (IS_ERR(dwmac->clk)) {
|
||||
dev_warn(dev, "No phy clock provided...\n");
|
||||
dwmac->clk = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *sti_dwmac_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct sti_dwmac *dwmac;
|
||||
int ret;
|
||||
|
||||
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
||||
if (!dwmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = sti_dwmac_parse_data(dwmac, pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to parse OF data\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return dwmac;
|
||||
}
|
||||
|
||||
const struct stmmac_of_data stih4xx_dwmac_data = {
|
||||
.fix_mac_speed = stih4xx_fix_retime_src,
|
||||
.setup = sti_dwmac_setup,
|
||||
.init = stix4xx_init,
|
||||
.exit = sti_dwmac_exit,
|
||||
};
|
||||
|
||||
const struct stmmac_of_data stid127_dwmac_data = {
|
||||
.fix_mac_speed = stid127_fix_retime_src,
|
||||
.setup = sti_dwmac_setup,
|
||||
.init = stid127_init,
|
||||
.exit = sti_dwmac_exit,
|
||||
};
|
140
drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
Normal file
140
drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer
|
||||
*
|
||||
* Copyright (C) 2013 Chen-Yu Tsai
|
||||
*
|
||||
* Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
struct sunxi_priv_data {
|
||||
int interface;
|
||||
int clk_enabled;
|
||||
struct clk *tx_clk;
|
||||
struct regulator *regulator;
|
||||
};
|
||||
|
||||
static void *sun7i_gmac_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct sunxi_priv_data *gmac;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
|
||||
if (!gmac)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gmac->interface = of_get_phy_mode(dev->of_node);
|
||||
|
||||
gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
|
||||
if (IS_ERR(gmac->tx_clk)) {
|
||||
dev_err(dev, "could not get tx clock\n");
|
||||
return gmac->tx_clk;
|
||||
}
|
||||
|
||||
/* Optional regulator for PHY */
|
||||
gmac->regulator = devm_regulator_get_optional(dev, "phy");
|
||||
if (IS_ERR(gmac->regulator)) {
|
||||
if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
dev_info(dev, "no regulator found\n");
|
||||
gmac->regulator = NULL;
|
||||
}
|
||||
|
||||
return gmac;
|
||||
}
|
||||
|
||||
#define SUN7I_GMAC_GMII_RGMII_RATE 125000000
|
||||
#define SUN7I_GMAC_MII_RATE 25000000
|
||||
|
||||
static int sun7i_gmac_init(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct sunxi_priv_data *gmac = priv;
|
||||
int ret;
|
||||
|
||||
if (gmac->regulator) {
|
||||
ret = regulator_enable(gmac->regulator);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set GMAC interface port mode
|
||||
*
|
||||
* The GMAC TX clock lines are configured by setting the clock
|
||||
* rate, which then uses the auto-reparenting feature of the
|
||||
* clock driver, and enabling/disabling the clock.
|
||||
*/
|
||||
if (gmac->interface == PHY_INTERFACE_MODE_RGMII) {
|
||||
clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);
|
||||
clk_prepare_enable(gmac->tx_clk);
|
||||
gmac->clk_enabled = 1;
|
||||
} else {
|
||||
clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE);
|
||||
clk_prepare(gmac->tx_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sun7i_gmac_exit(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
struct sunxi_priv_data *gmac = priv;
|
||||
|
||||
if (gmac->clk_enabled) {
|
||||
clk_disable(gmac->tx_clk);
|
||||
gmac->clk_enabled = 0;
|
||||
}
|
||||
clk_unprepare(gmac->tx_clk);
|
||||
|
||||
if (gmac->regulator)
|
||||
regulator_disable(gmac->regulator);
|
||||
}
|
||||
|
||||
static void sun7i_fix_speed(void *priv, unsigned int speed)
|
||||
{
|
||||
struct sunxi_priv_data *gmac = priv;
|
||||
|
||||
/* only GMII mode requires us to reconfigure the clock lines */
|
||||
if (gmac->interface != PHY_INTERFACE_MODE_GMII)
|
||||
return;
|
||||
|
||||
if (gmac->clk_enabled) {
|
||||
clk_disable(gmac->tx_clk);
|
||||
gmac->clk_enabled = 0;
|
||||
}
|
||||
clk_unprepare(gmac->tx_clk);
|
||||
|
||||
if (speed == 1000) {
|
||||
clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);
|
||||
clk_prepare_enable(gmac->tx_clk);
|
||||
gmac->clk_enabled = 1;
|
||||
} else {
|
||||
clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE);
|
||||
clk_prepare(gmac->tx_clk);
|
||||
}
|
||||
}
|
||||
|
||||
/* of_data specifying hardware features and callbacks.
|
||||
* hardware features were copied from Allwinner drivers. */
|
||||
const struct stmmac_of_data sun7i_gmac_data = {
|
||||
.has_gmac = 1,
|
||||
.tx_coe = 1,
|
||||
.fix_mac_speed = sun7i_fix_speed,
|
||||
.setup = sun7i_gmac_setup,
|
||||
.init = sun7i_gmac_init,
|
||||
.exit = sun7i_gmac_exit,
|
||||
};
|
126
drivers/net/ethernet/stmicro/stmmac/dwmac100.h
Normal file
126
drivers/net/ethernet/stmicro/stmmac/dwmac100.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*******************************************************************************
|
||||
MAC 10/100 Header File
|
||||
|
||||
Copyright (C) 2007-2009 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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC100_H__
|
||||
#define __DWMAC100_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* MAC BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
/* MAC CSR offset */
|
||||
#define MAC_CONTROL 0x00000000 /* MAC Control */
|
||||
#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
|
||||
#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
|
||||
#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
|
||||
#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
|
||||
#define MAC_MII_ADDR 0x00000014 /* MII Address */
|
||||
#define MAC_MII_DATA 0x00000018 /* MII Data */
|
||||
#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
|
||||
#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
|
||||
#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
|
||||
|
||||
/* MAC CTRL defines */
|
||||
#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
|
||||
#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
|
||||
#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
|
||||
#define MAC_CONTROL_PS 0x08000000 /* Port Select */
|
||||
#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
|
||||
#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
|
||||
#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
|
||||
#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
|
||||
#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
|
||||
#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
|
||||
#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
|
||||
#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
|
||||
#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
|
||||
#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
|
||||
#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
|
||||
#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
|
||||
#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
|
||||
#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
|
||||
#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
|
||||
#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
|
||||
#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
|
||||
#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
|
||||
#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
|
||||
#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define MAC_CORE_INIT (MAC_CONTROL_HBD | MAC_CONTROL_ASTP)
|
||||
|
||||
/* MAC FLOW CTRL defines */
|
||||
#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define MAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
|
||||
#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
|
||||
#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* MII ADDR defines */
|
||||
#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* DMA BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
|
||||
#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
#define DMA_BUS_MODE_DEFAULT 0x00000000
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
|
||||
|
||||
/* Transmit Threshold Control */
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
|
||||
DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
|
||||
DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
|
||||
DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
|
||||
DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
|
||||
DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
|
||||
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
|
||||
};
|
||||
|
||||
/* STMAC110 DMA Missed Frame Counter register defines */
|
||||
#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
|
||||
#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
|
||||
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
|
||||
#endif /* __DWMAC100_H__ */
|
267
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
Normal file
267
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 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>
|
||||
*******************************************************************************/
|
||||
#ifndef __DWMAC1000_H__
|
||||
#define __DWMAC1000_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
#define GMAC_CONTROL 0x00000000 /* Configuration */
|
||||
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
|
||||
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
|
||||
#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
|
||||
#define GMAC_MII_ADDR 0x00000010 /* MII Address */
|
||||
#define GMAC_MII_DATA 0x00000014 /* MII Data */
|
||||
#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
|
||||
#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
|
||||
|
||||
#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,
|
||||
mmc_rx_irq = 0x0020,
|
||||
mmc_irq = 0x0010,
|
||||
pmt_irq = 0x0008,
|
||||
pcs_ane_irq = 0x0004,
|
||||
pcs_link_irq = 0x0002,
|
||||
rgmii_irq = 0x0001,
|
||||
};
|
||||
#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
|
||||
|
||||
/* PMT Control and Status */
|
||||
#define GMAC_PMT 0x0000002c
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
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) (((reg > 15) ? 0x00000800 : 0x00000040) + \
|
||||
(reg * 8))
|
||||
#define GMAC_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \
|
||||
(reg * 8))
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 1
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offset */
|
||||
#define GMAC_AN_CTRL 0x000000c0 /* AN control */
|
||||
#define GMAC_AN_STATUS 0x000000c4 /* AN status */
|
||||
#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
|
||||
#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */
|
||||
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
|
||||
#define GMAC_TBI 0x000000d4 /* TBI extend status */
|
||||
#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
|
||||
|
||||
/* Register 54 (SGMII/RGMII status register) */
|
||||
#define GMAC_S_R_GMII_LINK 0x8
|
||||
#define GMAC_S_R_GMII_SPEED 0x5
|
||||
#define GMAC_S_R_GMII_SPEED_SHIFT 0x1
|
||||
#define GMAC_S_R_GMII_MODE 0x1
|
||||
#define GMAC_S_R_GMII_SPEED_125 2
|
||||
#define GMAC_S_R_GMII_SPEED_25 1
|
||||
|
||||
/* Common ADV and LPA defines */
|
||||
#define GMAC_ANE_FD (1 << 5)
|
||||
#define GMAC_ANE_HD (1 << 6)
|
||||
#define GMAC_ANE_PSE (3 << 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_2K 0x08000000 /* IEEE 802.3as 2K packets */
|
||||
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
|
||||
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
|
||||
#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */
|
||||
#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */
|
||||
#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
|
||||
enum inter_frame_gap {
|
||||
GMAC_CONTROL_IFG_88 = 0x00040000,
|
||||
GMAC_CONTROL_IFG_80 = 0x00020000,
|
||||
GMAC_CONTROL_IFG_40 = 0x000e0000,
|
||||
};
|
||||
#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense */
|
||||
#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
|
||||
#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
|
||||
#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
|
||||
#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
|
||||
#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
|
||||
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
|
||||
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
|
||||
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
|
||||
#define GMAC_CONTROL_ACS 0x00000080 /* Auto Pad/FCS Stripping */
|
||||
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
|
||||
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
|
||||
GMAC_CONTROL_BE | GMAC_CONTROL_DCRS)
|
||||
|
||||
/* GMAC Frame Filter defines */
|
||||
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
|
||||
#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
|
||||
#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
|
||||
#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
|
||||
#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
|
||||
#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
|
||||
#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
|
||||
#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
|
||||
/* GMII ADDR defines */
|
||||
#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
/* GMAC FLOW CTRL defines */
|
||||
#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define GMAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/*--- DMA BLOCK defines ---*/
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
/* Programmable burst length (passed thorugh platform)*/
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
|
||||
|
||||
enum rx_tx_priority_ratio {
|
||||
double_ratio = 0x00004000, /* 2:1 */
|
||||
triple_ratio = 0x00008000, /* 3:1 */
|
||||
quadruple_ratio = 0x0000c000, /* 4:1 */
|
||||
};
|
||||
|
||||
#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
|
||||
#define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */
|
||||
#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 17
|
||||
#define DMA_BUS_MODE_USP 0x00800000
|
||||
#define DMA_BUS_MODE_PBL 0x01000000
|
||||
#define DMA_BUS_MODE_AAL 0x02000000
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
|
||||
#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
|
||||
#define DMA_BUS_PR_RATIO_SHIFT 14
|
||||
#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
|
||||
|
||||
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
|
||||
/* Disable Drop TCP/IP csum error */
|
||||
#define DMA_CONTROL_DT 0x04000000
|
||||
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
|
||||
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
|
||||
/* Threshold for Activating the FC */
|
||||
enum rfa {
|
||||
act_full_minus_1 = 0x00800000,
|
||||
act_full_minus_2 = 0x00800200,
|
||||
act_full_minus_3 = 0x00800400,
|
||||
act_full_minus_4 = 0x00800600,
|
||||
};
|
||||
/* Threshold for Deactivating the FC */
|
||||
enum rfd {
|
||||
deac_full_minus_1 = 0x00400000,
|
||||
deac_full_minus_2 = 0x00400800,
|
||||
deac_full_minus_3 = 0x00401000,
|
||||
deac_full_minus_4 = 0x00401800,
|
||||
};
|
||||
#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
|
||||
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_64 = 0x00000000,
|
||||
DMA_CONTROL_TTC_128 = 0x00004000,
|
||||
DMA_CONTROL_TTC_192 = 0x00008000,
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000,
|
||||
DMA_CONTROL_TTC_40 = 0x00010000,
|
||||
DMA_CONTROL_TTC_32 = 0x00014000,
|
||||
DMA_CONTROL_TTC_24 = 0x00018000,
|
||||
DMA_CONTROL_TTC_16 = 0x0001c000,
|
||||
};
|
||||
#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
|
||||
|
||||
#define DMA_CONTROL_EFC 0x00000100
|
||||
#define DMA_CONTROL_FEF 0x00000080
|
||||
#define DMA_CONTROL_FUF 0x00000040
|
||||
|
||||
enum rtc_control {
|
||||
DMA_CONTROL_RTC_64 = 0x00000000,
|
||||
DMA_CONTROL_RTC_32 = 0x00000008,
|
||||
DMA_CONTROL_RTC_96 = 0x00000010,
|
||||
DMA_CONTROL_RTC_128 = 0x00000018,
|
||||
};
|
||||
#define DMA_CONTROL_TC_RX_MASK 0xffffffe7
|
||||
|
||||
#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */
|
||||
|
||||
/* MMC registers offset */
|
||||
#define GMAC_MMC_CTRL 0x100
|
||||
#define GMAC_MMC_RX_INTR 0x104
|
||||
#define GMAC_MMC_TX_INTR 0x108
|
||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||
#define GMAC_EXTHASH_BASE 0x500
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
#endif /* __DWMAC1000_H__ */
|
444
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
Normal file
444
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
Normal file
|
@ -0,0 +1,444 @@
|
|||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 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/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac1000.h"
|
||||
|
||||
static void dwmac1000_core_init(struct mac_device_info *hw, int mtu)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
value |= GMAC_CORE_INIT;
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONTROL_2K;
|
||||
if (mtu > 2000)
|
||||
value |= GMAC_CONTROL_JE;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
/* Mask GMAC interrupts */
|
||||
writel(0x207, ioaddr + GMAC_INT_MASK);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
/* Tag detection without filtering */
|
||||
writel(0x0, ioaddr + GMAC_VLAN_TAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
if (hw->rx_csum)
|
||||
value |= GMAC_CONTROL_IPC;
|
||||
else
|
||||
value &= ~GMAC_CONTROL_IPC;
|
||||
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
return !!(value & GMAC_CONTROL_IPC);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_regs(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
int i;
|
||||
pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
int offset = i * 4;
|
||||
pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
|
||||
offset, readl(ioaddr + offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits,
|
||||
int mcbitslog2)
|
||||
{
|
||||
int numhashregs, regs;
|
||||
|
||||
switch (mcbitslog2) {
|
||||
case 6:
|
||||
writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW);
|
||||
writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH);
|
||||
return;
|
||||
break;
|
||||
case 7:
|
||||
numhashregs = 4;
|
||||
break;
|
||||
case 8:
|
||||
numhashregs = 8;
|
||||
break;
|
||||
default:
|
||||
pr_debug("STMMAC: err in setting mulitcast filter\n");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
for (regs = 0; regs < numhashregs; regs++)
|
||||
writel(mcfilterbits[regs],
|
||||
ioaddr + GMAC_EXTHASH_BASE + regs * 4);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
unsigned int value = 0;
|
||||
unsigned int perfect_addr_number = hw->unicast_filter_entries;
|
||||
u32 mc_filter[8];
|
||||
int mcbitslog2 = hw->mcast_bits_log2;
|
||||
|
||||
pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
|
||||
netdev_mc_count(dev), netdev_uc_count(dev));
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value = GMAC_FRAME_FILTER_PR;
|
||||
} else if (dev->flags & IFF_ALLMULTI) {
|
||||
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
|
||||
} else if (!netdev_mc_empty(dev)) {
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Hash filter for multicast */
|
||||
value = GMAC_FRAME_FILTER_HMC;
|
||||
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper n bits of the calculated CRC are used to
|
||||
* index the contents of the hash table. The number of
|
||||
* bits used depends on the hardware configuration
|
||||
* selected at core configuration time.
|
||||
*/
|
||||
int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
|
||||
ETH_ALEN)) >>
|
||||
(32 - mcbitslog2);
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
}
|
||||
|
||||
dwmac1000_set_mchash(ioaddr, mc_filter, mcbitslog2);
|
||||
|
||||
/* Handle multiple unicast addresses (perfect filtering) */
|
||||
if (netdev_uc_count(dev) > perfect_addr_number)
|
||||
/* Switch to promiscuous mode if more than unicast
|
||||
* addresses are requested than supported by hardware.
|
||||
*/
|
||||
value |= GMAC_FRAME_FILTER_PR;
|
||||
else {
|
||||
int reg = 1;
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
netdev_for_each_uc_addr(ha, dev) {
|
||||
stmmac_set_mac_addr(ioaddr, ha->addr,
|
||||
GMAC_ADDR_HIGH(reg),
|
||||
GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FRAME_FILTER_DEBUG
|
||||
/* Enable Receive all mode (to debug filtering_fail errors) */
|
||||
value |= GMAC_FRAME_FILTER_RA;
|
||||
#endif
|
||||
writel(value, ioaddr + GMAC_FRAME_FILTER);
|
||||
}
|
||||
|
||||
|
||||
static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int flow = 0;
|
||||
|
||||
pr_debug("GMAC Flow-Control:\n");
|
||||
if (fc & FLOW_RX) {
|
||||
pr_debug("\tReceive Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_RFE;
|
||||
}
|
||||
if (fc & FLOW_TX) {
|
||||
pr_debug("\tTransmit Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_TFE;
|
||||
}
|
||||
|
||||
if (duplex) {
|
||||
pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
|
||||
flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
|
||||
}
|
||||
|
||||
writel(flow, ioaddr + GMAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int pmt = 0;
|
||||
|
||||
if (mode & WAKE_MAGIC) {
|
||||
pr_debug("GMAC: WOL Magic frame\n");
|
||||
pmt |= power_down | magic_pkt_en;
|
||||
}
|
||||
if (mode & WAKE_UCAST) {
|
||||
pr_debug("GMAC: WOL on global unicast\n");
|
||||
pmt |= global_unicast;
|
||||
}
|
||||
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
|
||||
int ret = 0;
|
||||
|
||||
/* Not used events (e.g. MMC interrupts) are not handled. */
|
||||
if ((intr_status & mmc_tx_irq))
|
||||
x->mmc_tx_irq_n++;
|
||||
if (unlikely(intr_status & mmc_rx_irq))
|
||||
x->mmc_rx_irq_n++;
|
||||
if (unlikely(intr_status & mmc_rx_csum_offload_irq))
|
||||
x->mmc_rx_csum_offload_irq_n++;
|
||||
if (unlikely(intr_status & pmt_irq)) {
|
||||
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
/* MAC trx/rx EEE LPI entry/exit interrupts */
|
||||
if (intr_status & lpiis_irq) {
|
||||
/* Clean LPI interrupt by reading the Reg 12 */
|
||||
ret = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEN)
|
||||
x->irq_tx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEX)
|
||||
x->irq_tx_path_exit_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEN)
|
||||
x->irq_rx_path_in_lpi_mode_n++;
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEX)
|
||||
x->irq_rx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
|
||||
if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
|
||||
readl(ioaddr + GMAC_AN_STATUS);
|
||||
x->irq_pcs_ane_n++;
|
||||
}
|
||||
if (intr_status & rgmii_irq) {
|
||||
u32 status = readl(ioaddr + GMAC_S_R_GMII);
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Save and dump the link status. */
|
||||
if (status & GMAC_S_R_GMII_LINK) {
|
||||
int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
|
||||
GMAC_S_R_GMII_SPEED_SHIFT;
|
||||
x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
|
||||
|
||||
if (speed_value == GMAC_S_R_GMII_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_S_R_GMII_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_link = 1;
|
||||
pr_debug("%s: Link is Up - %d/%s\n", __func__,
|
||||
(int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_debug("%s: Link is Down\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_mode(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
/* Enable the link status receive on RGMII, SGMII ore SMII
|
||||
* receive path and instruct the transmit to enter in LPI
|
||||
* state.
|
||||
*/
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (link)
|
||||
value |= LPI_CTRL_STATUS_PLS;
|
||||
else
|
||||
value &= ~LPI_CTRL_STATUS_PLS;
|
||||
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
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 void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
/* auto negotiation enable and External Loopback enable */
|
||||
u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
|
||||
|
||||
if (restart)
|
||||
value |= GMAC_AN_CTRL_RAN;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV);
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA);
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac1000_ops = {
|
||||
.core_init = dwmac1000_core_init,
|
||||
.rx_ipc = dwmac1000_rx_ipc_enable,
|
||||
.dump_regs = dwmac1000_dump_regs,
|
||||
.host_irq_status = dwmac1000_irq_status,
|
||||
.set_filter = dwmac1000_set_filter,
|
||||
.flow_ctrl = dwmac1000_flow_ctrl,
|
||||
.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,
|
||||
.ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.get_adv = dwmac1000_get_adv,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
|
||||
int perfect_uc_entries)
|
||||
{
|
||||
struct mac_device_info *mac;
|
||||
u32 hwid = readl(ioaddr + GMAC_VERSION);
|
||||
|
||||
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
mac->pcsr = ioaddr;
|
||||
mac->multicast_filter_bins = mcbins;
|
||||
mac->unicast_filter_entries = perfect_uc_entries;
|
||||
mac->mcast_bits_log2 = 0;
|
||||
|
||||
if (mac->multicast_filter_bins)
|
||||
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
|
||||
|
||||
mac->mac = &dwmac1000_ops;
|
||||
mac->dma = &dwmac1000_dma_ops;
|
||||
|
||||
mac->link.port = GMAC_CONTROL_PS;
|
||||
mac->link.duplex = GMAC_CONTROL_DM;
|
||||
mac->link.speed = GMAC_CONTROL_FES;
|
||||
mac->mii.addr = GMAC_MII_ADDR;
|
||||
mac->mii.data = GMAC_MII_DATA;
|
||||
mac->synopsys_uid = hwid;
|
||||
|
||||
return mac;
|
||||
}
|
201
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
Normal file
201
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 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 <asm/io.h>
|
||||
#include "dwmac1000.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
int limit;
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Set the DMA PBL (Programmable Burst Length) mode
|
||||
* Before stmmac core 3.50 this mode bit was 4xPBL, and
|
||||
* post 3.5 mode bit acts as 8*PBL.
|
||||
* For core rev < 3.5, when the core is set for 4xPBL mode, the
|
||||
* DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats
|
||||
* depending on pbl value.
|
||||
* For core rev > 3.5, when the core is set for 8xPBL mode, the
|
||||
* DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
|
||||
* depending on pbl value.
|
||||
*/
|
||||
value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
|
||||
(pbl << DMA_BUS_MODE_RPBL_SHIFT));
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (fb)
|
||||
value |= DMA_BUS_MODE_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (mb)
|
||||
value |= DMA_BUS_MODE_MB;
|
||||
|
||||
#ifdef CONFIG_STMMAC_DA
|
||||
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
|
||||
#endif
|
||||
|
||||
if (atds)
|
||||
value |= DMA_BUS_MODE_ATDS;
|
||||
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
|
||||
* for supported bursts.
|
||||
*
|
||||
* Note: This is applicable only for revision GMACv3.61a. For
|
||||
* older version this register is reserved and shall have no
|
||||
* effect.
|
||||
*
|
||||
* Note:
|
||||
* For Fixed Burst Mode: if we directly write 0xFF to this
|
||||
* register using the configurations pass from platform code,
|
||||
* this would ensure that all bursts supported by core are set
|
||||
* and those which are not supported would remain ineffective.
|
||||
*
|
||||
* For Non Fixed Burst Mode: provide the maximum value of the
|
||||
* burst length. Any burst equal or below the provided burst
|
||||
* length would be allowed to perform.
|
||||
*/
|
||||
writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
|
||||
/* RX/TX descriptor base address lists must be written into
|
||||
* DMA CSR3 and CSR4, respectively
|
||||
*/
|
||||
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
|
||||
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
|
||||
int rxmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (txmode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
csr6 |= DMA_CONTROL_TSF;
|
||||
/* Operating on second frame increase the performance
|
||||
* especially when transmit store-and-forward is used.
|
||||
*/
|
||||
csr6 |= DMA_CONTROL_OSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
|
||||
csr6 &= ~DMA_CONTROL_TSF;
|
||||
csr6 &= DMA_CONTROL_TC_TX_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (txmode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (txmode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else if (txmode <= 128)
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
else if (txmode <= 192)
|
||||
csr6 |= DMA_CONTROL_TTC_192;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_256;
|
||||
}
|
||||
|
||||
if (rxmode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable RX store and forward mode\n");
|
||||
csr6 |= DMA_CONTROL_RSF;
|
||||
} else {
|
||||
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
|
||||
csr6 &= ~DMA_CONTROL_RSF;
|
||||
csr6 &= DMA_CONTROL_TC_RX_MASK;
|
||||
if (rxmode <= 32)
|
||||
csr6 |= DMA_CONTROL_RTC_32;
|
||||
else if (rxmode <= 64)
|
||||
csr6 |= DMA_CONTROL_RTC_64;
|
||||
else if (rxmode <= 96)
|
||||
csr6 |= DMA_CONTROL_RTC_96;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_RTC_128;
|
||||
}
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
pr_info(" DMA registers\n");
|
||||
for (i = 0; i < 22; i++) {
|
||||
if ((i < 9) || (i > 17)) {
|
||||
int offset = i * 4;
|
||||
pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
|
||||
(DMA_BUS_MODE + offset),
|
||||
readl(ioaddr + DMA_BUS_MODE + offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
|
||||
{
|
||||
return readl(ioaddr + DMA_HW_FEATURE);
|
||||
}
|
||||
|
||||
static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
|
||||
{
|
||||
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac1000_dma_ops = {
|
||||
.init = dwmac1000_dma_init,
|
||||
.dump_regs = dwmac1000_dump_dma_regs,
|
||||
.dma_mode = dwmac1000_dma_operation_mode,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
.get_hw_feature = dwmac1000_get_hw_feature,
|
||||
.rx_watchdog = dwmac1000_rx_watchdog,
|
||||
};
|
198
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
Normal file
198
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 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/crc32.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
|
||||
static void dwmac100_core_init(struct mac_device_info *hw, int mtu)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dwmac100_dump_mac_regs(struct mac_device_info *hw)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
pr_info("\t----------------------------------------------\n"
|
||||
"\t DWMAC 100 CSR (base addr = 0x%p)\n"
|
||||
"\t----------------------------------------------\n", ioaddr);
|
||||
pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
|
||||
readl(ioaddr + MAC_CONTROL));
|
||||
pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
|
||||
readl(ioaddr + MAC_ADDR_HIGH));
|
||||
pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
|
||||
readl(ioaddr + MAC_ADDR_LOW));
|
||||
pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
|
||||
MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
|
||||
pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
|
||||
MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
|
||||
pr_info("\tflow control (offset 0x%x): 0x%08x\n",
|
||||
MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
|
||||
pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
|
||||
readl(ioaddr + MAC_VLAN1));
|
||||
pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
|
||||
readl(ioaddr + MAC_VLAN2));
|
||||
}
|
||||
|
||||
static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac100_irq_status(struct mac_device_info *hw,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac100_set_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_get_umac_addr(struct mac_device_info *hw,
|
||||
unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_set_filter(struct mac_device_info *hw,
|
||||
struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value |= MAC_CONTROL_PR;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
|
||||
MAC_CONTROL_HP);
|
||||
} else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|
||||
|| (dev->flags & IFF_ALLMULTI)) {
|
||||
value |= MAC_CONTROL_PM;
|
||||
value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_LOW);
|
||||
} else if (netdev_mc_empty(dev)) { /* no multicast */
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
|
||||
MAC_CONTROL_HO | MAC_CONTROL_HP);
|
||||
} else {
|
||||
u32 mc_filter[2];
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Perfect filter mode for physical address and Hash
|
||||
* filter for multicast
|
||||
*/
|
||||
value |= MAC_CONTROL_HP;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
|
||||
MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper 6 bits of the calculated CRC are used to
|
||||
* index the contens of the hash table
|
||||
*/
|
||||
int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
|
||||
writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
|
||||
|
||||
if (duplex)
|
||||
flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
|
||||
writel(flow, ioaddr + MAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
/* No PMT module supported on ST boards with this Eth chip. */
|
||||
static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac100_ops = {
|
||||
.core_init = dwmac100_core_init,
|
||||
.rx_ipc = dwmac100_rx_ipc_enable,
|
||||
.dump_regs = dwmac100_dump_mac_regs,
|
||||
.host_irq_status = dwmac100_irq_status,
|
||||
.set_filter = dwmac100_set_filter,
|
||||
.flow_ctrl = dwmac100_flow_ctrl,
|
||||
.pmt = dwmac100_pmt,
|
||||
.set_umac_addr = dwmac100_set_umac_addr,
|
||||
.get_umac_addr = dwmac100_get_umac_addr,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
|
||||
{
|
||||
struct mac_device_info *mac;
|
||||
|
||||
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
pr_info("\tDWMAC100\n");
|
||||
|
||||
mac->pcsr = ioaddr;
|
||||
mac->mac = &dwmac100_ops;
|
||||
mac->dma = &dwmac100_dma_ops;
|
||||
|
||||
mac->link.port = MAC_CONTROL_PS;
|
||||
mac->link.duplex = MAC_CONTROL_F;
|
||||
mac->link.speed = 0;
|
||||
mac->mii.addr = MAC_MII_ADDR;
|
||||
mac->mii.data = MAC_MII_DATA;
|
||||
mac->synopsys_uid = 0;
|
||||
|
||||
return mac;
|
||||
}
|
146
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
Normal file
146
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 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 <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
int limit;
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
/* Enable Application Access by writing to DMA CSR0 */
|
||||
writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
|
||||
ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
|
||||
/* RX/TX descriptor base addr lists must be written into
|
||||
* DMA CSR3 and CSR4, respectively
|
||||
*/
|
||||
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
|
||||
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Store and Forward capability is not used at all.
|
||||
*
|
||||
* The transmit threshold can be programmed by setting the TTC bits in the DMA
|
||||
* control register.
|
||||
*/
|
||||
static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
|
||||
int rxmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (txmode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (txmode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_debug("DWMAC 100 DMA CSR\n");
|
||||
for (i = 0; i < 9; i++)
|
||||
pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
|
||||
(DMA_BUS_MODE + i * 4),
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4));
|
||||
|
||||
pr_debug("\tCSR20 (0x%x): 0x%08x, CSR21 (0x%x): 0x%08x\n",
|
||||
DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR),
|
||||
DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
|
||||
}
|
||||
|
||||
/* DMA controller has two counters to track the number of the missed frames. */
|
||||
static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
|
||||
|
||||
if (unlikely(csr8)) {
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE) {
|
||||
stats->rx_over_errors += 0x800;
|
||||
x->rx_overflow_cntr += 0x800;
|
||||
} else {
|
||||
unsigned int ove_cntr;
|
||||
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
|
||||
stats->rx_over_errors += ove_cntr;
|
||||
x->rx_overflow_cntr += ove_cntr;
|
||||
}
|
||||
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
|
||||
stats->rx_missed_errors += 0xffff;
|
||||
x->rx_missed_cntr += 0xffff;
|
||||
} else {
|
||||
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
|
||||
stats->rx_missed_errors += miss_f;
|
||||
x->rx_missed_cntr += miss_f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac100_dma_ops = {
|
||||
.init = dwmac100_dma_init,
|
||||
.dump_regs = dwmac100_dump_dma_regs,
|
||||
.dma_mode = dwmac100_dma_operation_mode,
|
||||
.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
};
|
116
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
Normal file
116
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*******************************************************************************
|
||||
DWMAC DMA Header file.
|
||||
|
||||
Copyright (C) 2007-2009 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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC_DMA_H__
|
||||
#define __DWMAC_DMA_H__
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||
#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
|
||||
#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
|
||||
#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
|
||||
#define DMA_STATUS 0x00001014 /* Status Register */
|
||||
#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
|
||||
#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
|
||||
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
|
||||
/* Rx watchdog register */
|
||||
#define DMA_RX_WATCHDOG 0x00001024
|
||||
/* AXI Bus Mode */
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
#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 */
|
||||
#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
|
||||
|
||||
/* DMA Normal interrupt */
|
||||
#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
|
||||
#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
|
||||
|
||||
#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
|
||||
DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Abnormal interrupt */
|
||||
#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
|
||||
#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
|
||||
#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
|
||||
#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
|
||||
#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
|
||||
#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
|
||||
#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
|
||||
#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
|
||||
#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
|
||||
|
||||
#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
|
||||
DMA_INTR_ENA_UNE)
|
||||
|
||||
/* DMA default interrupt mask */
|
||||
#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 */
|
||||
#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
|
||||
#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
|
||||
#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
|
||||
#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
|
||||
#define DMA_STATUS_TS_SHIFT 20
|
||||
#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
|
||||
#define DMA_STATUS_RS_SHIFT 17
|
||||
#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
|
||||
#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
|
||||
#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
|
||||
#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
|
||||
#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
|
||||
#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
|
||||
#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
|
||||
#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
|
||||
#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
|
||||
#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
|
||||
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
|
||||
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
|
||||
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr);
|
||||
void dwmac_enable_dma_irq(void __iomem *ioaddr);
|
||||
void dwmac_disable_dma_irq(void __iomem *ioaddr);
|
||||
void dwmac_dma_start_tx(void __iomem *ioaddr);
|
||||
void dwmac_dma_stop_tx(void __iomem *ioaddr);
|
||||
void dwmac_dma_start_rx(void __iomem *ioaddr);
|
||||
void dwmac_dma_stop_rx(void __iomem *ioaddr);
|
||||
int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x);
|
||||
|
||||
#endif /* __DWMAC_DMA_H__ */
|
267
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
Normal file
267
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 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/io.h>
|
||||
#include "common.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#define GMAC_HI_REG_AE 0x80000000
|
||||
|
||||
/* CSR1 enables the transmit DMA to check for new descriptor */
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr)
|
||||
{
|
||||
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
|
||||
}
|
||||
|
||||
void dwmac_enable_dma_irq(void __iomem *ioaddr)
|
||||
{
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
void dwmac_disable_dma_irq(void __iomem *ioaddr)
|
||||
{
|
||||
writel(0, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
void dwmac_dma_start_tx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_tx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_start_rx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value |= DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_rx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
static void show_tx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- TX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- TX (Running):Fetching the Tx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- TX (Running): Waiting for end of tx\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- TX (Running): Reading the data "
|
||||
"and queuing the data into the Tx buf\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- TX (Suspended): Tx Buff Underflow "
|
||||
"or an unavailable Transmit descriptor\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- TX (Running): Closing Tx descriptor\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_rx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_debug("- RX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_debug("- RX (Running): Fetching the Rx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_debug("- RX (Running):Checking for end of pkt\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_debug("- RX (Running): Waiting for Rx pkt\n");
|
||||
break;
|
||||
case 4:
|
||||
pr_debug("- RX (Suspended): Unavailable Rx buf\n");
|
||||
break;
|
||||
case 5:
|
||||
pr_debug("- RX (Running): Closing Rx descriptor\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_debug("- RX(Running): Flushing the current frame"
|
||||
" from the Rx buf\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_debug("- RX (Running): Queuing the Rx frame"
|
||||
" from the Rx buf into memory\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int dwmac_dma_interrupt(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
int ret = 0;
|
||||
/* read the status register (CSR5) */
|
||||
u32 intr_status = readl(ioaddr + DMA_STATUS);
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
/* Enable it to monitor DMA rx/tx status in case of critical problems */
|
||||
pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
|
||||
show_tx_process_state(intr_status);
|
||||
show_rx_process_state(intr_status);
|
||||
#endif
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_STATUS_AIS)) {
|
||||
if (unlikely(intr_status & DMA_STATUS_UNF)) {
|
||||
ret = tx_hard_error_bump_tc;
|
||||
x->tx_undeflow_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_TJT))
|
||||
x->tx_jabber_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_OVF))
|
||||
x->rx_overflow_irq++;
|
||||
|
||||
if (unlikely(intr_status & DMA_STATUS_RU))
|
||||
x->rx_buf_unav_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RPS))
|
||||
x->rx_process_stopped_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_RWT))
|
||||
x->rx_watchdog_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_ETI))
|
||||
x->tx_early_irq++;
|
||||
if (unlikely(intr_status & DMA_STATUS_TPS)) {
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_FBI)) {
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_STATUS_NIS)) {
|
||||
x->normal_irq_n++;
|
||||
if (likely(intr_status & DMA_STATUS_RI)) {
|
||||
u32 value = readl(ioaddr + DMA_INTR_ENA);
|
||||
/* to schedule NAPI on real RIE event. */
|
||||
if (likely(value & DMA_INTR_ENA_RIE)) {
|
||||
x->rx_normal_irq_n++;
|
||||
ret |= handle_rx;
|
||||
}
|
||||
}
|
||||
if (likely(intr_status & DMA_STATUS_TI)) {
|
||||
x->tx_normal_irq_n++;
|
||||
ret |= handle_tx;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
}
|
||||
/* Optional hardware blocks, interrupts should be disabled */
|
||||
if (unlikely(intr_status &
|
||||
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
|
||||
pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
|
||||
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
|
||||
|
||||
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
|
||||
}
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers se have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
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)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
|
402
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
Normal file
402
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
Normal file
|
@ -0,0 +1,402 @@
|
|||
/*******************************************************************************
|
||||
This contains the functions to handle the enhanced descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 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/stmmac.h>
|
||||
#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)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.etx.error_summary)) {
|
||||
if (unlikely(p->des01.etx.jabber_timeout))
|
||||
x->tx_jabber++;
|
||||
|
||||
if (unlikely(p->des01.etx.frame_flushed)) {
|
||||
x->tx_frame_flushed++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.loss_carrier)) {
|
||||
x->tx_losscarrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.etx.no_carrier)) {
|
||||
x->tx_carrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.etx.late_collision))
|
||||
stats->collisions += p->des01.etx.collision_count;
|
||||
|
||||
if (unlikely(p->des01.etx.excessive_collisions))
|
||||
stats->collisions += p->des01.etx.collision_count;
|
||||
|
||||
if (unlikely(p->des01.etx.excessive_deferral))
|
||||
x->tx_deferred++;
|
||||
|
||||
if (unlikely(p->des01.etx.underflow_error)) {
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
x->tx_underflow++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.ip_header_error))
|
||||
x->tx_ip_header_error++;
|
||||
|
||||
if (unlikely(p->des01.etx.payload_error)) {
|
||||
x->tx_payload_error++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.deferred))
|
||||
x->tx_deferred++;
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.etx.vlan_frame)
|
||||
x->tx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.buffer1_size;
|
||||
}
|
||||
|
||||
static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
|
||||
{
|
||||
int ret = good_frame;
|
||||
u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
|
||||
|
||||
/* bits 5 7 0 | Frame status
|
||||
* ----------------------------------------------------------
|
||||
* 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
|
||||
* 1 0 0 | IPv4/6 No CSUM errorS.
|
||||
* 1 0 1 | IPv4/6 CSUM PAYLOAD error
|
||||
* 1 1 0 | IPv4/6 CSUM IP HR error
|
||||
* 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
|
||||
* 0 0 1 | IPv4/6 unsupported IP PAYLOAD
|
||||
* 0 1 1 | COE bypassed.. no IPv4/6 frame
|
||||
* 0 1 0 | Reserved.
|
||||
*/
|
||||
if (status == 0x0)
|
||||
ret = llc_snap;
|
||||
else if (status == 0x4)
|
||||
ret = good_frame;
|
||||
else if (status == 0x5)
|
||||
ret = csum_none;
|
||||
else if (status == 0x6)
|
||||
ret = csum_none;
|
||||
else if (status == 0x7)
|
||||
ret = csum_none;
|
||||
else if (status == 0x1)
|
||||
ret = discard_frame;
|
||||
else if (status == 0x3)
|
||||
ret = discard_frame;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p)
|
||||
{
|
||||
if (unlikely(p->basic.des01.erx.rx_mac_addr)) {
|
||||
if (p->des4.erx.ip_hdr_err)
|
||||
x->ip_hdr_err++;
|
||||
if (p->des4.erx.ip_payload_err)
|
||||
x->ip_payload_err++;
|
||||
if (p->des4.erx.ip_csum_bypassed)
|
||||
x->ip_csum_bypassed++;
|
||||
if (p->des4.erx.ipv4_pkt_rcvd)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (p->des4.erx.ipv6_pkt_rcvd)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
if (p->des4.erx.msg_type == RDES_EXT_SYNC)
|
||||
x->rx_msg_type_sync++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
|
||||
x->rx_msg_type_follow_up++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
|
||||
x->rx_msg_type_delay_req++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
|
||||
x->rx_msg_type_delay_resp++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_REQ)
|
||||
x->rx_msg_type_pdelay_req++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
|
||||
x->rx_msg_type_pdelay_resp++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->rx_msg_type_pdelay_follow_up++;
|
||||
else
|
||||
x->rx_msg_type_ext_no_ptp++;
|
||||
if (p->des4.erx.ptp_frame_type)
|
||||
x->ptp_frame_type++;
|
||||
if (p->des4.erx.ptp_ver)
|
||||
x->ptp_ver++;
|
||||
if (p->des4.erx.timestamp_dropped)
|
||||
x->timestamp_dropped++;
|
||||
if (p->des4.erx.av_pkt_rcvd)
|
||||
x->av_pkt_rcvd++;
|
||||
if (p->des4.erx.av_tagged_pkt_rcvd)
|
||||
x->av_tagged_pkt_rcvd++;
|
||||
if (p->des4.erx.vlan_tag_priority_val)
|
||||
x->vlan_tag_priority_val++;
|
||||
if (p->des4.erx.l3_filter_match)
|
||||
x->l3_filter_match++;
|
||||
if (p->des4.erx.l4_filter_match)
|
||||
x->l4_filter_match++;
|
||||
if (p->des4.erx.l3_l4_filter_no_match)
|
||||
x->l3_l4_filter_no_match++;
|
||||
}
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = good_frame;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.erx.error_summary)) {
|
||||
if (unlikely(p->des01.erx.descriptor_error)) {
|
||||
x->rx_desc++;
|
||||
stats->rx_length_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.overflow_error))
|
||||
x->rx_gmac_overflow++;
|
||||
|
||||
if (unlikely(p->des01.erx.ipc_csum_error))
|
||||
pr_err("\tIPC Csum Error/Giant frame\n");
|
||||
|
||||
if (unlikely(p->des01.erx.late_collision)) {
|
||||
stats->collisions++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.receive_watchdog))
|
||||
x->rx_watchdog++;
|
||||
|
||||
if (unlikely(p->des01.erx.error_gmii))
|
||||
x->rx_mii++;
|
||||
|
||||
if (unlikely(p->des01.erx.crc_error)) {
|
||||
x->rx_crc++;
|
||||
stats->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
/* After a payload csum error, the ES bit is set.
|
||||
* It doesn't match with the information reported into the databook.
|
||||
* At any rate, we need to understand if the CSUM hw computation is ok
|
||||
* and report this info to the upper layers. */
|
||||
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
|
||||
p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
|
||||
|
||||
if (unlikely(p->des01.erx.dribbling))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(p->des01.erx.sa_filter_fail)) {
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.erx.da_filter_fail)) {
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.erx.length_error)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.erx.vlan_tag)
|
||||
x->rx_vlan++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end)
|
||||
{
|
||||
p->des01.erx.own = 1;
|
||||
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ehn_desc_rx_set_on_ring(p, end);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des01.erx.disable_ic = 1;
|
||||
}
|
||||
|
||||
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des01.etx.own = 0;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_tx_set_on_chain(p, end);
|
||||
else
|
||||
ehn_desc_tx_set_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.own;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.erx.own;
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.own = 1;
|
||||
}
|
||||
|
||||
static void enh_desc_set_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.erx.own = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.last_segment;
|
||||
}
|
||||
|
||||
static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = p->des01.etx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p, ter);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode)
|
||||
{
|
||||
p->des01.etx.first_segment = is_fs;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
enh_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (likely(csum_flag))
|
||||
p->des01.etx.checksum_insertion = cic_full;
|
||||
}
|
||||
|
||||
static void enh_desc_clear_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.interrupt = 0;
|
||||
}
|
||||
|
||||
static void enh_desc_close_tx_desc(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.last_segment = 1;
|
||||
p->des01.etx.interrupt = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines. */
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
return p->des01.erx.frame_length - 2;
|
||||
else
|
||||
return p->des01.erx.frame_length;
|
||||
}
|
||||
|
||||
static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.time_stamp_enable = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.time_stamp_status;
|
||||
}
|
||||
|
||||
static u64 enh_desc_get_timestamp(void *desc, u32 ats)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
ns = p->des6;
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += p->des7 * 1000000000ULL;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
ns = p->des2;
|
||||
ns += p->des3 * 1000000000ULL;
|
||||
}
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_timestamp_status(void *desc, u32 ats)
|
||||
{
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
return p->basic.des01.erx.ipc_csum_error;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops enh_desc_ops = {
|
||||
.tx_status = enh_desc_get_tx_status,
|
||||
.rx_status = enh_desc_get_rx_status,
|
||||
.get_tx_len = enh_desc_get_tx_len,
|
||||
.init_rx_desc = enh_desc_init_rx_desc,
|
||||
.init_tx_desc = enh_desc_init_tx_desc,
|
||||
.get_tx_owner = enh_desc_get_tx_owner,
|
||||
.get_rx_owner = enh_desc_get_rx_owner,
|
||||
.release_tx_desc = enh_desc_release_tx_desc,
|
||||
.prepare_tx_desc = enh_desc_prepare_tx_desc,
|
||||
.clear_tx_ic = enh_desc_clear_tx_ic,
|
||||
.close_tx_desc = enh_desc_close_tx_desc,
|
||||
.get_tx_ls = enh_desc_get_tx_ls,
|
||||
.set_tx_owner = enh_desc_set_tx_owner,
|
||||
.set_rx_owner = enh_desc_set_rx_owner,
|
||||
.get_rx_frame_len = enh_desc_get_rx_frame_len,
|
||||
.rx_extended_status = enh_desc_get_ext_status,
|
||||
.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
|
||||
.get_timestamp = enh_desc_get_timestamp,
|
||||
.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
|
||||
};
|
135
drivers/net/ethernet/stmicro/stmmac/mmc.h
Normal file
135
drivers/net/ethernet/stmicro/stmmac/mmc.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*******************************************************************************
|
||||
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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MMC_H__
|
||||
#define __MMC_H__
|
||||
|
||||
/* 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_error;
|
||||
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;
|
||||
};
|
||||
|
||||
void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
|
||||
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
|
||||
void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||
|
||||
#endif /* __MMC_H__ */
|
267
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
Normal file
267
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*******************************************************************************
|
||||
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_DEFAULT_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_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_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_error += 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);
|
||||
}
|
273
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
Normal file
273
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*******************************************************************************
|
||||
This contains the functions to handle the normal descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 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/stmmac.h>
|
||||
#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)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.tx.error_summary)) {
|
||||
if (unlikely(p->des01.tx.underflow_error)) {
|
||||
x->tx_underflow++;
|
||||
stats->tx_fifo_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.tx.no_carrier)) {
|
||||
x->tx_carrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.tx.loss_carrier)) {
|
||||
x->tx_losscarrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely((p->des01.tx.excessive_deferral) ||
|
||||
(p->des01.tx.excessive_collisions) ||
|
||||
(p->des01.tx.late_collision)))
|
||||
stats->collisions += p->des01.tx.collision_count;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (p->des01.etx.vlan_frame)
|
||||
x->tx_vlan++;
|
||||
|
||||
if (unlikely(p->des01.tx.deferred))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.buffer1_size;
|
||||
}
|
||||
|
||||
/* This function verifies if each incoming frame has some errors
|
||||
* and, if required, updates the multicast statistics.
|
||||
* 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 = good_frame;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.rx.last_descriptor == 0)) {
|
||||
pr_warn("%s: Oversized frame spanned multiple buffers\n",
|
||||
__func__);
|
||||
stats->rx_length_errors++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.rx.error_summary)) {
|
||||
if (unlikely(p->des01.rx.descriptor_error))
|
||||
x->rx_desc++;
|
||||
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++;
|
||||
}
|
||||
if (unlikely(p->des01.rx.crc_error)) {
|
||||
x->rx_crc++;
|
||||
stats->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.rx.dribbling))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(p->des01.rx.length_error)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.rx.mii_error)) {
|
||||
x->rx_mii++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.rx.vlan_tag)
|
||||
x->vlan_tag++;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end)
|
||||
{
|
||||
p->des01.rx.own = 1;
|
||||
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_rx_set_on_ring(p, end);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des01.rx.disable_ic = 1;
|
||||
}
|
||||
|
||||
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des01.tx.own = 0;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_tx_set_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.own;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.rx.own;
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.own = 1;
|
||||
}
|
||||
|
||||
static void ndesc_set_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.rx.own = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.last_segment;
|
||||
}
|
||||
|
||||
static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = p->des01.tx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_end_tx_desc_on_chain(p, ter);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode)
|
||||
{
|
||||
p->des01.tx.first_segment = is_fs;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
norm_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
norm_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (likely(csum_flag))
|
||||
p->des01.tx.checksum_insertion = cic_full;
|
||||
}
|
||||
|
||||
static void ndesc_clear_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.interrupt = 0;
|
||||
}
|
||||
|
||||
static void ndesc_close_tx_desc(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.last_segment = 1;
|
||||
p->des01.tx.interrupt = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines. */
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
return p->des01.rx.frame_length - 2;
|
||||
else
|
||||
return p->des01.rx.frame_length;
|
||||
}
|
||||
|
||||
static void ndesc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.time_stamp_enable = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.time_stamp_status;
|
||||
}
|
||||
|
||||
static u64 ndesc_get_timestamp(void *desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = p->des2;
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += p->des3 * 1000000000ULL;
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
|
||||
if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops ndesc_ops = {
|
||||
.tx_status = ndesc_get_tx_status,
|
||||
.rx_status = ndesc_get_rx_status,
|
||||
.get_tx_len = ndesc_get_tx_len,
|
||||
.init_rx_desc = ndesc_init_rx_desc,
|
||||
.init_tx_desc = ndesc_init_tx_desc,
|
||||
.get_tx_owner = ndesc_get_tx_owner,
|
||||
.get_rx_owner = ndesc_get_rx_owner,
|
||||
.release_tx_desc = ndesc_release_tx_desc,
|
||||
.prepare_tx_desc = ndesc_prepare_tx_desc,
|
||||
.clear_tx_ic = ndesc_clear_tx_ic,
|
||||
.close_tx_desc = ndesc_close_tx_desc,
|
||||
.get_tx_ls = ndesc_get_tx_ls,
|
||||
.set_tx_owner = ndesc_set_tx_owner,
|
||||
.set_rx_owner = ndesc_set_rx_owner,
|
||||
.get_rx_frame_len = ndesc_get_rx_frame_len,
|
||||
.enable_tx_timestamp = ndesc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
|
||||
.get_timestamp = ndesc_get_timestamp,
|
||||
.get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
|
||||
};
|
142
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
Normal file
142
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*******************************************************************************
|
||||
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 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;
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
unsigned int bmax, len;
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(priv->dma_etx + entry);
|
||||
else
|
||||
desc = priv->dma_tx + entry;
|
||||
|
||||
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);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
|
||||
STMMAC_RING_MODE);
|
||||
wmb();
|
||||
priv->tx_skbuff[entry] = NULL;
|
||||
entry = (++priv->cur_tx) % txsize;
|
||||
|
||||
if (priv->extend_desc)
|
||||
desc = (struct dma_desc *)(priv->dma_etx + entry);
|
||||
else
|
||||
desc = priv->dma_tx + entry;
|
||||
|
||||
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
|
||||
len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
||||
STMMAC_RING_MODE);
|
||||
wmb();
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
} else {
|
||||
desc->des2 = dma_map_single(priv->device, skb->data,
|
||||
nopaged_len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(priv->device, desc->des2))
|
||||
return -1;
|
||||
priv->tx_skbuff_dma[entry].buf = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
|
||||
STMMAC_RING_MODE);
|
||||
}
|
||||
|
||||
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(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
/* Fill DES3 in case of RING mode */
|
||||
if (priv->dma_buf_sz >= 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(struct dma_desc *p)
|
||||
{
|
||||
p->des3 = p->des2 + BUF_SIZE_8KiB;
|
||||
}
|
||||
|
||||
static void stmmac_clean_desc3(void *priv_ptr, 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_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,
|
||||
.clean_desc3 = stmmac_clean_desc3,
|
||||
.set_16kib_bfsize = stmmac_set_16kib_bfsize,
|
||||
};
|
212
drivers/net/ethernet/stmicro/stmmac/stmmac.h
Normal file
212
drivers/net/ethernet/stmicro/stmmac/stmmac.h
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 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>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||
#define DRV_MODULE_VERSION "March_2013"
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pci.h>
|
||||
#include "common.h"
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
struct stmmac_tx_info {
|
||||
dma_addr_t buf;
|
||||
bool map_as_page;
|
||||
};
|
||||
|
||||
struct stmmac_priv {
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
|
||||
struct dma_desc *dma_tx;
|
||||
struct sk_buff **tx_skbuff;
|
||||
unsigned int cur_tx;
|
||||
unsigned int dirty_tx;
|
||||
unsigned int dma_tx_size;
|
||||
u32 tx_count_frames;
|
||||
u32 tx_coal_frames;
|
||||
u32 tx_coal_timer;
|
||||
struct stmmac_tx_info *tx_skbuff_dma;
|
||||
dma_addr_t dma_tx_phy;
|
||||
int tx_coalesce;
|
||||
int hwts_tx_en;
|
||||
spinlock_t tx_lock;
|
||||
bool tx_path_in_lpi_mode;
|
||||
struct timer_list txtimer;
|
||||
|
||||
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
|
||||
struct dma_extended_desc *dma_erx;
|
||||
struct sk_buff **rx_skbuff;
|
||||
unsigned int cur_rx;
|
||||
unsigned int dirty_rx;
|
||||
unsigned int dma_rx_size;
|
||||
unsigned int dma_buf_sz;
|
||||
u32 rx_riwt;
|
||||
int hwts_rx_en;
|
||||
dma_addr_t *rx_skbuff_dma;
|
||||
dma_addr_t dma_rx_phy;
|
||||
|
||||
struct napi_struct napi ____cacheline_aligned_in_smp;
|
||||
|
||||
void __iomem *ioaddr;
|
||||
struct net_device *dev;
|
||||
struct device *device;
|
||||
struct mac_device_info *hw;
|
||||
spinlock_t lock;
|
||||
|
||||
struct phy_device *phydev ____cacheline_aligned_in_smp;
|
||||
int oldlink;
|
||||
int speed;
|
||||
int oldduplex;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
int mii_irq[PHY_MAX_ADDR];
|
||||
|
||||
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
struct dma_features dma_cap;
|
||||
struct stmmac_counters mmc;
|
||||
int hw_cap_support;
|
||||
int synopsys_id;
|
||||
u32 msg_enable;
|
||||
int wolopts;
|
||||
int wol_irq;
|
||||
struct clk *stmmac_clk;
|
||||
struct reset_control *stmmac_rst;
|
||||
int clk_csr;
|
||||
struct timer_list eee_ctrl_timer;
|
||||
int lpi_irq;
|
||||
int eee_enabled;
|
||||
int eee_active;
|
||||
int tx_lpi_timer;
|
||||
int pcs;
|
||||
unsigned int mode;
|
||||
int extend_desc;
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_ops;
|
||||
unsigned int default_addend;
|
||||
struct clk *clk_ptp_ref;
|
||||
unsigned int clk_ptp_rate;
|
||||
u32 adv_ts;
|
||||
int use_riwt;
|
||||
int irq_wake;
|
||||
spinlock_t ptp_lock;
|
||||
};
|
||||
|
||||
int stmmac_mdio_unregister(struct net_device *ndev);
|
||||
int stmmac_mdio_register(struct net_device *ndev);
|
||||
int stmmac_mdio_reset(struct mii_bus *mii);
|
||||
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;
|
||||
extern const struct stmmac_hwtimestamp stmmac_ptp;
|
||||
int stmmac_ptp_register(struct stmmac_priv *priv);
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv);
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_STMMAC_PLATFORM
|
||||
#ifdef CONFIG_DWMAC_MESON
|
||||
extern const struct stmmac_of_data meson6_dwmac_data;
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_SUNXI
|
||||
extern const struct stmmac_of_data sun7i_gmac_data;
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_STI
|
||||
extern const struct stmmac_of_data stih4xx_dwmac_data;
|
||||
extern const struct stmmac_of_data stid127_dwmac_data;
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_SOCFPGA
|
||||
extern const struct stmmac_of_data socfpga_gmac_data;
|
||||
#endif
|
||||
extern struct platform_driver stmmac_pltfr_driver;
|
||||
static inline int stmmac_register_platform(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&stmmac_pltfr_driver);
|
||||
if (err)
|
||||
pr_err("stmmac: failed to register the platform driver\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_platform(void)
|
||||
{
|
||||
platform_driver_unregister(&stmmac_pltfr_driver);
|
||||
}
|
||||
#else
|
||||
static inline int stmmac_register_platform(void)
|
||||
{
|
||||
pr_debug("stmmac: do not register the platf driver\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_platform(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_PLATFORM */
|
||||
|
||||
#ifdef CONFIG_STMMAC_PCI
|
||||
extern struct pci_driver stmmac_pci_driver;
|
||||
static inline int stmmac_register_pci(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pci_register_driver(&stmmac_pci_driver);
|
||||
if (err)
|
||||
pr_err("stmmac: failed to register the PCI driver\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_pci(void)
|
||||
{
|
||||
pci_unregister_driver(&stmmac_pci_driver);
|
||||
}
|
||||
#else
|
||||
static inline int stmmac_register_pci(void)
|
||||
{
|
||||
pr_debug("stmmac: do not register the PCI driver\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_pci(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_PCI */
|
||||
|
||||
#endif /* __STMMAC_H__ */
|
778
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
Normal file
778
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
Normal file
|
@ -0,0 +1,778 @@
|
|||
/*******************************************************************************
|
||||
STMMAC Ethtool support
|
||||
|
||||
Copyright (C) 2007-2009 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/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1054
|
||||
#define MAC100_ETHTOOL_NAME "st_mac100"
|
||||
#define GMAC_ETHTOOL_NAME "st_gmac"
|
||||
|
||||
struct stmmac_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int sizeof_stat;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define STMMAC_STAT(m) \
|
||||
{ #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
|
||||
offsetof(struct stmmac_priv, xstats.m)}
|
||||
|
||||
static const struct stmmac_stats stmmac_gstrings_stats[] = {
|
||||
/* Transmit errors */
|
||||
STMMAC_STAT(tx_underflow),
|
||||
STMMAC_STAT(tx_carrier),
|
||||
STMMAC_STAT(tx_losscarrier),
|
||||
STMMAC_STAT(vlan_tag),
|
||||
STMMAC_STAT(tx_deferred),
|
||||
STMMAC_STAT(tx_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(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),
|
||||
STMMAC_STAT(rx_gmac_overflow),
|
||||
STMMAC_STAT(rx_watchdog),
|
||||
STMMAC_STAT(da_rx_filter_fail),
|
||||
STMMAC_STAT(sa_rx_filter_fail),
|
||||
STMMAC_STAT(rx_missed_cntr),
|
||||
STMMAC_STAT(rx_overflow_cntr),
|
||||
STMMAC_STAT(rx_vlan),
|
||||
/* Tx/Rx IRQ error info */
|
||||
STMMAC_STAT(tx_undeflow_irq),
|
||||
STMMAC_STAT(tx_process_stopped_irq),
|
||||
STMMAC_STAT(tx_jabber_irq),
|
||||
STMMAC_STAT(rx_overflow_irq),
|
||||
STMMAC_STAT(rx_buf_unav_irq),
|
||||
STMMAC_STAT(rx_process_stopped_irq),
|
||||
STMMAC_STAT(rx_watchdog_irq),
|
||||
STMMAC_STAT(tx_early_irq),
|
||||
STMMAC_STAT(fatal_bus_error_irq),
|
||||
/* Tx/Rx IRQ Events */
|
||||
STMMAC_STAT(rx_early_irq),
|
||||
STMMAC_STAT(threshold),
|
||||
STMMAC_STAT(tx_pkt_n),
|
||||
STMMAC_STAT(rx_pkt_n),
|
||||
STMMAC_STAT(normal_irq_n),
|
||||
STMMAC_STAT(rx_normal_irq_n),
|
||||
STMMAC_STAT(napi_poll),
|
||||
STMMAC_STAT(tx_normal_irq_n),
|
||||
STMMAC_STAT(tx_clean),
|
||||
STMMAC_STAT(tx_reset_ic_bit),
|
||||
STMMAC_STAT(irq_receive_pmt_irq_n),
|
||||
/* MMC info */
|
||||
STMMAC_STAT(mmc_tx_irq_n),
|
||||
STMMAC_STAT(mmc_rx_irq_n),
|
||||
STMMAC_STAT(mmc_rx_csum_offload_irq_n),
|
||||
/* EEE */
|
||||
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),
|
||||
/* Extended RDES status */
|
||||
STMMAC_STAT(ip_hdr_err),
|
||||
STMMAC_STAT(ip_payload_err),
|
||||
STMMAC_STAT(ip_csum_bypassed),
|
||||
STMMAC_STAT(ipv4_pkt_rcvd),
|
||||
STMMAC_STAT(ipv6_pkt_rcvd),
|
||||
STMMAC_STAT(rx_msg_type_ext_no_ptp),
|
||||
STMMAC_STAT(rx_msg_type_sync),
|
||||
STMMAC_STAT(rx_msg_type_follow_up),
|
||||
STMMAC_STAT(rx_msg_type_delay_req),
|
||||
STMMAC_STAT(rx_msg_type_delay_resp),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_req),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_resp),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_follow_up),
|
||||
STMMAC_STAT(ptp_frame_type),
|
||||
STMMAC_STAT(ptp_ver),
|
||||
STMMAC_STAT(timestamp_dropped),
|
||||
STMMAC_STAT(av_pkt_rcvd),
|
||||
STMMAC_STAT(av_tagged_pkt_rcvd),
|
||||
STMMAC_STAT(vlan_tag_priority_val),
|
||||
STMMAC_STAT(l3_filter_match),
|
||||
STMMAC_STAT(l4_filter_match),
|
||||
STMMAC_STAT(l3_l4_filter_no_match),
|
||||
/* PCS */
|
||||
STMMAC_STAT(irq_pcs_ane_n),
|
||||
STMMAC_STAT(irq_pcs_link_n),
|
||||
STMMAC_STAT(irq_rgmii_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_error),
|
||||
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)
|
||||
strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
|
||||
else
|
||||
strlcpy(info->driver, MAC100_ETHTOOL_NAME,
|
||||
sizeof(info->driver));
|
||||
|
||||
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_getsettings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int rc;
|
||||
|
||||
if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
|
||||
struct rgmii_adv adv;
|
||||
|
||||
if (!priv->xstats.pcs_link) {
|
||||
ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
|
||||
cmd->duplex = DUPLEX_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
cmd->duplex = priv->xstats.pcs_duplex;
|
||||
|
||||
ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
|
||||
|
||||
/* Get and convert ADV/LP_ADV from the HW AN registers */
|
||||
if (!priv->hw->mac->get_adv)
|
||||
return -EOPNOTSUPP; /* should never happen indeed */
|
||||
|
||||
priv->hw->mac->get_adv(priv->hw, &adv);
|
||||
|
||||
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
|
||||
|
||||
if (adv.pause & STMMAC_PCS_PAUSE)
|
||||
cmd->advertising |= ADVERTISED_Pause;
|
||||
if (adv.pause & STMMAC_PCS_ASYM_PAUSE)
|
||||
cmd->advertising |= ADVERTISED_Asym_Pause;
|
||||
if (adv.lp_pause & STMMAC_PCS_PAUSE)
|
||||
cmd->lp_advertising |= ADVERTISED_Pause;
|
||||
if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE)
|
||||
cmd->lp_advertising |= ADVERTISED_Asym_Pause;
|
||||
|
||||
/* Reg49[3] always set because ANE is always supported */
|
||||
cmd->autoneg = ADVERTISED_Autoneg;
|
||||
cmd->supported |= SUPPORTED_Autoneg;
|
||||
cmd->advertising |= ADVERTISED_Autoneg;
|
||||
cmd->lp_advertising |= ADVERTISED_Autoneg;
|
||||
|
||||
if (adv.duplex) {
|
||||
cmd->supported |= (SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_10baseT_Full);
|
||||
cmd->advertising |= (ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Full);
|
||||
} else {
|
||||
cmd->supported |= (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_10baseT_Half);
|
||||
cmd->advertising |= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_10baseT_Half);
|
||||
}
|
||||
if (adv.lp_duplex)
|
||||
cmd->lp_advertising |= (ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Full);
|
||||
else
|
||||
cmd->lp_advertising |= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_10baseT_Half);
|
||||
cmd->port = PORT_OTHER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (phy == NULL) {
|
||||
pr_err("%s: %s: PHY is not registered\n",
|
||||
__func__, dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!netif_running(dev)) {
|
||||
pr_err("%s: interface is disabled: we cannot track "
|
||||
"link speed / duplex setting\n", dev->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
cmd->transceiver = XCVR_INTERNAL;
|
||||
rc = phy_ethtool_gset(phy, cmd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_setsettings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int rc;
|
||||
|
||||
if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
|
||||
u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
|
||||
|
||||
/* Only support ANE */
|
||||
if (cmd->autoneg != AUTONEG_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
mask &= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Half |
|
||||
ADVERTISED_10baseT_Full);
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
if (priv->hw->mac->ctrl_ane)
|
||||
priv->hw->mac->ctrl_ane(priv->hw, 1);
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
rc = phy_ethtool_sset(phy, cmd);
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
return priv->msg_enable;
|
||||
}
|
||||
|
||||
static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
priv->msg_enable = level;
|
||||
|
||||
}
|
||||
|
||||
static int stmmac_check_if_running(struct net_device *dev)
|
||||
{
|
||||
if (!netif_running(dev))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_get_regs_len(struct net_device *dev)
|
||||
{
|
||||
return REG_SPACE_SIZE;
|
||||
}
|
||||
|
||||
static void stmmac_ethtool_gregs(struct net_device *dev,
|
||||
struct ethtool_regs *regs, void *space)
|
||||
{
|
||||
int i;
|
||||
u32 *reg_space = (u32 *) space;
|
||||
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
memset(reg_space, 0x0, REG_SPACE_SIZE);
|
||||
|
||||
if (!priv->plat->has_gmac) {
|
||||
/* MAC registers */
|
||||
for (i = 0; i < 12; i++)
|
||||
reg_space[i] = readl(priv->ioaddr + (i * 4));
|
||||
/* DMA registers */
|
||||
for (i = 0; i < 9; i++)
|
||||
reg_space[i + 12] =
|
||||
readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
|
||||
reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR);
|
||||
reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR);
|
||||
} else {
|
||||
/* MAC registers */
|
||||
for (i = 0; i < 55; i++)
|
||||
reg_space[i] = readl(priv->ioaddr + (i * 4));
|
||||
/* DMA registers */
|
||||
for (i = 0; i < 22; i++)
|
||||
reg_space[i + 55] =
|
||||
readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stmmac_get_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return;
|
||||
|
||||
pause->rx_pause = 0;
|
||||
pause->tx_pause = 0;
|
||||
pause->autoneg = priv->phydev->autoneg;
|
||||
|
||||
if (priv->flow_ctrl & FLOW_RX)
|
||||
pause->rx_pause = 1;
|
||||
if (priv->flow_ctrl & FLOW_TX)
|
||||
pause->tx_pause = 1;
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
stmmac_set_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int new_pause = FLOW_OFF;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (pause->rx_pause)
|
||||
new_pause |= FLOW_RX;
|
||||
if (pause->tx_pause)
|
||||
new_pause |= FLOW_TX;
|
||||
|
||||
priv->flow_ctrl = new_pause;
|
||||
phy->autoneg = pause->autoneg;
|
||||
|
||||
if (phy->autoneg) {
|
||||
if (netif_running(netdev))
|
||||
ret = phy_start_aneg(phy);
|
||||
} else
|
||||
priv->hw->mac->flow_ctrl(priv->hw, phy->duplex,
|
||||
priv->flow_ctrl, priv->pause);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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, j = 0;
|
||||
|
||||
/* 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[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:
|
||||
len = STMMAC_STATS_LEN;
|
||||
|
||||
if (priv->dma_cap.rmon)
|
||||
len += STMMAC_MMC_STATS_LEN;
|
||||
|
||||
return len;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently only support WOL through Magic packet. */
|
||||
static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (device_can_wakeup(priv->device)) {
|
||||
wol->supported = WAKE_MAGIC | WAKE_UCAST;
|
||||
wol->wolopts = priv->wolopts;
|
||||
}
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
if (wol->wolopts & ~support)
|
||||
return -EINVAL;
|
||||
|
||||
if (wol->wolopts) {
|
||||
pr_info("stmmac: wakeup enable\n");
|
||||
device_set_wakeup_enable(priv->device, 1);
|
||||
enable_irq_wake(priv->wol_irq);
|
||||
} else {
|
||||
device_set_wakeup_enable(priv->device, 0);
|
||||
disable_irq_wake(priv->wol_irq);
|
||||
}
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->wolopts = wol->wolopts;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_op_get_eee(struct net_device *dev,
|
||||
struct ethtool_eee *edata)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!priv->dma_cap.eee)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
edata->eee_enabled = priv->eee_enabled;
|
||||
edata->eee_active = priv->eee_active;
|
||||
edata->tx_lpi_timer = priv->tx_lpi_timer;
|
||||
|
||||
return phy_ethtool_get_eee(priv->phydev, edata);
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_op_set_eee(struct net_device *dev,
|
||||
struct ethtool_eee *edata)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
priv->eee_enabled = edata->eee_enabled;
|
||||
|
||||
if (!priv->eee_enabled)
|
||||
stmmac_disable_eee_mode(priv);
|
||||
else {
|
||||
/* We are asking for enabling the EEE but it is safe
|
||||
* to verify all by invoking the eee_init function.
|
||||
* In case of failure it will return an error.
|
||||
*/
|
||||
priv->eee_enabled = stmmac_eee_init(priv);
|
||||
if (!priv->eee_enabled)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Do not change tx_lpi_timer in case of failure */
|
||||
priv->tx_lpi_timer = edata->tx_lpi_timer;
|
||||
}
|
||||
|
||||
return phy_ethtool_set_eee(priv->phydev, edata);
|
||||
}
|
||||
|
||||
static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
|
||||
{
|
||||
unsigned long clk = clk_get_rate(priv->stmmac_clk);
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return (usec * (clk / 1000000)) / 256;
|
||||
}
|
||||
|
||||
static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv)
|
||||
{
|
||||
unsigned long clk = clk_get_rate(priv->stmmac_clk);
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return (riwt * 256) / (clk / 1000000);
|
||||
}
|
||||
|
||||
static int stmmac_get_coalesce(struct net_device *dev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
ec->tx_coalesce_usecs = priv->tx_coal_timer;
|
||||
ec->tx_max_coalesced_frames = priv->tx_coal_frames;
|
||||
|
||||
if (priv->use_riwt)
|
||||
ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_set_coalesce(struct net_device *dev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
unsigned int rx_riwt;
|
||||
|
||||
/* Check not supported parameters */
|
||||
if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) ||
|
||||
(ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) ||
|
||||
(ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) ||
|
||||
(ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) ||
|
||||
(ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) ||
|
||||
(ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) ||
|
||||
(ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) ||
|
||||
(ec->rx_max_coalesced_frames_high) ||
|
||||
(ec->tx_max_coalesced_frames_irq) ||
|
||||
(ec->stats_block_coalesce_usecs) ||
|
||||
(ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ec->rx_coalesce_usecs == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ec->tx_coalesce_usecs == 0) &&
|
||||
(ec->tx_max_coalesced_frames == 0))
|
||||
return -EINVAL;
|
||||
|
||||
if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) ||
|
||||
(ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES))
|
||||
return -EINVAL;
|
||||
|
||||
rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv);
|
||||
|
||||
if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT))
|
||||
return -EINVAL;
|
||||
else if (!priv->use_riwt)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Only copy relevant parameters, ignore all others. */
|
||||
priv->tx_coal_frames = ec->tx_max_coalesced_frames;
|
||||
priv->tx_coal_timer = ec->tx_coalesce_usecs;
|
||||
priv->rx_riwt = rx_riwt;
|
||||
priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_get_ts_info(struct net_device *dev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) {
|
||||
|
||||
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
|
||||
if (priv->ptp_clock)
|
||||
info->phc_index = ptp_clock_index(priv->ptp_clock);
|
||||
|
||||
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
|
||||
|
||||
info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_ALL));
|
||||
return 0;
|
||||
} else
|
||||
return ethtool_op_get_ts_info(dev, info);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops stmmac_ethtool_ops = {
|
||||
.begin = stmmac_check_if_running,
|
||||
.get_drvinfo = stmmac_ethtool_getdrvinfo,
|
||||
.get_settings = stmmac_ethtool_getsettings,
|
||||
.set_settings = stmmac_ethtool_setsettings,
|
||||
.get_msglevel = stmmac_ethtool_getmsglevel,
|
||||
.set_msglevel = stmmac_ethtool_setmsglevel,
|
||||
.get_regs = stmmac_ethtool_gregs,
|
||||
.get_regs_len = stmmac_ethtool_get_regs_len,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_pauseparam = stmmac_get_pauseparam,
|
||||
.set_pauseparam = stmmac_set_pauseparam,
|
||||
.get_ethtool_stats = stmmac_get_ethtool_stats,
|
||||
.get_strings = stmmac_get_strings,
|
||||
.get_wol = stmmac_get_wol,
|
||||
.set_wol = stmmac_set_wol,
|
||||
.get_eee = stmmac_ethtool_op_get_eee,
|
||||
.set_eee = stmmac_ethtool_op_set_eee,
|
||||
.get_sset_count = stmmac_get_sset_count,
|
||||
.get_ts_info = stmmac_get_ts_info,
|
||||
.get_coalesce = stmmac_get_coalesce,
|
||||
.set_coalesce = stmmac_set_coalesce,
|
||||
};
|
||||
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
netdev->ethtool_ops = &stmmac_ethtool_ops;
|
||||
}
|
148
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
Normal file
148
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*******************************************************************************
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This implements all the API for managing HW timestamp & PTP.
|
||||
|
||||
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/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include "common.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
|
||||
{
|
||||
writel(data, ioaddr + PTP_TCR);
|
||||
}
|
||||
|
||||
static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + PTP_TCR);
|
||||
unsigned long data;
|
||||
|
||||
/* Convert the ptp_clock to nano second
|
||||
* formula = (1/ptp_clock) * 1000000000
|
||||
* where, ptp_clock = 50MHz.
|
||||
*/
|
||||
data = (1000000000ULL / 50000000);
|
||||
|
||||
/* 0.465ns accuracy */
|
||||
if (!(value & PTP_TCR_TSCTRLSSR))
|
||||
data = (data * 1000) / 465;
|
||||
|
||||
writel(data, ioaddr + PTP_SSIR);
|
||||
}
|
||||
|
||||
static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
|
||||
{
|
||||
int limit;
|
||||
u32 value;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(nsec, ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSINIT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time initialize to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(addend, ioaddr + PTP_TAR);
|
||||
/* issue command to update the addend value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSADDREG;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present addend update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
|
||||
ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSUPDT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time adjust/update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 stmmac_get_systime(void __iomem *ioaddr)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = readl(ioaddr + PTP_STNSR);
|
||||
/* convert sec time value to nanosecond */
|
||||
ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
const struct stmmac_hwtimestamp stmmac_ptp = {
|
||||
.config_hw_tstamping = stmmac_config_hw_tstamping,
|
||||
.init_systime = stmmac_init_systime,
|
||||
.config_sub_second_increment = stmmac_config_sub_second_increment,
|
||||
.config_addend = stmmac_config_addend,
|
||||
.adjust_systime = stmmac_adjust_systime,
|
||||
.get_systime = stmmac_get_systime,
|
||||
};
|
3099
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Normal file
3099
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Normal file
File diff suppressed because it is too large
Load diff
318
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
Normal file
318
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*******************************************************************************
|
||||
STMMAC Ethernet Driver -- MDIO bus implementation
|
||||
Provides Bus interface for MII registers
|
||||
|
||||
Copyright (C) 2007-2009 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: Carl Shaw <carl.shaw@st.com>
|
||||
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
#define MII_BUSY 0x00000001
|
||||
#define MII_WRITE 0x00000002
|
||||
|
||||
static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
|
||||
{
|
||||
unsigned long curr;
|
||||
unsigned long finish = jiffies + 3 * HZ;
|
||||
|
||||
do {
|
||||
curr = jiffies;
|
||||
if (readl(ioaddr + mii_addr) & MII_BUSY)
|
||||
cpu_relax();
|
||||
else
|
||||
return 0;
|
||||
} while (!time_after_eq(curr, finish));
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr reg bits 15-11
|
||||
* @phyreg: MII addr reg bits 10-6
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
|
||||
int data;
|
||||
u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
|
||||
((phyreg << 6) & (0x000007C0)));
|
||||
regValue |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
|
||||
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
writel(regValue, priv->ioaddr + mii_address);
|
||||
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
data = (int)readl(priv->ioaddr + mii_data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr reg bits 15-11
|
||||
* @phyreg: MII addr reg bits 10-6
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
|
||||
u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
|
||||
u16 value =
|
||||
(((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
|
||||
| MII_WRITE;
|
||||
|
||||
value |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(phydata, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_reset
|
||||
* @bus: points to the mii_bus structure
|
||||
* Description: reset the MII bus
|
||||
*/
|
||||
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;
|
||||
struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (priv->device->of_node) {
|
||||
int reset_gpio, active_low;
|
||||
|
||||
if (data->reset_gpio < 0) {
|
||||
struct device_node *np = priv->device->of_node;
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
data->reset_gpio = of_get_named_gpio(np,
|
||||
"snps,reset-gpio", 0);
|
||||
if (data->reset_gpio < 0)
|
||||
return 0;
|
||||
|
||||
data->active_low = of_property_read_bool(np,
|
||||
"snps,reset-active-low");
|
||||
of_property_read_u32_array(np,
|
||||
"snps,reset-delays-us", data->delays, 3);
|
||||
}
|
||||
|
||||
reset_gpio = data->reset_gpio;
|
||||
active_low = data->active_low;
|
||||
|
||||
if (!gpio_request(reset_gpio, "mdio-reset")) {
|
||||
gpio_direction_output(reset_gpio, active_low ? 1 : 0);
|
||||
udelay(data->delays[0]);
|
||||
gpio_set_value(reset_gpio, active_low ? 0 : 1);
|
||||
udelay(data->delays[1]);
|
||||
gpio_set_value(reset_gpio, active_low ? 1 : 0);
|
||||
udelay(data->delays[2]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data->phy_reset) {
|
||||
pr_debug("stmmac_mdio_reset: calling phy_reset\n");
|
||||
data->phy_reset(priv->plat->bsp_priv);
|
||||
}
|
||||
|
||||
/* This is a workaround for problems with the STE101P PHY.
|
||||
* It doesn't complete its reset until at least one clock cycle
|
||||
* on MDC, so perform a dummy mdio read.
|
||||
*/
|
||||
writel(0, priv->ioaddr + mii_address);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_register
|
||||
* @ndev: net device structure
|
||||
* Description: it registers the MII bus
|
||||
*/
|
||||
int stmmac_mdio_register(struct net_device *ndev)
|
||||
{
|
||||
int err = 0;
|
||||
struct mii_bus *new_bus;
|
||||
int *irqlist;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
|
||||
int addr, found;
|
||||
|
||||
if (!mdio_bus_data)
|
||||
return 0;
|
||||
|
||||
new_bus = mdiobus_alloc();
|
||||
if (new_bus == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mdio_bus_data->irqs) {
|
||||
irqlist = mdio_bus_data->irqs;
|
||||
} else {
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++)
|
||||
priv->mii_irq[addr] = PHY_POLL;
|
||||
irqlist = priv->mii_irq;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (priv->device->of_node)
|
||||
mdio_bus_data->reset_gpio = -1;
|
||||
#endif
|
||||
|
||||
new_bus->name = "stmmac";
|
||||
new_bus->read = &stmmac_mdio_read;
|
||||
new_bus->write = &stmmac_mdio_write;
|
||||
new_bus->reset = &stmmac_mdio_reset;
|
||||
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
||||
new_bus->name, priv->plat->bus_id);
|
||||
new_bus->priv = ndev;
|
||||
new_bus->irq = irqlist;
|
||||
new_bus->phy_mask = mdio_bus_data->phy_mask;
|
||||
new_bus->parent = priv->device;
|
||||
err = mdiobus_register(new_bus);
|
||||
if (err != 0) {
|
||||
pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
|
||||
goto bus_register_fail;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
|
||||
struct phy_device *phydev = new_bus->phy_map[addr];
|
||||
if (phydev) {
|
||||
int act = 0;
|
||||
char irq_num[4];
|
||||
char *irq_str;
|
||||
|
||||
/*
|
||||
* If an IRQ was provided to be assigned after
|
||||
* the bus probe, do it here.
|
||||
*/
|
||||
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 we're going to bind the MAC to this PHY bus,
|
||||
* and no PHY number was provided to the MAC,
|
||||
* use the one probed here.
|
||||
*/
|
||||
if (priv->plat->phy_addr == -1)
|
||||
priv->plat->phy_addr = addr;
|
||||
|
||||
act = (priv->plat->phy_addr == addr);
|
||||
switch (phydev->irq) {
|
||||
case PHY_POLL:
|
||||
irq_str = "POLL";
|
||||
break;
|
||||
case PHY_IGNORE_INTERRUPT:
|
||||
irq_str = "IGNORE";
|
||||
break;
|
||||
default:
|
||||
sprintf(irq_num, "%d", phydev->irq);
|
||||
irq_str = irq_num;
|
||||
break;
|
||||
}
|
||||
pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
|
||||
ndev->name, phydev->phy_id, addr,
|
||||
irq_str, dev_name(&phydev->dev),
|
||||
act ? " active" : "");
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pr_warn("%s: No PHY found\n", ndev->name);
|
||||
mdiobus_unregister(new_bus);
|
||||
mdiobus_free(new_bus);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->mii = new_bus;
|
||||
|
||||
return 0;
|
||||
|
||||
bus_register_fail:
|
||||
mdiobus_free(new_bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_unregister
|
||||
* @ndev: net device structure
|
||||
* Description: it unregisters the MII bus
|
||||
*/
|
||||
int stmmac_mdio_unregister(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (!priv->mii)
|
||||
return 0;
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
priv->mii = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
202
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
Normal file
202
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*******************************************************************************
|
||||
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"
|
||||
|
||||
static struct plat_stmmacenet_data plat_dat;
|
||||
static struct stmmac_mdio_bus_data mdio_data;
|
||||
static struct stmmac_dma_cfg dma_cfg;
|
||||
|
||||
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.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.phy_reset = NULL;
|
||||
mdio_data.phy_mask = 0;
|
||||
plat_dat.mdio_bus_data = &mdio_data;
|
||||
|
||||
dma_cfg.pbl = 32;
|
||||
dma_cfg.burst_len = DMA_AXI_BLEN_256;
|
||||
plat_dat.dma_cfg = &dma_cfg;
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat_dat.multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat_dat.unicast_filter_entries = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 register 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 (IS_ERR(priv)) {
|
||||
pr_err("%s: main driver probe failed", __func__);
|
||||
ret = PTR_ERR(priv);
|
||||
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_pci_remove
|
||||
*
|
||||
* @pdev: platform device pointer
|
||||
* Description: this function calls the main to free the net resources
|
||||
* and releases the PCI resources.
|
||||
*/
|
||||
static void 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_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 const struct pci_device_id stmmac_id_table[] = {
|
||||
{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, stmmac_id_table);
|
||||
|
||||
struct pci_driver stmmac_pci_driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.id_table = stmmac_id_table,
|
||||
.probe = stmmac_pci_probe,
|
||||
.remove = stmmac_pci_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = stmmac_pci_suspend,
|
||||
.resume = stmmac_pci_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
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");
|
417
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
Normal file
417
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
Normal file
|
@ -0,0 +1,417 @@
|
|||
/*******************************************************************************
|
||||
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 <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "stmmac.h"
|
||||
|
||||
static const struct of_device_id stmmac_dt_ids[] = {
|
||||
#ifdef CONFIG_DWMAC_MESON
|
||||
{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_SUNXI
|
||||
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_STI
|
||||
{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
|
||||
{ .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
|
||||
{ .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
|
||||
{ .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
|
||||
#endif
|
||||
#ifdef CONFIG_DWMAC_SOCFPGA
|
||||
{ .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
|
||||
#endif
|
||||
/* SoC specific glue layers should come before generic bindings */
|
||||
{ .compatible = "st,spear600-gmac"},
|
||||
{ .compatible = "snps,dwmac-3.610"},
|
||||
{ .compatible = "snps,dwmac-3.70a"},
|
||||
{ .compatible = "snps,dwmac-3.710"},
|
||||
{ .compatible = "snps,dwmac"},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
/* This function validates the number of Multicast filtering bins specified
|
||||
* by the configuration through the device tree. The Synopsys GMAC supports
|
||||
* 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC
|
||||
* number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds
|
||||
* to 7 bits, and 256 refers to 8 bits of the CRC. Any other setting is
|
||||
* invalid and will cause the filtering algorithm to use Multicast
|
||||
* promiscuous mode.
|
||||
*/
|
||||
static int dwmac1000_validate_mcast_bins(int mcast_bins)
|
||||
{
|
||||
int x = mcast_bins;
|
||||
|
||||
switch (x) {
|
||||
case HASH_TABLE_SIZE:
|
||||
case 128:
|
||||
case 256:
|
||||
break;
|
||||
default:
|
||||
x = 0;
|
||||
pr_info("Hash table entries set to unexpected value %d",
|
||||
mcast_bins);
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* This function validates the number of Unicast address entries supported
|
||||
* by a particular Synopsys 10/100/1000 controller. The Synopsys controller
|
||||
* supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter
|
||||
* logic. This function validates a valid, supported configuration is
|
||||
* selected, and defaults to 1 Unicast address if an unsupported
|
||||
* configuration is selected.
|
||||
*/
|
||||
static int dwmac1000_validate_ucast_entries(int ucast_entries)
|
||||
{
|
||||
int x = ucast_entries;
|
||||
|
||||
switch (x) {
|
||||
case 1:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
break;
|
||||
default:
|
||||
x = 1;
|
||||
pr_info("Unicast table entries set to unexpected value %d\n",
|
||||
ucast_entries);
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct stmmac_dma_cfg *dma_cfg;
|
||||
const struct of_device_id *device;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
device = of_match_device(stmmac_dt_ids, &pdev->dev);
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
if (device->data) {
|
||||
const struct stmmac_of_data *data = device->data;
|
||||
plat->has_gmac = data->has_gmac;
|
||||
plat->enh_desc = data->enh_desc;
|
||||
plat->tx_coe = data->tx_coe;
|
||||
plat->rx_coe = data->rx_coe;
|
||||
plat->bugged_jumbo = data->bugged_jumbo;
|
||||
plat->pmt = data->pmt;
|
||||
plat->riwt_off = data->riwt_off;
|
||||
plat->fix_mac_speed = data->fix_mac_speed;
|
||||
plat->bus_setup = data->bus_setup;
|
||||
plat->setup = data->setup;
|
||||
plat->free = data->free;
|
||||
plat->init = data->init;
|
||||
plat->exit = data->exit;
|
||||
}
|
||||
|
||||
*mac = of_get_mac_address(np);
|
||||
plat->interface = of_get_phy_mode(np);
|
||||
|
||||
/* Get max speed of operation from device tree */
|
||||
if (of_property_read_u32(np, "max-speed", &plat->max_speed))
|
||||
plat->max_speed = -1;
|
||||
|
||||
plat->bus_id = of_alias_get_id(np, "ethernet");
|
||||
if (plat->bus_id < 0)
|
||||
plat->bus_id = 0;
|
||||
|
||||
/* Default to phy auto-detection */
|
||||
plat->phy_addr = -1;
|
||||
|
||||
/* "snps,phy-addr" is not a standard property. Mark it as deprecated
|
||||
* and warn of its use. Remove this when phy node support is added.
|
||||
*/
|
||||
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
|
||||
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
|
||||
|
||||
if (plat->phy_bus_name)
|
||||
plat->mdio_bus_data = NULL;
|
||||
else
|
||||
plat->mdio_bus_data =
|
||||
devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct stmmac_mdio_bus_data),
|
||||
GFP_KERNEL);
|
||||
|
||||
plat->force_sf_dma_mode =
|
||||
of_property_read_bool(np, "snps,force_sf_dma_mode");
|
||||
|
||||
/* Set the maxmtu to a default of JUMBO_LEN in case the
|
||||
* parameter is not present in the device tree.
|
||||
*/
|
||||
plat->maxmtu = JUMBO_LEN;
|
||||
|
||||
/*
|
||||
* Currently only the properties needed on SPEAr600
|
||||
* are provided. All other properties should be added
|
||||
* once needed on other platforms.
|
||||
*/
|
||||
if (of_device_is_compatible(np, "st,spear600-gmac") ||
|
||||
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
|
||||
of_device_is_compatible(np, "snps,dwmac")) {
|
||||
/* Note that the max-frame-size parameter as defined in the
|
||||
* ePAPR v1.1 spec is defined as max-frame-size, it's
|
||||
* actually used as the IEEE definition of MAC Client
|
||||
* data, or MTU. The ePAPR specification is confusing as
|
||||
* the definition is max-frame-size, but usage examples
|
||||
* are clearly MTUs
|
||||
*/
|
||||
of_property_read_u32(np, "max-frame-size", &plat->maxmtu);
|
||||
of_property_read_u32(np, "snps,multicast-filter-bins",
|
||||
&plat->multicast_filter_bins);
|
||||
of_property_read_u32(np, "snps,perfect-filter-entries",
|
||||
&plat->unicast_filter_entries);
|
||||
plat->unicast_filter_entries = dwmac1000_validate_ucast_entries(
|
||||
plat->unicast_filter_entries);
|
||||
plat->multicast_filter_bins = dwmac1000_validate_mcast_bins(
|
||||
plat->multicast_filter_bins);
|
||||
plat->has_gmac = 1;
|
||||
plat->pmt = 1;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
|
||||
of_device_is_compatible(np, "snps,dwmac-3.710")) {
|
||||
plat->enh_desc = 1;
|
||||
plat->bugged_jumbo = 1;
|
||||
plat->force_sf_dma_mode = 1;
|
||||
}
|
||||
|
||||
if (of_find_property(np, "snps,pbl", NULL)) {
|
||||
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
|
||||
GFP_KERNEL);
|
||||
if (!dma_cfg)
|
||||
return -ENOMEM;
|
||||
plat->dma_cfg = dma_cfg;
|
||||
of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
|
||||
dma_cfg->fixed_burst =
|
||||
of_property_read_bool(np, "snps,fixed-burst");
|
||||
dma_cfg->mixed_burst =
|
||||
of_property_read_bool(np, "snps,mixed-burst");
|
||||
}
|
||||
plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
|
||||
if (plat->force_thresh_dma_mode) {
|
||||
plat->force_sf_dma_mode = 0;
|
||||
pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
* 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;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *addr = NULL;
|
||||
struct stmmac_priv *priv = NULL;
|
||||
struct plat_stmmacenet_data *plat_dat = NULL;
|
||||
const char *mac = NULL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(addr))
|
||||
return PTR_ERR(addr);
|
||||
|
||||
plat_dat = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (!plat_dat)
|
||||
plat_dat = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct plat_stmmacenet_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat_dat) {
|
||||
pr_err("%s: ERROR: no memory", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set default value for multicast hash bins */
|
||||
plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
|
||||
|
||||
/* Set default value for unicast filter entries */
|
||||
plat_dat->unicast_filter_entries = 1;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
|
||||
if (ret) {
|
||||
pr_err("%s: main dt probe failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom setup (if needed) */
|
||||
if (plat_dat->setup) {
|
||||
plat_dat->bsp_priv = plat_dat->setup(pdev);
|
||||
if (IS_ERR(plat_dat->bsp_priv))
|
||||
return PTR_ERR(plat_dat->bsp_priv);
|
||||
}
|
||||
|
||||
/* Custom initialisation (if needed)*/
|
||||
if (plat_dat->init) {
|
||||
ret = plat_dat->init(pdev, plat_dat->bsp_priv);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
|
||||
if (IS_ERR(priv)) {
|
||||
pr_err("%s: main driver probe failed", __func__);
|
||||
return PTR_ERR(priv);
|
||||
}
|
||||
|
||||
/* Get MAC address if available (DT) */
|
||||
if (mac)
|
||||
memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
|
||||
|
||||
/* Get the MAC information */
|
||||
priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
|
||||
if (priv->dev->irq < 0) {
|
||||
if (priv->dev->irq != -EPROBE_DEFER) {
|
||||
netdev_err(priv->dev,
|
||||
"MAC IRQ configuration information not found\n");
|
||||
}
|
||||
return priv->dev->irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 < 0) {
|
||||
if (priv->wol_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
priv->wol_irq = priv->dev->irq;
|
||||
}
|
||||
|
||||
priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
|
||||
if (priv->lpi_irq == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
platform_set_drvdata(pdev, priv->dev);
|
||||
|
||||
pr_debug("STMMAC platform driver registration completed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
int ret = stmmac_dvr_remove(ndev);
|
||||
|
||||
if (priv->plat->exit)
|
||||
priv->plat->exit(pdev, priv->plat->bsp_priv);
|
||||
|
||||
if (priv->plat->free)
|
||||
priv->plat->free(pdev, priv->plat->bsp_priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stmmac_pltfr_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
ret = stmmac_suspend(ndev);
|
||||
if (priv->plat->exit)
|
||||
priv->plat->exit(pdev, priv->plat->bsp_priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_pltfr_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (priv->plat->init)
|
||||
priv->plat->init(pdev, priv->plat->bsp_priv);
|
||||
|
||||
return stmmac_resume(ndev);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
|
||||
stmmac_pltfr_suspend, stmmac_pltfr_resume);
|
||||
|
||||
struct platform_driver stmmac_pltfr_driver = {
|
||||
.probe = stmmac_pltfr_probe,
|
||||
.remove = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &stmmac_pltfr_pm_ops,
|
||||
.of_match_table = of_match_ptr(stmmac_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
|
||||
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
||||
MODULE_LICENSE("GPL");
|
213
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
Normal file
213
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*******************************************************************************
|
||||
PTP 1588 clock using the STMMAC.
|
||||
|
||||
Copyright (C) 2013 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>
|
||||
*******************************************************************************/
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
/**
|
||||
* stmmac_adjust_freq
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ppb: desired period change in parts ber billion
|
||||
*
|
||||
* Description: this function will adjust the frequency of hardware clock.
|
||||
*/
|
||||
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 diff, addend;
|
||||
int neg_adj = 0;
|
||||
u64 adj;
|
||||
|
||||
if (ppb < 0) {
|
||||
neg_adj = 1;
|
||||
ppb = -ppb;
|
||||
}
|
||||
|
||||
addend = priv->default_addend;
|
||||
adj = addend;
|
||||
adj *= ppb;
|
||||
diff = div_u64(adj, 1000000000ULL);
|
||||
addend = neg_adj ? (addend - diff) : (addend + diff);
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->config_addend(priv->ioaddr, addend);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_adjust_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @delta: desired change in nanoseconds
|
||||
*
|
||||
* Description: this function will shift/adjust the hardware clock time.
|
||||
*/
|
||||
static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 sec, nsec;
|
||||
u32 quotient, reminder;
|
||||
int neg_adj = 0;
|
||||
|
||||
if (delta < 0) {
|
||||
neg_adj = 1;
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
|
||||
sec = quotient;
|
||||
nsec = reminder;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: pointer to hold time/result
|
||||
*
|
||||
* Description: this function will read the current time from the
|
||||
* hardware clock and store it in @ts.
|
||||
*/
|
||||
static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
u32 reminder;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
ns = priv->hw->ptp->get_systime(priv->ioaddr);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &reminder);
|
||||
ts->tv_nsec = reminder;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_set_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: time value to set
|
||||
*
|
||||
* Description: this function will set the current time on the
|
||||
* hardware clock.
|
||||
*/
|
||||
static int stmmac_set_time(struct ptp_clock_info *ptp,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* structure describing a PTP hardware clock */
|
||||
static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "stmmac_ptp_clock",
|
||||
.max_adj = 62500000,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0,
|
||||
.n_per_out = 0,
|
||||
.n_pins = 0,
|
||||
.pps = 0,
|
||||
.adjfreq = stmmac_adjust_freq,
|
||||
.adjtime = stmmac_adjust_time,
|
||||
.gettime = stmmac_get_time,
|
||||
.settime = stmmac_set_time,
|
||||
.enable = stmmac_enable,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_ptp_register
|
||||
* @priv: driver private structure
|
||||
* Description: this function will register the ptp clock driver
|
||||
* to kernel. It also does some house keeping work.
|
||||
*/
|
||||
int stmmac_ptp_register(struct stmmac_priv *priv)
|
||||
{
|
||||
spin_lock_init(&priv->ptp_lock);
|
||||
priv->ptp_clock_ops = stmmac_ptp_clock_ops;
|
||||
|
||||
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
|
||||
priv->device);
|
||||
if (IS_ERR(priv->ptp_clock)) {
|
||||
priv->ptp_clock = NULL;
|
||||
pr_err("ptp_clock_register() failed on %s\n", priv->dev->name);
|
||||
} else
|
||||
pr_debug("Added PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_ptp_unregister
|
||||
* @priv: driver private structure
|
||||
* Description: this function will remove/unregister the ptp clock driver
|
||||
* from the kernel.
|
||||
*/
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->ptp_clock) {
|
||||
ptp_clock_unregister(priv->ptp_clock);
|
||||
priv->ptp_clock = NULL;
|
||||
pr_debug("Removed PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
}
|
||||
}
|
72
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
Normal file
72
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/******************************************************************************
|
||||
PTP Header file
|
||||
|
||||
Copyright (C) 2013 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>
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_PTP_H__
|
||||
#define __STMMAC_PTP_H__
|
||||
|
||||
/* IEEE 1588 PTP register offsets */
|
||||
#define PTP_TCR 0x0700 /* Timestamp Control Reg */
|
||||
#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
|
||||
#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
|
||||
#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
|
||||
#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
|
||||
#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
|
||||
#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
|
||||
#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
|
||||
#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
|
||||
#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
|
||||
#define PTP_TSR 0x0728 /* Timestamp Status */
|
||||
|
||||
#define PTP_STNSUR_ADDSUB_SHIFT 31
|
||||
|
||||
/* PTP TCR defines */
|
||||
#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
|
||||
#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
|
||||
#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
|
||||
#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
|
||||
/* Timestamp Interrupt Trigger Enable */
|
||||
#define PTP_TCR_TSTRIG 0x00000010
|
||||
#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
|
||||
#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
|
||||
/* Timestamp Digital or Binary Rollover Control */
|
||||
#define PTP_TCR_TSCTRLSSR 0x00000200
|
||||
|
||||
/* Enable PTP packet Processing for Version 2 Format */
|
||||
#define PTP_TCR_TSVER2ENA 0x00000400
|
||||
/* Enable Processing of PTP over Ethernet Frames */
|
||||
#define PTP_TCR_TSIPENA 0x00000800
|
||||
/* Enable Processing of PTP Frames Sent over IPv6-UDP */
|
||||
#define PTP_TCR_TSIPV6ENA 0x00001000
|
||||
/* Enable Processing of PTP Frames Sent over IPv4-UDP */
|
||||
#define PTP_TCR_TSIPV4ENA 0x00002000
|
||||
/* Enable Timestamp Snapshot for Event Messages */
|
||||
#define PTP_TCR_TSEVNTENA 0x00004000
|
||||
/* Enable Snapshot for Messages Relevant to Master */
|
||||
#define PTP_TCR_TSMSTRENA 0x00008000
|
||||
/* Select PTP packets for Taking Snapshots */
|
||||
#define PTP_TCR_SNAPTYPSEL_1 0x00010000
|
||||
/* Enable MAC address for PTP Frame Filtering */
|
||||
#define PTP_TCR_TSENMACADDR 0x00040000
|
||||
|
||||
#endif /* __STMMAC_PTP_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue