From 41e003a71d1f5557457d7af97190b73352cbfd39 Mon Sep 17 00:00:00 2001 From: hwg Date: Tue, 11 Mar 2014 21:52:01 +0800 Subject: [PATCH] ethernet: add gmac driver --- arch/arm/boot/dts/rk3188-tb.dts | 2 +- drivers/net/ethernet/{rk => rockchip}/Kconfig | 3 +- .../net/ethernet/{rk => rockchip}/Makefile | 1 + drivers/net/ethernet/rockchip/gmac/Kconfig | 31 + drivers/net/ethernet/rockchip/gmac/Makefile | 7 + .../net/ethernet/rockchip/gmac/chain_mode.c | 161 + drivers/net/ethernet/rockchip/gmac/common.h | 475 +++ drivers/net/ethernet/rockchip/gmac/descs.h | 219 ++ .../net/ethernet/rockchip/gmac/descs_com.h | 134 + drivers/net/ethernet/rockchip/gmac/dwmac100.h | 126 + .../net/ethernet/rockchip/gmac/dwmac1000.h | 269 ++ .../ethernet/rockchip/gmac/dwmac1000_core.c | 408 +++ .../ethernet/rockchip/gmac/dwmac1000_dma.c | 203 ++ .../ethernet/rockchip/gmac/dwmac100_core.c | 193 ++ .../net/ethernet/rockchip/gmac/dwmac100_dma.c | 146 + .../net/ethernet/rockchip/gmac/dwmac_dma.h | 117 + .../net/ethernet/rockchip/gmac/dwmac_lib.c | 289 ++ drivers/net/ethernet/rockchip/gmac/enh_desc.c | 445 +++ drivers/net/ethernet/rockchip/gmac/gmac.IAB | Bin 0 -> 147456 bytes drivers/net/ethernet/rockchip/gmac/gmac.IAD | Bin 0 -> 1768 bytes drivers/net/ethernet/rockchip/gmac/gmac.IMB | Bin 0 -> 36864 bytes drivers/net/ethernet/rockchip/gmac/gmac.IMD | Bin 0 -> 688 bytes drivers/net/ethernet/rockchip/gmac/gmac.PFI | Bin 0 -> 104 bytes drivers/net/ethernet/rockchip/gmac/gmac.PO | Bin 0 -> 776 bytes drivers/net/ethernet/rockchip/gmac/gmac.PR | Bin 0 -> 8624 bytes drivers/net/ethernet/rockchip/gmac/gmac.PRI | Bin 0 -> 53136 bytes drivers/net/ethernet/rockchip/gmac/gmac.PS | Bin 0 -> 249740 bytes .../ethernet/rockchip/gmac/gmac.SearchResults | 1 + drivers/net/ethernet/rockchip/gmac/mmc.h | 135 + drivers/net/ethernet/rockchip/gmac/mmc_core.c | 267 ++ .../net/ethernet/rockchip/gmac/norm_desc.c | 275 ++ .../net/ethernet/rockchip/gmac/ring_mode.c | 127 + drivers/net/ethernet/rockchip/gmac/stmmac.h | 180 + .../ethernet/rockchip/gmac/stmmac_ethtool.c | 788 +++++ .../ethernet/rockchip/gmac/stmmac_hwtstamp.c | 148 + .../net/ethernet/rockchip/gmac/stmmac_main.c | 2956 +++++++++++++++++ .../net/ethernet/rockchip/gmac/stmmac_mdio.c | 270 ++ .../net/ethernet/rockchip/gmac/stmmac_pci.c | 196 ++ .../ethernet/rockchip/gmac/stmmac_platform.c | 252 ++ .../net/ethernet/rockchip/gmac/stmmac_ptp.c | 211 ++ .../net/ethernet/rockchip/gmac/stmmac_ptp.h | 74 + .../ethernet/{rk => rockchip}/vmac/Kconfig | 0 .../ethernet/{rk => rockchip}/vmac/Makefile | 0 .../{rk => rockchip}/vmac/rk29_vmac.c | 0 .../{rk => rockchip}/vmac/rk29_vmac.h | 0 .../{rk => rockchip}/vmac/rk29_vmac_phy.c | 6 +- 46 files changed, 9110 insertions(+), 5 deletions(-) rename drivers/net/ethernet/{rk => rockchip}/Kconfig (66%) rename drivers/net/ethernet/{rk => rockchip}/Makefile (70%) create mode 100755 drivers/net/ethernet/rockchip/gmac/Kconfig create mode 100755 drivers/net/ethernet/rockchip/gmac/Makefile create mode 100755 drivers/net/ethernet/rockchip/gmac/chain_mode.c create mode 100755 drivers/net/ethernet/rockchip/gmac/common.h create mode 100755 drivers/net/ethernet/rockchip/gmac/descs.h create mode 100755 drivers/net/ethernet/rockchip/gmac/descs_com.h create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac100.h create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac1000.h create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac100_core.c create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac_dma.h create mode 100755 drivers/net/ethernet/rockchip/gmac/dwmac_lib.c create mode 100755 drivers/net/ethernet/rockchip/gmac/enh_desc.c create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.IAB create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.IAD create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.IMB create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.IMD create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.PFI create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.PO create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.PR create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.PRI create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.PS create mode 100755 drivers/net/ethernet/rockchip/gmac/gmac.SearchResults create mode 100755 drivers/net/ethernet/rockchip/gmac/mmc.h create mode 100755 drivers/net/ethernet/rockchip/gmac/mmc_core.c create mode 100755 drivers/net/ethernet/rockchip/gmac/norm_desc.c create mode 100755 drivers/net/ethernet/rockchip/gmac/ring_mode.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac.h create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_main.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_pci.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_platform.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c create mode 100755 drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h rename drivers/net/ethernet/{rk => rockchip}/vmac/Kconfig (100%) rename drivers/net/ethernet/{rk => rockchip}/vmac/Makefile (100%) rename drivers/net/ethernet/{rk => rockchip}/vmac/rk29_vmac.c (100%) rename drivers/net/ethernet/{rk => rockchip}/vmac/rk29_vmac.h (100%) rename drivers/net/ethernet/{rk => rockchip}/vmac/rk29_vmac_phy.c (97%) diff --git a/arch/arm/boot/dts/rk3188-tb.dts b/arch/arm/boot/dts/rk3188-tb.dts index 285faecfe5ec..01fc551f90c6 100755 --- a/arch/arm/boot/dts/rk3188-tb.dts +++ b/arch/arm/boot/dts/rk3188-tb.dts @@ -121,7 +121,7 @@ }; vmac-phy { - compatible = "vmac-phy"; + compatible = "rockchip,vmac-phy"; power-gpios = <&gpio0 GPIO_C0 GPIO_ACTIVE_HIGH>; }; }; diff --git a/drivers/net/ethernet/rk/Kconfig b/drivers/net/ethernet/rockchip/Kconfig similarity index 66% rename from drivers/net/ethernet/rk/Kconfig rename to drivers/net/ethernet/rockchip/Kconfig index be5f534e70d6..777b5e897ff7 100755 --- a/drivers/net/ethernet/rk/Kconfig +++ b/drivers/net/ethernet/rockchip/Kconfig @@ -11,6 +11,7 @@ config NET_VENDOR_ROCKCHIP if NET_VENDOR_ROCKCHIP -source "drivers/net/ethernet/rk/vmac/Kconfig" +source "drivers/net/ethernet/rockchip/vmac/Kconfig" +source "drivers/net/ethernet/rockchip/gmac/Kconfig" endif # NET_VENDOR_ROCKCHIP diff --git a/drivers/net/ethernet/rk/Makefile b/drivers/net/ethernet/rockchip/Makefile similarity index 70% rename from drivers/net/ethernet/rk/Makefile rename to drivers/net/ethernet/rockchip/Makefile index e36c612ba7cb..8d8d89eff1ad 100755 --- a/drivers/net/ethernet/rk/Makefile +++ b/drivers/net/ethernet/rockchip/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_RK_VMAC_ETH) += vmac/ +obj-$(CONFIG_RK_GMAC_ETH) += gmac/ diff --git a/drivers/net/ethernet/rockchip/gmac/Kconfig b/drivers/net/ethernet/rockchip/gmac/Kconfig new file mode 100755 index 000000000000..957a46bdbc18 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/Kconfig @@ -0,0 +1,31 @@ +config RK_GMAC_ETH + tristate "Rockchip 10/100/1000 Ethernet driver" + depends on HAS_IOMEM && HAS_DMA + select NET_CORE + select MII + select PHYLIB + select CRC32 + select PTP_1588_CLOCK + ---help--- + Rockchip 10/100/1000 Ethernet driver. + +if RK_GMAC_ETH + +config GMAC_DEBUG_FS + bool "Enable monitoring via sysFS " + default n + depends on RK_GMAC_ETH && DEBUG_FS + ---help--- + The gmac entry in /sys reports DMA TX/RX rings + or (if supported) the HW cap register. + +config GMAC_DA + bool "GMAC 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 diff --git a/drivers/net/ethernet/rockchip/gmac/Makefile b/drivers/net/ethernet/rockchip/gmac/Makefile new file mode 100755 index 000000000000..7abf9db73cc2 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_RK_GMAC_ETH) += stmmac.o +stmmac-$(CONFIG_RK_GMAC_ETH) += stmmac_platform.o +stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.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) diff --git a/drivers/net/ethernet/rockchip/gmac/chain_mode.c b/drivers/net/ethernet/rockchip/gmac/chain_mode.c new file mode 100755 index 000000000000..d234ab540b29 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/chain_mode.c @@ -0,0 +1,161 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include "stmmac.h" + +static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)p; + unsigned int txsize = priv->dma_tx_size; + unsigned int entry = priv->cur_tx % txsize; + struct dma_desc *desc = priv->dma_tx + entry; + unsigned int nopaged_len = skb_headlen(skb); + unsigned int bmax; + unsigned int i = 1, len; + + if (priv->plat->enh_desc) + bmax = BUF_SIZE_8KiB; + else + bmax = BUF_SIZE_2KiB; + + len = nopaged_len - bmax; + + desc->des2 = dma_map_single(priv->device, skb->data, + bmax, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE); + + while (len != 0) { + entry = (++priv->cur_tx) % txsize; + desc = priv->dma_tx + entry; + + if (len > bmax) { + desc->des2 = dma_map_single(priv->device, + (skb->data + bmax * i), + bmax, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum, + STMMAC_CHAIN_MODE); + priv->hw->desc->set_tx_owner(desc); + priv->tx_skbuff[entry] = NULL; + len -= bmax; + i++; + } else { + desc->des2 = dma_map_single(priv->device, + (skb->data + bmax * i), len, + DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum, + STMMAC_CHAIN_MODE); + priv->hw->desc->set_tx_owner(desc); + priv->tx_skbuff[entry] = NULL; + len = 0; + } + } + return entry; +} + +static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc) +{ + unsigned int ret = 0; + + if ((enh_desc && (len > BUF_SIZE_8KiB)) || + (!enh_desc && (len > BUF_SIZE_2KiB))) { + ret = 1; + } + + return ret; +} + +static void stmmac_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_chain_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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/common.h b/drivers/net/ethernet/rockchip/gmac/common.h new file mode 100755 index 000000000000..95176979b2d2 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/common.h @@ -0,0 +1,475 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include +#include +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) +#define STMMAC_VLAN_TAG_USED +#include +#endif + +#include "descs.h" +#include "mmc.h" + +#undef CHIP_DEBUG_PRINT +/* Turn-on extra printk debug for MAC core, dma and descriptors */ +/* #define CHIP_DEBUG_PRINT */ + +#ifdef CHIP_DEBUG_PRINT +#define CHIP_DBG(fmt, args...) printk(fmt, ## args) +#else +#define CHIP_DBG(fmt, args...) do { } while (0) +#endif + +/* 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 << 1) +#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 2) +#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 3) +#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 4) + +#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 0x0 + +#define STMMAC_CHAIN_MODE 0x1 +#define STMMAC_RING_MODE 0x2 + +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 stmmac_ops { + /* MAC core initialization */ + void (*core_init) (void __iomem *ioaddr); + /* Enable and verify that the IPC module is supported */ + int (*rx_ipc) (void __iomem *ioaddr); + /* Dump MAC registers */ + void (*dump_regs) (void __iomem *ioaddr); + /* Handle extra events on specific interrupts hw dependent */ + int (*host_irq_status) (void __iomem *ioaddr, + struct stmmac_extra_stats *x); + /* Multicast filter setting */ + void (*set_filter) (struct net_device *dev, int id); + /* Flow control setting */ + void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time); + /* Set power management mode (e.g. magic frame) */ + void (*pmt) (void __iomem *ioaddr, unsigned long mode); + /* Set/Get Unicast MAC addresses */ + void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n); + void (*set_eee_mode) (void __iomem *ioaddr); + void (*reset_eee_mode) (void __iomem *ioaddr); + void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw); + void (*set_eee_pls) (void __iomem *ioaddr, int link); + void (*ctrl_ane) (void __iomem *ioaddr, bool restart); + void (*get_adv) (void __iomem *ioaddr, 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_ring_mode_ops { + unsigned int (*is_jumbo_frm) (int len, int ehn_desc); + unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); + void (*refill_desc3) (void *priv, struct dma_desc *p); + void (*init_desc3) (struct dma_desc *p); + void (*clean_desc3) (void *priv, struct dma_desc *p); + int (*set_16kib_bfsize) (int mtu); +}; + +struct stmmac_chain_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); + unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); + 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_ring_mode_ops *ring; + const struct stmmac_chain_mode_ops *chain; + const struct stmmac_hwtimestamp *ptp; + struct mii_regs mii; /* MII register Addresses */ + struct mac_link link; + unsigned int synopsys_uid; +}; + +struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr); +struct mac_device_info *dwmac100_setup(void __iomem *ioaddr); + +extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], + unsigned int high, unsigned int low); +extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int high, unsigned int low); + +extern void stmmac_set_mac(void __iomem *ioaddr, bool enable); + +extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); +extern const struct stmmac_ring_mode_ops ring_mode_ops; +extern const struct stmmac_chain_mode_ops chain_mode_ops; + +#endif /* __COMMON_H__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/descs.h b/drivers/net/ethernet/rockchip/gmac/descs.h new file mode 100755 index 000000000000..ad3996038018 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/descs.h @@ -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 +*******************************************************************************/ + +#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__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/descs_com.h b/drivers/net/ethernet/rockchip/gmac/descs_com.h new file mode 100755 index 000000000000..6f2cc78c5cf5 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/descs_com.h @@ -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 +*******************************************************************************/ + +#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__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac100.h b/drivers/net/ethernet/rockchip/gmac/dwmac100.h new file mode 100755 index 000000000000..2ec6aeae349e --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac100.h @@ -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 +*******************************************************************************/ + +#ifndef __DWMAC100_H__ +#define __DWMAC100_H__ + +#include +#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__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac1000.h b/drivers/net/ethernet/rockchip/gmac/dwmac1000.h new file mode 100755 index 000000000000..c12aabb8cf93 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac1000.h @@ -0,0 +1,269 @@ +/******************************************************************************* + 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 +*******************************************************************************/ +#ifndef __DWMAC1000_H__ +#define __DWMAC1000_H__ + +#include +#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 32 + +/* 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_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */ +#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */ + +/* GMAC Configuration defines */ +#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_JE | GMAC_CONTROL_BE) + +/* 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 + +extern const struct stmmac_dma_ops dwmac1000_dma_ops; +#endif /* __DWMAC1000_H__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c b/drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c new file mode 100755 index 000000000000..7e05e8d0f1c2 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c @@ -0,0 +1,408 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#include +#include +#include +#include "dwmac1000.h" + +static void dwmac1000_core_init(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + GMAC_CONTROL); + value |= GMAC_CORE_INIT; + 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(void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + GMAC_CONTROL); + + value |= GMAC_CONTROL_IPC; + writel(value, ioaddr + GMAC_CONTROL); + + value = readl(ioaddr + GMAC_CONTROL); + + return !!(value & GMAC_CONTROL_IPC); +} + +static void dwmac1000_dump_regs(void __iomem *ioaddr) +{ + 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(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), + GMAC_ADDR_LOW(reg_n)); +} + +static void dwmac1000_set_filter(struct net_device *dev, int id) +{ + void __iomem *ioaddr = (void __iomem *)dev->base_addr; + unsigned int value = 0; + unsigned int perfect_addr_number; + + CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", + __func__, netdev_mc_count(dev), netdev_uc_count(dev)); + + if (dev->flags & IFF_PROMISC) + value = GMAC_FRAME_FILTER_PR; + else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE) + || (dev->flags & IFF_ALLMULTI)) { + value = GMAC_FRAME_FILTER_PM; /* pass all multi */ + writel(0xffffffff, ioaddr + GMAC_HASH_HIGH); + writel(0xffffffff, ioaddr + GMAC_HASH_LOW); + } else if (!netdev_mc_empty(dev)) { + u32 mc_filter[2]; + struct netdev_hw_addr *ha; + + /* Hash filter for multicast */ + value = GMAC_FRAME_FILTER_HMC; + + 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 = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 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 + GMAC_HASH_LOW); + writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); + } + + /* Extra 16 regs are available in cores newer than the 3.40. */ + if (id > DWMAC_CORE_3_40) + perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; + else + perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2; + + /* Handle multiple unicast addresses (perfect filtering) */ + if (netdev_uc_count(dev) > perfect_addr_number) + /* Switch to promiscuous mode if more than 16 addrs + * are required + */ + value |= GMAC_FRAME_FILTER_PR; + else { + int reg = 1; + struct netdev_hw_addr *ha; + + netdev_for_each_uc_addr(ha, dev) { + dwmac1000_set_umac_addr(ioaddr, ha->addr, 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); + + CHIP_DBG(KERN_INFO "\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n", + readl(ioaddr + GMAC_FRAME_FILTER), + readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW)); +} + +static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + unsigned int flow = 0; + + CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n"); + if (fc & FLOW_RX) { + CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_RFE; + } + if (fc & FLOW_TX) { + CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n"); + flow |= GMAC_FLOW_CTRL_TFE; + } + + if (duplex) { + CHIP_DBG(KERN_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(void __iomem *ioaddr, unsigned long mode) +{ + unsigned int pmt = 0; + + if (mode & WAKE_MAGIC) { + CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); + pmt |= power_down | magic_pkt_en; + } + if (mode & WAKE_UCAST) { + CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); + pmt |= global_unicast; + } + + writel(pmt, ioaddr + GMAC_PMT); +} + +static int dwmac1000_irq_status(void __iomem *ioaddr, + struct stmmac_extra_stats *x) +{ + 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)) { + CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_TX_INTR)); + x->mmc_tx_irq_n++; + } + if (unlikely(intr_status & mmc_rx_irq)) { + CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_INTR)); + x->mmc_rx_irq_n++; + } + if (unlikely(intr_status & mmc_rx_csum_offload_irq)) { + CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n", + readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD)); + x->mmc_rx_csum_offload_irq_n++; + } + if (unlikely(intr_status & pmt_irq)) { + CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n"); + /* 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) { + CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n"); + x->irq_tx_path_in_lpi_mode_n++; + } + if (ret & LPI_CTRL_STATUS_TLPIEX) { + CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n"); + x->irq_tx_path_exit_lpi_mode_n++; + } + if (ret & LPI_CTRL_STATUS_RLPIEN) { + CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n"); + x->irq_rx_path_in_lpi_mode_n++; + } + if (ret & LPI_CTRL_STATUS_RLPIEX) { + CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n"); + x->irq_rx_path_exit_lpi_mode_n++; + } + } + + if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) { + CHIP_DBG(KERN_INFO "GMAC PCS ANE IRQ\n"); + readl(ioaddr + GMAC_AN_STATUS); + x->irq_pcs_ane_n++; + } + if (intr_status & rgmii_irq) { + u32 status = readl(ioaddr + GMAC_S_R_GMII); + CHIP_DBG(KERN_INFO "GMAC RGMII/SGMII interrupt\n"); + 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("Link is Up - %d/%s\n", (int)x->pcs_speed, + x->pcs_duplex ? "Full" : "Half"); + } else { + x->pcs_link = 0; + pr_debug("Link is Down\n"); + } + } + + return ret; +} + +static void dwmac1000_set_eee_mode(void __iomem *ioaddr) +{ + 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(void __iomem *ioaddr) +{ + 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(void __iomem *ioaddr, int link) +{ + 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(void __iomem *ioaddr, int ls, int tw) +{ + int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16); + + /* Program the timers in the LPI timer control register: + * LS: minimum time (ms) for which the link + * status from PHY should be ok before transmitting + * the LPI pattern. + * TW: minimum time (us) for which the core waits + * after it has stopped transmitting the LPI pattern. + */ + writel(value, ioaddr + LPI_TIMER_CTRL); +} + +static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart) +{ + u32 value; + + value = readl(ioaddr + GMAC_AN_CTRL); + /* auto negotiation enable and External Loopback enable */ + 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(void __iomem *ioaddr, struct rgmii_adv *adv) +{ + 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) +{ + 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->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; +} diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c b/drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c new file mode 100755 index 000000000000..d5f4239acf53 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c @@ -0,0 +1,203 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#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_GMAC_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) { + CHIP_DBG(KERN_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 { + CHIP_DBG(KERN_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) { + CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n"); + csr6 |= DMA_CONTROL_RSF; + } else { + CHIP_DBG(KERN_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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac100_core.c b/drivers/net/ethernet/rockchip/gmac/dwmac100_core.c new file mode 100755 index 000000000000..007bb2be3f10 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac100_core.c @@ -0,0 +1,193 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#include +#include "dwmac100.h" + +static void dwmac100_core_init(void __iomem *ioaddr) +{ + 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(void __iomem *ioaddr) +{ + 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(void __iomem *ioaddr) +{ + return 0; +} + +static int dwmac100_irq_status(void __iomem *ioaddr, + struct stmmac_extra_stats *x) +{ + return 0; +} + +static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); +} + +static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, + unsigned int reg_n) +{ + stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); +} + +static void dwmac100_set_filter(struct net_device *dev, int id) +{ + 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); + + CHIP_DBG(KERN_INFO "%s: Filter: 0x%08x Hash: HI 0x%08x, LO 0x%08x\n", + __func__, readl(ioaddr + MAC_CONTROL), + readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW)); +} + +static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex, + unsigned int fc, unsigned int pause_time) +{ + 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(void __iomem *ioaddr, 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->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; +} diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c b/drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c new file mode 100755 index 000000000000..67551c154138 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c @@ -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 +*******************************************************************************/ + +#include +#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; + + CHIP_DBG(KERN_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)); + CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n", + DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR)); + CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n", + 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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac_dma.h b/drivers/net/ethernet/rockchip/gmac/dwmac_dma.h new file mode 100755 index 000000000000..8e5662ce488b --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac_dma.h @@ -0,0 +1,117 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#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 */ + +extern void dwmac_enable_dma_transmission(void __iomem *ioaddr); +extern void dwmac_enable_dma_irq(void __iomem *ioaddr); +extern void dwmac_disable_dma_irq(void __iomem *ioaddr); +extern void dwmac_dma_start_tx(void __iomem *ioaddr); +extern void dwmac_dma_stop_tx(void __iomem *ioaddr); +extern void dwmac_dma_start_rx(void __iomem *ioaddr); +extern void dwmac_dma_stop_rx(void __iomem *ioaddr); +extern int dwmac_dma_interrupt(void __iomem *ioaddr, + struct stmmac_extra_stats *x); + +#endif /* __DWMAC_DMA_H__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/dwmac_lib.c b/drivers/net/ethernet/rockchip/gmac/dwmac_lib.c new file mode 100755 index 000000000000..491d7e930603 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/dwmac_lib.c @@ -0,0 +1,289 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#include "common.h" +#include "dwmac_dma.h" + +#undef DWMAC_DMA_DEBUG +#ifdef DWMAC_DMA_DEBUG +#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args) +#else +#define DWMAC_LIB_DBG(fmt, args...) do { } while (0) +#endif + +#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_info("- TX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- TX (Running):Fetching the Tx desc\n"); + break; + case 2: + pr_info("- TX (Running): Waiting for end of tx\n"); + break; + case 3: + pr_info("- TX (Running): Reading the data " + "and queuing the data into the Tx buf\n"); + break; + case 6: + pr_info("- TX (Suspended): Tx Buff Underflow " + "or an unavailable Transmit descriptor\n"); + break; + case 7: + pr_info("- 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_info("- RX (Stopped): Reset or Stop command\n"); + break; + case 1: + pr_info("- RX (Running): Fetching the Rx desc\n"); + break; + case 2: + pr_info("- RX (Running):Checking for end of pkt\n"); + break; + case 3: + pr_info("- RX (Running): Waiting for Rx pkt\n"); + break; + case 4: + pr_info("- RX (Suspended): Unavailable Rx buf\n"); + break; + case 5: + pr_info("- RX (Running): Closing Rx descriptor\n"); + break; + case 6: + pr_info("- RX(Running): Flushing the current frame" + " from the Rx buf\n"); + break; + case 7: + pr_info("- 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); + + DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status); +#ifdef DWMAC_DMA_DEBUG + /* It displays the DMA process states (CSR5 register) */ + show_tx_process_state(intr_status); + show_rx_process_state(intr_status); +#endif + /* ABNORMAL interrupts */ + if (unlikely(intr_status & DMA_STATUS_AIS)) { + DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: "); + if (unlikely(intr_status & DMA_STATUS_UNF)) { + DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n"); + ret = tx_hard_error_bump_tc; + x->tx_undeflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TJT)) { + DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n"); + x->tx_jabber_irq++; + } + if (unlikely(intr_status & DMA_STATUS_OVF)) { + DWMAC_LIB_DBG(KERN_INFO "recv overflow\n"); + x->rx_overflow_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RU)) { + DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n"); + x->rx_buf_unav_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RPS)) { + DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n"); + x->rx_process_stopped_irq++; + } + if (unlikely(intr_status & DMA_STATUS_RWT)) { + DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n"); + x->rx_watchdog_irq++; + } + if (unlikely(intr_status & DMA_STATUS_ETI)) { + DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n"); + x->tx_early_irq++; + } + if (unlikely(intr_status & DMA_STATUS_TPS)) { + DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n"); + x->tx_process_stopped_irq++; + ret = tx_hard_error; + } + if (unlikely(intr_status & DMA_STATUS_FBI)) { + DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n"); + 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_info("%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); + + DWMAC_LIB_DBG(KERN_INFO "\n\n"); + 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; +} + diff --git a/drivers/net/ethernet/rockchip/gmac/enh_desc.c b/drivers/net/ethernet/rockchip/gmac/enh_desc.c new file mode 100755 index 000000000000..0fbc8fafa706 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/enh_desc.c @@ -0,0 +1,445 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#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)) { + CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx); + if (unlikely(p->des01.etx.jabber_timeout)) { + CHIP_DBG(KERN_ERR "\tjabber_timeout error\n"); + x->tx_jabber++; + } + + if (unlikely(p->des01.etx.frame_flushed)) { + CHIP_DBG(KERN_ERR "\tframe_flushed error\n"); + x->tx_frame_flushed++; + dwmac_dma_flush_tx_fifo(ioaddr); + } + + if (unlikely(p->des01.etx.loss_carrier)) { + CHIP_DBG(KERN_ERR "\tloss_carrier error\n"); + x->tx_losscarrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.etx.no_carrier)) { + CHIP_DBG(KERN_ERR "\tno_carrier error\n"); + x->tx_carrier++; + stats->tx_carrier_errors++; + } + if (unlikely(p->des01.etx.late_collision)) { + CHIP_DBG(KERN_ERR "\tlate_collision error\n"); + stats->collisions += p->des01.etx.collision_count; + } + if (unlikely(p->des01.etx.excessive_collisions)) { + CHIP_DBG(KERN_ERR "\texcessive_collisions\n"); + stats->collisions += p->des01.etx.collision_count; + } + if (unlikely(p->des01.etx.excessive_deferral)) { + CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n"); + x->tx_deferred++; + } + + if (unlikely(p->des01.etx.underflow_error)) { + CHIP_DBG(KERN_ERR "\tunderflow error\n"); + dwmac_dma_flush_tx_fifo(ioaddr); + x->tx_underflow++; + } + + if (unlikely(p->des01.etx.ip_header_error)) { + CHIP_DBG(KERN_ERR "\tTX IP header csum error\n"); + x->tx_ip_header_error++; + } + + if (unlikely(p->des01.etx.payload_error)) { + CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n"); + x->tx_payload_error++; + dwmac_dma_flush_tx_fifo(ioaddr); + } + + ret = -1; + } + + if (unlikely(p->des01.etx.deferred)) { + CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n"); + x->tx_deferred++; + } +#ifdef STMMAC_VLAN_TAG_USED + if (p->des01.etx.vlan_frame) { + CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n"); + 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) { + CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n"); + ret = llc_snap; + } else if (status == 0x4) { + CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n"); + ret = good_frame; + } else if (status == 0x5) { + CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n"); + ret = csum_none; + } else if (status == 0x6) { + CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n"); + ret = csum_none; + } else if (status == 0x7) { + CHIP_DBG(KERN_ERR + "RX Des0 status: IPv4/6 Header and Payload Error.\n"); + ret = csum_none; + } else if (status == 0x1) { + CHIP_DBG(KERN_ERR + "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n"); + ret = discard_frame; + } else if (status == 0x3) { + CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n"); + 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_DELAY_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)) { + CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n", + p->des01.erx); + if (unlikely(p->des01.erx.descriptor_error)) { + CHIP_DBG(KERN_ERR "\tdescriptor error\n"); + x->rx_desc++; + stats->rx_length_errors++; + } + if (unlikely(p->des01.erx.overflow_error)) { + CHIP_DBG(KERN_ERR "\toverflow error\n"); + x->rx_gmac_overflow++; + } + + if (unlikely(p->des01.erx.ipc_csum_error)) + CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n"); + + if (unlikely(p->des01.erx.late_collision)) { + CHIP_DBG(KERN_ERR "\tlate_collision error\n"); + stats->collisions++; + stats->collisions++; + } + if (unlikely(p->des01.erx.receive_watchdog)) { + CHIP_DBG(KERN_ERR "\treceive_watchdog error\n"); + x->rx_watchdog++; + } + if (unlikely(p->des01.erx.error_gmii)) { + CHIP_DBG(KERN_ERR "\tReceive Error\n"); + x->rx_mii++; + } + if (unlikely(p->des01.erx.crc_error)) { + CHIP_DBG(KERN_ERR "\tCRC error\n"); + 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)) { + CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n"); + x->dribbling_bit++; + } + if (unlikely(p->des01.erx.sa_filter_fail)) { + CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n"); + x->sa_rx_filter_fail++; + ret = discard_frame; + } + if (unlikely(p->des01.erx.da_filter_fail)) { + CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n"); + x->da_rx_filter_fail++; + ret = discard_frame; + } + if (unlikely(p->des01.erx.length_error)) { + CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n"); + x->rx_length++; + ret = discard_frame; + } +#ifdef STMMAC_VLAN_TAG_USED + if (p->des01.erx.vlan_tag) { + CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n"); + 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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.IAB b/drivers/net/ethernet/rockchip/gmac/gmac.IAB new file mode 100755 index 0000000000000000000000000000000000000000..f90b041ac88cc45bec508cb6077571b767f5c008 GIT binary patch literal 147456 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 literal 0 HcmV?d00001 diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.IAD b/drivers/net/ethernet/rockchip/gmac/gmac.IAD new file mode 100755 index 0000000000000000000000000000000000000000..ef8e68acbb8f80667f6f2bd3f1898cc392ca3873 GIT binary patch literal 1768 zcmc(fziU%b6vt0~;3W7IK?R2(9UL6e4vM%Wq*1}9#`J+hhvv1W@USm=q_M`SuQ-T{ zM8$%*#7Q@UKX7r#;AV%6F47bnDlP#9i#quI-g}c9|AHRKH|L%6dH0@o&VBFEQIRQ` zN=Quh)g0`9PO1w-J-W z45PJ@t=6jaBZ>pgp`*<+9M&6g&zMSqOVQCbZ@4%v7jG>uGy0H{2A8IzZ9SpuJBZ8N ztXpFAJ|zP#Lr2>Y(OeQ`<*t_UjJ~84!4>If`-=@@K=B+=u2ElM^eLqbu1rVUbyFYq zjixKBON>U85L`${+qUXbg8dzF_n3;nMVg_W65T)6HywC7!FyZaTKbZD!OTN(g{(?M z)Hb*_9c_!r(L6@$J!h%|u45ql{V@BYKFNFfc~zgg;JTLkG|tuQHD)#`J#alb+Fl!u z^T;^q-qkEJAxB(q)4-Ciicd4Q` tyG>E&?=86$xRm9#?Y@zFCsgaH?@$_C+H$;gH=)nH{&t^>XFAsu@DG#mn1KKQ literal 0 HcmV?d00001 diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.IMB b/drivers/net/ethernet/rockchip/gmac/gmac.IMB new file mode 100755 index 0000000000000000000000000000000000000000..cbdb4abb3cf17f8c4cc4effc1a85cf59b1c018a0 GIT binary patch literal 36864 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 Rxi4-8+zhxG_%F!7{{Wes=?MS; literal 0 HcmV?d00001 diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.IMD b/drivers/net/ethernet/rockchip/gmac/gmac.IMD new file mode 100755 index 0000000000000000000000000000000000000000..eb6fd7d2bc3976a9cba96197e414b55e4a3b77a8 GIT binary patch literal 688 zcmbOv!oXm}V8qP8$S|Nl0BHXdrU7*V*m6!F3Bnpc`~~PHh31d3vi=^-gHI=L9j58NXbnEt7`xW2msXyfEW;*wAPmd|eHa4`dh$&9V zjyKUWiOEha%1h1BH3lk)Nh!)KOD!sn$xAJXNiE3$$&>)q$E4>bCZiiYB=`%M7#K2! rgiC4X$OHNh$u^t|sFMY%`$pDMh6UM685p7b6d=u!d50n4!A%AL@}VR3 literal 0 HcmV?d00001 diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.PR b/drivers/net/ethernet/rockchip/gmac/gmac.PR new file mode 100755 index 0000000000000000000000000000000000000000..d6ed8d592322fa8df3537b5ebcec01df98897c2f GIT binary patch literal 8624 zcmeI%O-NKx6u|K_X_lE*YL*pLBosz!u7a!xDacK2vJa4PoSB*d-#nXn_uT{U5^EWMTzT(In@A(C zN0xooJ%(<+=lO-6oEx*&JGWlei%*0u8{bdVR#3N0wv;Z}WfSN2LEYe5Lwwx2O1EU% z_l(*(w=cNefvb*~YY}OnKfVHAm~WF_Dt)-G&nR1zZ@nbiO`Ph9uN^CZRfenGtiri` zTfnWEoYVTSzxyBDn5#vDHPyL&!|fq%IzOimiR@82p5xk*d`o7$l)e<}`* zvB)i)qc*p`Zl0dS?K&nKi22p*-*g|69M6v#T-!9AoZBdFd#M9Wj9u7Wt_!-}#Wl^h zY$2D_GlNmK$n6Gh&vDxb)KI_3N%}sXo^p9$|74wCwhOghE z^=%NhDV(^HmIabd_rHTR+)9B*LAATYxqN$q+bm9cPMF}{lH)^ommf!`^R(=i%m%r@ z_s8v3Rp<5ww{~hnSQ0LY90P2oMm?>#x9nIo)ooiC*=7Cg~bDIk3#dwraQWRB(l@oH;xqQ?QYPel_=&&&ROcIRCNGkl+f&?zAnGJ8>fydd F`vVm7YP@*Bv`=UMA2sd8{ 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 literal 0 HcmV?d00001 diff --git a/drivers/net/ethernet/rockchip/gmac/gmac.PS b/drivers/net/ethernet/rockchip/gmac/gmac.PS new file mode 100755 index 0000000000000000000000000000000000000000..4baafe199940a70f4038276f0015415e3a9ae3c5 GIT binary patch literal 249740 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 +*******************************************************************************/ + +#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_errror; + unsigned int mmc_rx_align_error; + unsigned int mmc_rx_run_error; + unsigned int mmc_rx_jabber_error; + unsigned int mmc_rx_undersize_g; + unsigned int mmc_rx_oversize_g; + unsigned int mmc_rx_64_octets_gb; + unsigned int mmc_rx_65_to_127_octets_gb; + unsigned int mmc_rx_128_to_255_octets_gb; + unsigned int mmc_rx_256_to_511_octets_gb; + unsigned int mmc_rx_512_to_1023_octets_gb; + unsigned int mmc_rx_1024_to_max_octets_gb; + unsigned int mmc_rx_unicast_g; + unsigned int mmc_rx_length_error; + unsigned int mmc_rx_autofrangetype; + unsigned int mmc_rx_pause_frames; + unsigned int mmc_rx_fifo_overflow; + unsigned int mmc_rx_vlan_frames_gb; + unsigned int mmc_rx_watchdog_error; + /* IPC */ + unsigned int mmc_rx_ipc_intr_mask; + unsigned int mmc_rx_ipc_intr; + /* IPv4 */ + unsigned int mmc_rx_ipv4_gd; + unsigned int mmc_rx_ipv4_hderr; + unsigned int mmc_rx_ipv4_nopay; + unsigned int mmc_rx_ipv4_frag; + unsigned int mmc_rx_ipv4_udsbl; + + unsigned int mmc_rx_ipv4_gd_octets; + unsigned int mmc_rx_ipv4_hderr_octets; + unsigned int mmc_rx_ipv4_nopay_octets; + unsigned int mmc_rx_ipv4_frag_octets; + unsigned int mmc_rx_ipv4_udsbl_octets; + + /* IPV6 */ + unsigned int mmc_rx_ipv6_gd_octets; + unsigned int mmc_rx_ipv6_hderr_octets; + unsigned int mmc_rx_ipv6_nopay_octets; + + unsigned int mmc_rx_ipv6_gd; + unsigned int mmc_rx_ipv6_hderr; + unsigned int mmc_rx_ipv6_nopay; + + /* Protocols */ + unsigned int mmc_rx_udp_gd; + unsigned int mmc_rx_udp_err; + unsigned int mmc_rx_tcp_gd; + unsigned int mmc_rx_tcp_err; + unsigned int mmc_rx_icmp_gd; + unsigned int mmc_rx_icmp_err; + + unsigned int mmc_rx_udp_gd_octets; + unsigned int mmc_rx_udp_err_octets; + unsigned int mmc_rx_tcp_gd_octets; + unsigned int mmc_rx_tcp_err_octets; + unsigned int mmc_rx_icmp_gd_octets; + unsigned int mmc_rx_icmp_err_octets; +}; + +extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode); +extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr); +extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc); + +#endif /* __MMC_H__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/mmc_core.c b/drivers/net/ethernet/rockchip/gmac/mmc_core.c new file mode 100755 index 000000000000..50617c5a0bdb --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/mmc_core.c @@ -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 +*******************************************************************************/ + +#include +#include +#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_errror += readl(ioaddr + MMC_RX_CRC_ERRROR); + mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR); + mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR); + mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR); + mmc->mmc_rx_undersize_g += readl(ioaddr + MMC_RX_UNDERSIZE_G); + mmc->mmc_rx_oversize_g += readl(ioaddr + MMC_RX_OVERSIZE_G); + mmc->mmc_rx_64_octets_gb += readl(ioaddr + MMC_RX_64_OCTETS_GB); + mmc->mmc_rx_65_to_127_octets_gb += + readl(ioaddr + MMC_RX_65_TO_127_OCTETS_GB); + mmc->mmc_rx_128_to_255_octets_gb += + readl(ioaddr + MMC_RX_128_TO_255_OCTETS_GB); + mmc->mmc_rx_256_to_511_octets_gb += + readl(ioaddr + MMC_RX_256_TO_511_OCTETS_GB); + mmc->mmc_rx_512_to_1023_octets_gb += + readl(ioaddr + MMC_RX_512_TO_1023_OCTETS_GB); + mmc->mmc_rx_1024_to_max_octets_gb += + readl(ioaddr + MMC_RX_1024_TO_MAX_OCTETS_GB); + mmc->mmc_rx_unicast_g += readl(ioaddr + MMC_RX_UNICAST_G); + mmc->mmc_rx_length_error += readl(ioaddr + MMC_RX_LENGTH_ERROR); + mmc->mmc_rx_autofrangetype += readl(ioaddr + MMC_RX_AUTOFRANGETYPE); + mmc->mmc_rx_pause_frames += readl(ioaddr + MMC_RX_PAUSE_FRAMES); + mmc->mmc_rx_fifo_overflow += readl(ioaddr + MMC_RX_FIFO_OVERFLOW); + mmc->mmc_rx_vlan_frames_gb += readl(ioaddr + MMC_RX_VLAN_FRAMES_GB); + mmc->mmc_rx_watchdog_error += readl(ioaddr + MMC_RX_WATCHDOG_ERROR); + /* IPC */ + mmc->mmc_rx_ipc_intr_mask += readl(ioaddr + MMC_RX_IPC_INTR_MASK); + mmc->mmc_rx_ipc_intr += readl(ioaddr + MMC_RX_IPC_INTR); + /* IPv4 */ + mmc->mmc_rx_ipv4_gd += readl(ioaddr + MMC_RX_IPV4_GD); + mmc->mmc_rx_ipv4_hderr += readl(ioaddr + MMC_RX_IPV4_HDERR); + mmc->mmc_rx_ipv4_nopay += readl(ioaddr + MMC_RX_IPV4_NOPAY); + mmc->mmc_rx_ipv4_frag += readl(ioaddr + MMC_RX_IPV4_FRAG); + mmc->mmc_rx_ipv4_udsbl += readl(ioaddr + MMC_RX_IPV4_UDSBL); + + mmc->mmc_rx_ipv4_gd_octets += readl(ioaddr + MMC_RX_IPV4_GD_OCTETS); + mmc->mmc_rx_ipv4_hderr_octets += + readl(ioaddr + MMC_RX_IPV4_HDERR_OCTETS); + mmc->mmc_rx_ipv4_nopay_octets += + readl(ioaddr + MMC_RX_IPV4_NOPAY_OCTETS); + mmc->mmc_rx_ipv4_frag_octets += readl(ioaddr + MMC_RX_IPV4_FRAG_OCTETS); + mmc->mmc_rx_ipv4_udsbl_octets += + readl(ioaddr + MMC_RX_IPV4_UDSBL_OCTETS); + + /* IPV6 */ + mmc->mmc_rx_ipv6_gd_octets += readl(ioaddr + MMC_RX_IPV6_GD_OCTETS); + mmc->mmc_rx_ipv6_hderr_octets += + readl(ioaddr + MMC_RX_IPV6_HDERR_OCTETS); + mmc->mmc_rx_ipv6_nopay_octets += + readl(ioaddr + MMC_RX_IPV6_NOPAY_OCTETS); + + mmc->mmc_rx_ipv6_gd += readl(ioaddr + MMC_RX_IPV6_GD); + mmc->mmc_rx_ipv6_hderr += readl(ioaddr + MMC_RX_IPV6_HDERR); + mmc->mmc_rx_ipv6_nopay += readl(ioaddr + MMC_RX_IPV6_NOPAY); + + /* Protocols */ + mmc->mmc_rx_udp_gd += readl(ioaddr + MMC_RX_UDP_GD); + mmc->mmc_rx_udp_err += readl(ioaddr + MMC_RX_UDP_ERR); + mmc->mmc_rx_tcp_gd += readl(ioaddr + MMC_RX_TCP_GD); + mmc->mmc_rx_tcp_err += readl(ioaddr + MMC_RX_TCP_ERR); + mmc->mmc_rx_icmp_gd += readl(ioaddr + MMC_RX_ICMP_GD); + mmc->mmc_rx_icmp_err += readl(ioaddr + MMC_RX_ICMP_ERR); + + mmc->mmc_rx_udp_gd_octets += readl(ioaddr + MMC_RX_UDP_GD_OCTETS); + mmc->mmc_rx_udp_err_octets += readl(ioaddr + MMC_RX_UDP_ERR_OCTETS); + mmc->mmc_rx_tcp_gd_octets += readl(ioaddr + MMC_RX_TCP_GD_OCTETS); + mmc->mmc_rx_tcp_err_octets += readl(ioaddr + MMC_RX_TCP_ERR_OCTETS); + mmc->mmc_rx_icmp_gd_octets += readl(ioaddr + MMC_RX_ICMP_GD_OCTETS); + mmc->mmc_rx_icmp_err_octets += readl(ioaddr + MMC_RX_ICMP_ERR_OCTETS); +} diff --git a/drivers/net/ethernet/rockchip/gmac/norm_desc.c b/drivers/net/ethernet/rockchip/gmac/norm_desc.c new file mode 100755 index 000000000000..11775b99afc5 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/norm_desc.c @@ -0,0 +1,275 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#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) { + CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n"); + 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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/ring_mode.c b/drivers/net/ethernet/rockchip/gmac/ring_mode.c new file mode 100755 index 000000000000..c9d942a5c335 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/ring_mode.c @@ -0,0 +1,127 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include "stmmac.h" + +static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)p; + unsigned int txsize = priv->dma_tx_size; + unsigned int entry = priv->cur_tx % txsize; + struct dma_desc *desc = priv->dma_tx + entry; + unsigned int nopaged_len = skb_headlen(skb); + unsigned int bmax, len; + + if (priv->plat->enh_desc) + bmax = BUF_SIZE_8KiB; + else + bmax = BUF_SIZE_2KiB; + + len = nopaged_len - bmax; + + if (nopaged_len > BUF_SIZE_8KiB) { + + desc->des2 = dma_map_single(priv->device, skb->data, + bmax, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + desc->des3 = desc->des2 + BUF_SIZE_4KiB; + priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, + STMMAC_RING_MODE); + wmb(); + entry = (++priv->cur_tx) % txsize; + desc = priv->dma_tx + entry; + + desc->des2 = dma_map_single(priv->device, skb->data + bmax, + len, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = 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); + priv->tx_skbuff[entry] = NULL; + } else { + desc->des2 = dma_map_single(priv->device, skb->data, + nopaged_len, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = 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; + + if (unlikely(priv->plat->has_gmac)) + /* 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_ring_mode_ops ring_mode_ops = { + .is_jumbo_frm = stmmac_is_jumbo_frm, + .jumbo_frm = stmmac_jumbo_frm, + .refill_desc3 = stmmac_refill_desc3, + .init_desc3 = stmmac_init_desc3, + .clean_desc3 = stmmac_clean_desc3, + .set_16kib_bfsize = stmmac_set_16kib_bfsize, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac.h b/drivers/net/ethernet/rockchip/gmac/stmmac.h new file mode 100755 index 000000000000..f1970c4acbfd --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac.h @@ -0,0 +1,180 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#ifndef __STMMAC_H__ +#define __STMMAC_H__ + +#define STMMAC_RESOURCE_NAME "stmmaceth" +#define DRV_MODULE_VERSION "March_2013" + +#include +#include +#include +#include +#include "common.h" +#include + +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; + dma_addr_t *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; + int no_csum_insertion; + 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; + 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; + u32 adv_ts; + int use_riwt; + spinlock_t ptp_lock; +}; + +extern int phyaddr; + +extern int stmmac_mdio_unregister(struct net_device *ndev); +extern int stmmac_mdio_register(struct net_device *ndev); +extern void stmmac_set_ethtool_ops(struct net_device *netdev); +extern const struct stmmac_desc_ops enh_desc_ops; +extern const struct stmmac_desc_ops ndesc_ops; +extern const struct stmmac_hwtimestamp stmmac_ptp; +extern int stmmac_ptp_register(struct stmmac_priv *priv); +extern void stmmac_ptp_unregister(struct stmmac_priv *priv); +int stmmac_freeze(struct net_device *ndev); +int stmmac_restore(struct net_device *ndev); +int stmmac_resume(struct net_device *ndev); +int stmmac_suspend(struct net_device *ndev); +int stmmac_dvr_remove(struct net_device *ndev); +struct stmmac_priv *stmmac_dvr_probe(struct device *device, + struct plat_stmmacenet_data *plat_dat, + void __iomem *addr); +void stmmac_disable_eee_mode(struct stmmac_priv *priv); +bool stmmac_eee_init(struct stmmac_priv *priv); + +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); +} + +#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__ */ diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c b/drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c new file mode 100755 index 000000000000..c5f9cb85c8ef --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c @@ -0,0 +1,788 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#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_errror), + STMMAC_MMC_STAT(mmc_rx_align_error), + STMMAC_MMC_STAT(mmc_rx_run_error), + STMMAC_MMC_STAT(mmc_rx_jabber_error), + STMMAC_MMC_STAT(mmc_rx_undersize_g), + STMMAC_MMC_STAT(mmc_rx_oversize_g), + STMMAC_MMC_STAT(mmc_rx_64_octets_gb), + STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb), + STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb), + STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb), + STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb), + STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb), + STMMAC_MMC_STAT(mmc_rx_unicast_g), + STMMAC_MMC_STAT(mmc_rx_length_error), + STMMAC_MMC_STAT(mmc_rx_autofrangetype), + STMMAC_MMC_STAT(mmc_rx_pause_frames), + STMMAC_MMC_STAT(mmc_rx_fifo_overflow), + STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb), + STMMAC_MMC_STAT(mmc_rx_watchdog_error), + STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask), + STMMAC_MMC_STAT(mmc_rx_ipc_intr), + STMMAC_MMC_STAT(mmc_rx_ipv4_gd), + STMMAC_MMC_STAT(mmc_rx_ipv4_hderr), + STMMAC_MMC_STAT(mmc_rx_ipv4_nopay), + STMMAC_MMC_STAT(mmc_rx_ipv4_frag), + STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl), + STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets), + STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets), + STMMAC_MMC_STAT(mmc_rx_ipv6_gd), + STMMAC_MMC_STAT(mmc_rx_ipv6_hderr), + STMMAC_MMC_STAT(mmc_rx_ipv6_nopay), + STMMAC_MMC_STAT(mmc_rx_udp_gd), + STMMAC_MMC_STAT(mmc_rx_udp_err), + STMMAC_MMC_STAT(mmc_rx_tcp_gd), + STMMAC_MMC_STAT(mmc_rx_tcp_err), + STMMAC_MMC_STAT(mmc_rx_icmp_gd), + STMMAC_MMC_STAT(mmc_rx_icmp_err), + STMMAC_MMC_STAT(mmc_rx_udp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_udp_err_octets), + STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), + STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), + STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), +}; +#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) + +static void stmmac_ethtool_getdrvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (priv->plat->has_gmac) + 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) + priv->hw->mac->get_adv(priv->ioaddr, &adv); + else + return -EOPNOTSUPP; /* should never happen indeed */ + + /* 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; + spin_lock_irq(&priv->lock); + rc = phy_ethtool_gset(phy, cmd); + spin_unlock_irq(&priv->lock); + 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; + + if (cmd->autoneg == AUTONEG_ENABLE) { + 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->ioaddr, 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; + + spin_lock(&priv->lock); + + 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; + + spin_unlock(&priv->lock); +} + +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; + + spin_lock(&priv->lock); + + 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->ioaddr, phy->duplex, + priv->flow_ctrl, priv->pause); + spin_unlock(&priv->lock); + 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) +{ + SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops); +} diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c b/drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c new file mode 100755 index 000000000000..def7e75e1d57 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c @@ -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 + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#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 * 100) / 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, +}; diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_main.c b/drivers/net/ethernet/rockchip/gmac/stmmac_main.c new file mode 100755 index 000000000000..8d2da8b562d9 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_main.c @@ -0,0 +1,2956 @@ +/******************************************************************************* + This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers. + ST Ethernet IPs are built around a Synopsys IP Core. + + Copyright(C) 2007-2011 STMicroelectronics Ltd + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Author: Giuseppe Cavallaro + + Documentation available at: + http://www.stlinux.com + Support available at: + https://bugzilla.stlinux.com/ +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_GMAC_DEBUG_FS +#include +#include +#endif /* CONFIG_GMAC_DEBUG_FS */ +#include +#include "stmmac_ptp.h" +#include "stmmac.h" + +#undef STMMAC_DEBUG +/*#define STMMAC_DEBUG*/ +#ifdef STMMAC_DEBUG +#define DBG(nlevel, klevel, fmt, args...) \ + ((void)(netif_msg_##nlevel(priv) && \ + printk(KERN_##klevel fmt, ## args))) +#else +#define DBG(nlevel, klevel, fmt, args...) do { } while (0) +#endif + +#undef STMMAC_RX_DEBUG +/*#define STMMAC_RX_DEBUG*/ +#ifdef STMMAC_RX_DEBUG +#define RX_DBG(fmt, args...) printk(fmt, ## args) +#else +#define RX_DBG(fmt, args...) do { } while (0) +#endif + +#undef STMMAC_XMIT_DEBUG +/*#define STMMAC_XMIT_DEBUG*/ +#ifdef STMMAC_XMIT_DEBUG +#define TX_DBG(fmt, args...) printk(fmt, ## args) +#else +#define TX_DBG(fmt, args...) do { } while (0) +#endif + +#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) +#define JUMBO_LEN 9000 + +/* Module parameters */ +#define TX_TIMEO 5000 +static int watchdog = TX_TIMEO; +module_param(watchdog, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds (default 5s)"); + +static int debug = -1; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); + +int phyaddr = -1; +module_param(phyaddr, int, S_IRUGO); +MODULE_PARM_DESC(phyaddr, "Physical device address"); + +#define DMA_TX_SIZE 256 +static int dma_txsize = DMA_TX_SIZE; +module_param(dma_txsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list"); + +#define DMA_RX_SIZE 256 +static int dma_rxsize = DMA_RX_SIZE; +module_param(dma_rxsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list"); + +static int flow_ctrl = FLOW_OFF; +module_param(flow_ctrl, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(flow_ctrl, "Flow control ability [on/off]"); + +static int pause = PAUSE_TIME; +module_param(pause, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pause, "Flow Control Pause Time"); + +#define TC_DEFAULT 64 +static int tc = TC_DEFAULT; +module_param(tc, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tc, "DMA threshold control value"); + +#define DMA_BUFFER_SIZE BUF_SIZE_2KiB +static int buf_sz = DMA_BUFFER_SIZE; +module_param(buf_sz, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(buf_sz, "DMA buffer size"); + +static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | + NETIF_MSG_LINK | NETIF_MSG_IFUP | + NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); + +#define STMMAC_DEFAULT_LPI_TIMER 1000 +static int eee_timer = STMMAC_DEFAULT_LPI_TIMER; +module_param(eee_timer, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec"); +#define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x)) + +/* By default the driver will use the ring mode to manage tx and rx descriptors + * but passing this value so user can force to use the chain instead of the ring + */ +static unsigned int chain_mode; +module_param(chain_mode, int, S_IRUGO); +MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode"); + +static irqreturn_t stmmac_interrupt(int irq, void *dev_id); + +#ifdef CONFIG_GMAC_DEBUG_FS +static int stmmac_init_fs(struct net_device *dev); +static void stmmac_exit_fs(void); +#endif + +#define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x)) + +/** + * stmmac_verify_args - verify the driver parameters. + * Description: it verifies if some wrong parameter is passed to the driver. + * Note that wrong parameters are replaced with the default values. + */ +static void stmmac_verify_args(void) +{ + if (unlikely(watchdog < 0)) + watchdog = TX_TIMEO; + if (unlikely(dma_rxsize < 0)) + dma_rxsize = DMA_RX_SIZE; + if (unlikely(dma_txsize < 0)) + dma_txsize = DMA_TX_SIZE; + if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB))) + buf_sz = DMA_BUFFER_SIZE; + if (unlikely(flow_ctrl > 1)) + flow_ctrl = FLOW_AUTO; + else if (likely(flow_ctrl < 0)) + flow_ctrl = FLOW_OFF; + if (unlikely((pause < 0) || (pause > 0xffff))) + pause = PAUSE_TIME; + if (eee_timer < 0) + eee_timer = STMMAC_DEFAULT_LPI_TIMER; +} + +/** + * stmmac_clk_csr_set - dynamically set the MDC clock + * @priv: driver private structure + * Description: this is to dynamically set the MDC clock according to the csr + * clock input. + * Note: + * If a specific clk_csr value is passed from the platform + * this means that the CSR Clock Range selection cannot be + * changed at run-time and it is fixed (as reported in the driver + * documentation). Viceversa the driver will try to set the MDC + * clock dynamically according to the actual clock input. + */ +static void stmmac_clk_csr_set(struct stmmac_priv *priv) +{ + u32 clk_rate; + + clk_rate = clk_get_rate(priv->stmmac_clk); + + /* Platform provided default clk_csr would be assumed valid + * for all other cases except for the below mentioned ones. + * For values higher than the IEEE 802.3 specified frequency + * we can not estimate the proper divider as it is not known + * the frequency of clk_csr_i. So we do not change the default + * divider. + */ + if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) { + if (clk_rate < CSR_F_35M) + priv->clk_csr = STMMAC_CSR_20_35M; + else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M)) + priv->clk_csr = STMMAC_CSR_35_60M; + else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M)) + priv->clk_csr = STMMAC_CSR_60_100M; + else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M)) + priv->clk_csr = STMMAC_CSR_100_150M; + else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) + priv->clk_csr = STMMAC_CSR_150_250M; + else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) + priv->clk_csr = STMMAC_CSR_250_300M; + } +} + +#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG) +static void print_pkt(unsigned char *buf, int len) +{ + int j; + pr_info("len = %d byte, buf addr: 0x%p", len, buf); + for (j = 0; j < len; j++) { + if ((j % 16) == 0) + pr_info("\n %03x:", j); + pr_info(" %02x", buf[j]); + } + pr_info("\n"); +} +#endif + +/* minimum number of free TX descriptors required to wake up TX process */ +#define STMMAC_TX_THRESH(x) (x->dma_tx_size/4) + +static inline u32 stmmac_tx_avail(struct stmmac_priv *priv) +{ + return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1; +} + +/** + * stmmac_hw_fix_mac_speed: callback for speed selection + * @priv: driver private structure + * Description: on some platforms (e.g. ST), some HW system configuraton + * registers have to be set according to the link speed negotiated. + */ +static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv) +{ + struct phy_device *phydev = priv->phydev; + + if (likely(priv->plat->fix_mac_speed)) + priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed); +} + +/** + * stmmac_enable_eee_mode: Check and enter in LPI mode + * @priv: driver private structure + * Description: this function is to verify and enter in LPI mode for EEE. + */ +static void stmmac_enable_eee_mode(struct stmmac_priv *priv) +{ + /* Check and enter in LPI mode */ + if ((priv->dirty_tx == priv->cur_tx) && + (priv->tx_path_in_lpi_mode == false)) + priv->hw->mac->set_eee_mode(priv->ioaddr); +} + +/** + * stmmac_disable_eee_mode: disable/exit from EEE + * @priv: driver private structure + * Description: this function is to exit and disable EEE in case of + * LPI state is true. This is called by the xmit. + */ +void stmmac_disable_eee_mode(struct stmmac_priv *priv) +{ + priv->hw->mac->reset_eee_mode(priv->ioaddr); + del_timer_sync(&priv->eee_ctrl_timer); + priv->tx_path_in_lpi_mode = false; +} + +/** + * stmmac_eee_ctrl_timer: EEE TX SW timer. + * @arg : data hook + * Description: + * if there is no data transfer and if we are not in LPI state, + * then MAC Transmitter can be moved to LPI state. + */ +static void stmmac_eee_ctrl_timer(unsigned long arg) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)arg; + + stmmac_enable_eee_mode(priv); + mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer)); +} + +/** + * stmmac_eee_init: init EEE + * @priv: driver private structure + * Description: + * If the EEE support has been enabled while configuring the driver, + * if the GMAC actually supports the EEE (from the HW cap reg) and the + * phy can also manage EEE, so enable the LPI state and start the timer + * to verify if the tx path can enter in LPI state. + */ +bool stmmac_eee_init(struct stmmac_priv *priv) +{ + bool ret = false; + + /* Using PCS we cannot dial with the phy registers at this stage + * so we do not support extra feature like EEE. + */ + if ((priv->pcs == STMMAC_PCS_RGMII) || (priv->pcs == STMMAC_PCS_TBI) || + (priv->pcs == STMMAC_PCS_RTBI)) + goto out; + + /* MAC core supports the EEE feature. */ + if (priv->dma_cap.eee) { + /* Check if the PHY supports EEE */ + if (phy_init_eee(priv->phydev, 1)) + goto out; + + if (!priv->eee_active) { + priv->eee_active = 1; + init_timer(&priv->eee_ctrl_timer); + priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer; + priv->eee_ctrl_timer.data = (unsigned long)priv; + priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer); + add_timer(&priv->eee_ctrl_timer); + + priv->hw->mac->set_eee_timer(priv->ioaddr, + STMMAC_DEFAULT_LIT_LS, + priv->tx_lpi_timer); + } else + /* Set HW EEE according to the speed */ + priv->hw->mac->set_eee_pls(priv->ioaddr, + priv->phydev->link); + + pr_info("stmmac: Energy-Efficient Ethernet initialized\n"); + + ret = true; + } +out: + return ret; +} + +/* stmmac_get_tx_hwtstamp: get HW TX timestamps + * @priv: driver private structure + * @entry : descriptor index to be used. + * @skb : the socket buffer + * Description : + * This function will read timestamp from the descriptor & pass it to stack. + * and also perform some sanity checks. + */ +static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, + unsigned int entry, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps shhwtstamp; + u64 ns; + void *desc = NULL; + + if (!priv->hwts_tx_en) + return; + + /* exit if skb doesn't support hw tstamp */ + if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))) + return; + + if (priv->adv_ts) + desc = (priv->dma_etx + entry); + else + desc = (priv->dma_tx + entry); + + /* check tx tstamp status */ + if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc)) + return; + + /* get the valid tstamp */ + ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts); + + memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); + shhwtstamp.hwtstamp = ns_to_ktime(ns); + /* pass tstamp to stack */ + skb_tstamp_tx(skb, &shhwtstamp); + + return; +} + +/* stmmac_get_rx_hwtstamp: get HW RX timestamps + * @priv: driver private structure + * @entry : descriptor index to be used. + * @skb : the socket buffer + * Description : + * This function will read received packet's timestamp from the descriptor + * and pass it to stack. It also perform some sanity checks. + */ +static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, + unsigned int entry, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps *shhwtstamp = NULL; + u64 ns; + void *desc = NULL; + + if (!priv->hwts_rx_en) + return; + + if (priv->adv_ts) + desc = (priv->dma_erx + entry); + else + desc = (priv->dma_rx + entry); + + /* exit if rx tstamp is not valid */ + if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts)) + return; + + /* get valid tstamp */ + ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts); + shhwtstamp = skb_hwtstamps(skb); + memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); + shhwtstamp->hwtstamp = ns_to_ktime(ns); +} + +/** + * stmmac_hwtstamp_ioctl - control hardware timestamping. + * @dev: device pointer. + * @ifr: An IOCTL specefic structure, that can contain a pointer to + * a proprietary structure used to pass information to the driver. + * Description: + * This function configures the MAC to enable/disable both outgoing(TX) + * and incoming(RX) packets time stamping based on user input. + * Return Value: + * 0 on success and an appropriate -ve integer on failure. + */ +static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct hwtstamp_config config; + struct timespec now; + u64 temp = 0; + u32 ptp_v2 = 0; + u32 tstamp_all = 0; + u32 ptp_over_ipv4_udp = 0; + u32 ptp_over_ipv6_udp = 0; + u32 ptp_over_ethernet = 0; + u32 snap_type_sel = 0; + u32 ts_master_en = 0; + u32 ts_event_en = 0; + u32 value = 0; + + if (!(priv->dma_cap.time_stamp || priv->adv_ts)) { + netdev_alert(priv->dev, "No support for HW time stamping\n"); + priv->hwts_tx_en = 0; + priv->hwts_rx_en = 0; + + return -EOPNOTSUPP; + } + + if (copy_from_user(&config, ifr->ifr_data, + sizeof(struct hwtstamp_config))) + return -EFAULT; + + pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n", + __func__, config.flags, config.tx_type, config.rx_filter); + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv->hwts_tx_en = 0; + break; + case HWTSTAMP_TX_ON: + priv->hwts_tx_en = 1; + break; + default: + return -ERANGE; + } + + if (priv->adv_ts) { + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + /* time stamp no incoming packet at all */ + config.rx_filter = HWTSTAMP_FILTER_NONE; + break; + + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + /* PTP v1, UDP, any kind of event packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + /* take time stamp for all event messages */ + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + /* PTP v1, UDP, Sync packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + /* take time stamp for SYNC messages only */ + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + /* PTP v1, UDP, Delay_req packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + /* take time stamp for Delay_Req messages only */ + ts_master_en = PTP_TCR_TSMSTRENA; + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + /* PTP v2, UDP, any kind of event packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for all event messages */ + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + /* PTP v2, UDP, Sync packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for SYNC messages only */ + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + /* PTP v2, UDP, Delay_req packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for Delay_Req messages only */ + ts_master_en = PTP_TCR_TSMSTRENA; + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_EVENT: + /* PTP v2/802.AS1 any layer, any kind of event packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for all event messages */ + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + ptp_over_ethernet = PTP_TCR_TSIPENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_SYNC: + /* PTP v2/802.AS1, any layer, Sync packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for SYNC messages only */ + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + ptp_over_ethernet = PTP_TCR_TSIPENA; + break; + + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + /* PTP v2/802.AS1, any layer, Delay_req packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; + ptp_v2 = PTP_TCR_TSVER2ENA; + /* take time stamp for Delay_Req messages only */ + ts_master_en = PTP_TCR_TSMSTRENA; + ts_event_en = PTP_TCR_TSEVNTENA; + + ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; + ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; + ptp_over_ethernet = PTP_TCR_TSIPENA; + break; + + case HWTSTAMP_FILTER_ALL: + /* time stamp any incoming packet */ + config.rx_filter = HWTSTAMP_FILTER_ALL; + tstamp_all = PTP_TCR_TSENALL; + break; + + default: + return -ERANGE; + } + } else { + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + config.rx_filter = HWTSTAMP_FILTER_NONE; + break; + default: + /* PTP v1, UDP, any kind of event packet */ + config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; + } + } + priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1); + + if (!priv->hwts_tx_en && !priv->hwts_rx_en) + priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0); + else { + value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR | + tstamp_all | ptp_v2 | ptp_over_ethernet | + ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | + ts_master_en | snap_type_sel); + + priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value); + + /* program Sub Second Increment reg */ + priv->hw->ptp->config_sub_second_increment(priv->ioaddr); + + /* calculate default added value: + * formula is : + * addend = (2^32)/freq_div_ratio; + * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz + * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK; + * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to + * achive 20ns accuracy. + * + * 2^x * y == (y << x), hence + * 2^32 * 50000000 ==> (50000000 << 32) + */ + temp = (u64) (50000000ULL << 32); + priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK); + priv->hw->ptp->config_addend(priv->ioaddr, + priv->default_addend); + + /* initialize system time */ + getnstimeofday(&now); + priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec, + now.tv_nsec); + } + + return copy_to_user(ifr->ifr_data, &config, + sizeof(struct hwtstamp_config)) ? -EFAULT : 0; +} + +/** + * stmmac_init_ptp: init PTP + * @priv: driver private structure + * Description: this is to verify if the HW supports the PTPv1 or v2. + * This is done by looking at the HW cap. register. + * Also it registers the ptp driver. + */ +static int stmmac_init_ptp(struct stmmac_priv *priv) +{ + if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) + return -EOPNOTSUPP; + + if (netif_msg_hw(priv)) { + if (priv->dma_cap.time_stamp) { + pr_debug("IEEE 1588-2002 Time Stamp supported\n"); + priv->adv_ts = 0; + } + if (priv->dma_cap.atime_stamp && priv->extend_desc) { + pr_debug + ("IEEE 1588-2008 Advanced Time Stamp supported\n"); + priv->adv_ts = 1; + } + } + + priv->hw->ptp = &stmmac_ptp; + priv->hwts_tx_en = 0; + priv->hwts_rx_en = 0; + + return stmmac_ptp_register(priv); +} + +static void stmmac_release_ptp(struct stmmac_priv *priv) +{ + stmmac_ptp_unregister(priv); +} + +/** + * stmmac_adjust_link + * @dev: net device structure + * Description: it adjusts the link parameters. + */ +static void stmmac_adjust_link(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + unsigned long flags; + int new_state = 0; + unsigned int fc = priv->flow_ctrl, pause_time = priv->pause; + + if (phydev == NULL) + return; + + DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n", + phydev->addr, phydev->link); + + spin_lock_irqsave(&priv->lock, flags); + + if (phydev->link) { + u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); + + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (phydev->duplex != priv->oldduplex) { + new_state = 1; + if (!(phydev->duplex)) + ctrl &= ~priv->hw->link.duplex; + else + ctrl |= priv->hw->link.duplex; + priv->oldduplex = phydev->duplex; + } + /* Flow Control operation */ + if (phydev->pause) + priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex, + fc, pause_time); + + if (phydev->speed != priv->speed) { + new_state = 1; + switch (phydev->speed) { + case 1000: + if (likely(priv->plat->has_gmac)) + ctrl &= ~priv->hw->link.port; + stmmac_hw_fix_mac_speed(priv); + break; + case 100: + case 10: + if (priv->plat->has_gmac) { + ctrl |= priv->hw->link.port; + if (phydev->speed == SPEED_100) { + ctrl |= priv->hw->link.speed; + } else { + ctrl &= ~(priv->hw->link.speed); + } + } else { + ctrl &= ~priv->hw->link.port; + } + stmmac_hw_fix_mac_speed(priv); + break; + default: + if (netif_msg_link(priv)) + pr_warn("%s: Speed (%d) not 10/100\n", + dev->name, phydev->speed); + break; + } + + priv->speed = phydev->speed; + } + + writel(ctrl, priv->ioaddr + MAC_CTRL_REG); + + if (!priv->oldlink) { + new_state = 1; + priv->oldlink = 1; + } + } else if (priv->oldlink) { + new_state = 1; + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; + } + + if (new_state && netif_msg_link(priv)) + phy_print_status(phydev); + + /* At this stage, it could be needed to setup the EEE or adjust some + * MAC related HW registers. + */ + priv->eee_enabled = stmmac_eee_init(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n"); +} + +/** + * stmmac_check_pcs_mode: verify if RGMII/SGMII is supported + * @priv: driver private structure + * Description: this is to verify if the HW supports the PCS. + * Physical Coding Sublayer (PCS) interface that can be used when the MAC is + * configured for the TBI, RTBI, or SGMII PHY interface. + */ +static void stmmac_check_pcs_mode(struct stmmac_priv *priv) +{ + int interface = priv->plat->interface; + + if (priv->dma_cap.pcs) { + if ((interface & PHY_INTERFACE_MODE_RGMII) || + (interface & PHY_INTERFACE_MODE_RGMII_ID) || + (interface & PHY_INTERFACE_MODE_RGMII_RXID) || + (interface & PHY_INTERFACE_MODE_RGMII_TXID)) { + pr_debug("STMMAC: PCS RGMII support enable\n"); + priv->pcs = STMMAC_PCS_RGMII; + } else if (interface & PHY_INTERFACE_MODE_SGMII) { + pr_debug("STMMAC: PCS SGMII support enable\n"); + priv->pcs = STMMAC_PCS_SGMII; + } + } +} + +/** + * stmmac_init_phy - PHY initialization + * @dev: net device structure + * Description: it initializes the driver's PHY state, and attaches the PHY + * to the mac driver. + * Return value: + * 0 on success + */ +static int stmmac_init_phy(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + struct phy_device *phydev; + char phy_id_fmt[MII_BUS_ID_SIZE + 3]; + char bus_id[MII_BUS_ID_SIZE]; + int interface = priv->plat->interface; + priv->oldlink = 0; + priv->speed = 0; + priv->oldduplex = -1; + + if (priv->plat->phy_bus_name) + snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", + priv->plat->phy_bus_name, priv->plat->bus_id); + else + snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", + priv->plat->bus_id); + + snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, + priv->plat->phy_addr); + pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt); + + phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + /* Stop Advertising 1000BASE Capability if interface is not GMII */ + if ((interface == PHY_INTERFACE_MODE_MII) || + (interface == PHY_INTERFACE_MODE_RMII)) + phydev->advertising &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + /* + * Broken HW is sometimes missing the pull-up resistor on the + * MDIO line, which results in reads to non-existent devices returning + * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent + * device as well. + * Note: phydev->phy_id is the result of reading the UID PHY registers. + */ + if (phydev->phy_id == 0) { + phy_disconnect(phydev); + return -ENODEV; + } + pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)" + " Link = %d\n", dev->name, phydev->phy_id, phydev->link); + + priv->phydev = phydev; + + return 0; +} + +/** + * stmmac_display_ring: display ring + * @head: pointer to the head of the ring passed. + * @size: size of the ring. + * @extend_desc: to verify if extended descriptors are used. + * Description: display the control/status and buffer descriptors. + */ +static void stmmac_display_ring(void *head, int size, int extend_desc) +{ + int i; + struct dma_extended_desc *ep = (struct dma_extended_desc *)head; + struct dma_desc *p = (struct dma_desc *)head; + + for (i = 0; i < size; i++) { + u64 x; + if (extend_desc) { + x = *(u64 *) ep; + pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", + i, (unsigned int)virt_to_phys(ep), + (unsigned int)x, (unsigned int)(x >> 32), + ep->basic.des2, ep->basic.des3); + ep++; + } else { + x = *(u64 *) p; + pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x", + i, (unsigned int)virt_to_phys(p), + (unsigned int)x, (unsigned int)(x >> 32), + p->des2, p->des3); + p++; + } + pr_info("\n"); + } +} + +static void stmmac_display_rings(struct stmmac_priv *priv) +{ + unsigned int txsize = priv->dma_tx_size; + unsigned int rxsize = priv->dma_rx_size; + + if (priv->extend_desc) { + pr_info("Extended RX descriptor ring:\n"); + stmmac_display_ring((void *)priv->dma_erx, rxsize, 1); + pr_info("Extended TX descriptor ring:\n"); + stmmac_display_ring((void *)priv->dma_etx, txsize, 1); + } else { + pr_info("RX descriptor ring:\n"); + stmmac_display_ring((void *)priv->dma_rx, rxsize, 0); + pr_info("TX descriptor ring:\n"); + stmmac_display_ring((void *)priv->dma_tx, txsize, 0); + } +} + +static int stmmac_set_bfsize(int mtu, int bufsize) +{ + int ret = bufsize; + + if (mtu >= BUF_SIZE_4KiB) + ret = BUF_SIZE_8KiB; + else if (mtu >= BUF_SIZE_2KiB) + ret = BUF_SIZE_4KiB; + else if (mtu >= DMA_BUFFER_SIZE) + ret = BUF_SIZE_2KiB; + else + ret = DMA_BUFFER_SIZE; + + return ret; +} + +/** + * stmmac_clear_descriptors: clear descriptors + * @priv: driver private structure + * Description: this function is called to clear the tx and rx descriptors + * in case of both basic and extended descriptors are used. + */ +static void stmmac_clear_descriptors(struct stmmac_priv *priv) +{ + int i; + unsigned int txsize = priv->dma_tx_size; + unsigned int rxsize = priv->dma_rx_size; + + /* Clear the Rx/Tx descriptors */ + for (i = 0; i < rxsize; i++) + if (priv->extend_desc) + priv->hw->desc->init_rx_desc(&priv->dma_erx[i].basic, + priv->use_riwt, priv->mode, + (i == rxsize - 1)); + else + priv->hw->desc->init_rx_desc(&priv->dma_rx[i], + priv->use_riwt, priv->mode, + (i == rxsize - 1)); + for (i = 0; i < txsize; i++) + if (priv->extend_desc) + priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic, + priv->mode, + (i == txsize - 1)); + else + priv->hw->desc->init_tx_desc(&priv->dma_tx[i], + priv->mode, + (i == txsize - 1)); +} + +static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, + int i) +{ + struct sk_buff *skb; + + skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, + GFP_KERNEL); + if (unlikely(skb == NULL)) { + pr_err("%s: Rx init fails; skb is NULL\n", __func__); + return 1; + } + skb_reserve(skb, NET_IP_ALIGN); + priv->rx_skbuff[i] = skb; + priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, + priv->dma_buf_sz, + DMA_FROM_DEVICE); + + p->des2 = priv->rx_skbuff_dma[i]; + + if ((priv->mode == STMMAC_RING_MODE) && + (priv->dma_buf_sz == BUF_SIZE_16KiB)) + priv->hw->ring->init_desc3(p); + + return 0; +} + +/** + * init_dma_desc_rings - init the RX/TX descriptor rings + * @dev: net device structure + * Description: this function initializes the DMA RX/TX descriptors + * and allocates the socket buffers. It suppors the chained and ring + * modes. + */ +static void init_dma_desc_rings(struct net_device *dev) +{ + int i; + struct stmmac_priv *priv = netdev_priv(dev); + unsigned int txsize = priv->dma_tx_size; + unsigned int rxsize = priv->dma_rx_size; + unsigned int bfsize = 0; + + /* Set the max buffer size according to the DESC mode + * and the MTU. Note that RING mode allows 16KiB bsize. + */ + if (priv->mode == STMMAC_RING_MODE) + bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu); + + if (bfsize < BUF_SIZE_16KiB) + bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); + + DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n", + txsize, rxsize, bfsize); + + if (priv->extend_desc) { + priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * + sizeof(struct + dma_extended_desc), + &priv->dma_rx_phy, + GFP_KERNEL); + priv->dma_etx = dma_alloc_coherent(priv->device, txsize * + sizeof(struct + dma_extended_desc), + &priv->dma_tx_phy, + GFP_KERNEL); + if ((!priv->dma_erx) || (!priv->dma_etx)) + return; + } else { + priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * + sizeof(struct dma_desc), + &priv->dma_rx_phy, + GFP_KERNEL); + priv->dma_tx = dma_alloc_coherent(priv->device, txsize * + sizeof(struct dma_desc), + &priv->dma_tx_phy, + GFP_KERNEL); + if ((!priv->dma_rx) || (!priv->dma_tx)) + return; + } + + priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), + GFP_KERNEL); + priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), + GFP_KERNEL); + priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), + GFP_KERNEL); + priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), + GFP_KERNEL); + if (netif_msg_drv(priv)) + pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__, + (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy); + + /* RX INITIALIZATION */ + DBG(probe, INFO, "stmmac: SKB addresses:\nskb\t\tskb data\tdma data\n"); + for (i = 0; i < rxsize; i++) { + struct dma_desc *p; + if (priv->extend_desc) + p = &((priv->dma_erx + i)->basic); + else + p = priv->dma_rx + i; + + if (stmmac_init_rx_buffers(priv, p, i)) + break; + + DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], + priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); + } + priv->cur_rx = 0; + priv->dirty_rx = (unsigned int)(i - rxsize); + priv->dma_buf_sz = bfsize; + buf_sz = bfsize; + + /* Setup the chained descriptor addresses */ + if (priv->mode == STMMAC_CHAIN_MODE) { + if (priv->extend_desc) { + priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy, + rxsize, 1); + priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy, + txsize, 1); + } else { + priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy, + rxsize, 0); + priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy, + txsize, 0); + } + } + + /* TX INITIALIZATION */ + for (i = 0; i < txsize; i++) { + struct dma_desc *p; + if (priv->extend_desc) + p = &((priv->dma_etx + i)->basic); + else + p = priv->dma_tx + i; + p->des2 = 0; + priv->tx_skbuff_dma[i] = 0; + priv->tx_skbuff[i] = NULL; + } + + priv->dirty_tx = 0; + priv->cur_tx = 0; + + stmmac_clear_descriptors(priv); + + if (netif_msg_hw(priv)) + stmmac_display_rings(priv); +} + +static void dma_free_rx_skbufs(struct stmmac_priv *priv) +{ + int i; + + for (i = 0; i < priv->dma_rx_size; i++) { + if (priv->rx_skbuff[i]) { + dma_unmap_single(priv->device, priv->rx_skbuff_dma[i], + priv->dma_buf_sz, DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_skbuff[i]); + } + priv->rx_skbuff[i] = NULL; + } +} + +static void dma_free_tx_skbufs(struct stmmac_priv *priv) +{ + int i; + + for (i = 0; i < priv->dma_tx_size; i++) { + if (priv->tx_skbuff[i] != NULL) { + struct dma_desc *p; + if (priv->extend_desc) + p = &((priv->dma_etx + i)->basic); + else + p = priv->dma_tx + i; + + if (priv->tx_skbuff_dma[i]) + dma_unmap_single(priv->device, + priv->tx_skbuff_dma[i], + priv->hw->desc->get_tx_len(p), + DMA_TO_DEVICE); + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; + priv->tx_skbuff_dma[i] = 0; + } + } +} + +static void free_dma_desc_resources(struct stmmac_priv *priv) +{ + /* Release the DMA TX/RX socket buffers */ + dma_free_rx_skbufs(priv); + dma_free_tx_skbufs(priv); + + /* Free DMA regions of consistent memory previously allocated */ + if (!priv->extend_desc) { + dma_free_coherent(priv->device, + priv->dma_tx_size * sizeof(struct dma_desc), + priv->dma_tx, priv->dma_tx_phy); + dma_free_coherent(priv->device, + priv->dma_rx_size * sizeof(struct dma_desc), + priv->dma_rx, priv->dma_rx_phy); + } else { + dma_free_coherent(priv->device, priv->dma_tx_size * + sizeof(struct dma_extended_desc), + priv->dma_etx, priv->dma_tx_phy); + dma_free_coherent(priv->device, priv->dma_rx_size * + sizeof(struct dma_extended_desc), + priv->dma_erx, priv->dma_rx_phy); + } + kfree(priv->rx_skbuff_dma); + kfree(priv->rx_skbuff); + kfree(priv->tx_skbuff_dma); + kfree(priv->tx_skbuff); +} + +/** + * stmmac_dma_operation_mode - HW DMA operation mode + * @priv: driver private structure + * Description: it sets the DMA operation mode: tx/rx DMA thresholds + * or Store-And-Forward capability. + */ +static void stmmac_dma_operation_mode(struct stmmac_priv *priv) +{ + if (likely(priv->plat->force_sf_dma_mode || + ((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) { + /* + * In case of GMAC, SF mode can be enabled + * to perform the TX COE in HW. This depends on: + * 1) TX COE if actually supported + * 2) There is no bugged Jumbo frame support + * that needs to not insert csum in the TDES. + */ + priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); + tc = SF_DMA_MODE; + } else + priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); +} + +/** + * stmmac_tx_clean: + * @priv: driver private structure + * Description: it reclaims resources after transmission completes. + */ +static void stmmac_tx_clean(struct stmmac_priv *priv) +{ + unsigned int txsize = priv->dma_tx_size; + + spin_lock(&priv->tx_lock); + + priv->xstats.tx_clean++; + + while (priv->dirty_tx != priv->cur_tx) { + int last; + unsigned int entry = priv->dirty_tx % txsize; + struct sk_buff *skb = priv->tx_skbuff[entry]; + struct dma_desc *p; + + if (priv->extend_desc) + p = (struct dma_desc *)(priv->dma_etx + entry); + else + p = priv->dma_tx + entry; + + /* Check if the descriptor is owned by the DMA. */ + if (priv->hw->desc->get_tx_owner(p)) + break; + + /* Verify tx error by looking at the last segment. */ + last = priv->hw->desc->get_tx_ls(p); + if (likely(last)) { + int tx_error = + priv->hw->desc->tx_status(&priv->dev->stats, + &priv->xstats, p, + priv->ioaddr); + if (likely(tx_error == 0)) { + priv->dev->stats.tx_packets++; + priv->xstats.tx_pkt_n++; + } else + priv->dev->stats.tx_errors++; + + stmmac_get_tx_hwtstamp(priv, entry, skb); + } + TX_DBG("%s: curr %d, dirty %d\n", __func__, + priv->cur_tx, priv->dirty_tx); + + if (likely(priv->tx_skbuff_dma[entry])) { + dma_unmap_single(priv->device, + priv->tx_skbuff_dma[entry], + priv->hw->desc->get_tx_len(p), + DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = 0; + } + priv->hw->ring->clean_desc3(priv, p); + + if (likely(skb != NULL)) { + dev_kfree_skb(skb); + priv->tx_skbuff[entry] = NULL; + } + + priv->hw->desc->release_tx_desc(p, priv->mode); + + priv->dirty_tx++; + } + if (unlikely(netif_queue_stopped(priv->dev) && + stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) { + netif_tx_lock(priv->dev); + if (netif_queue_stopped(priv->dev) && + stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) { + TX_DBG("%s: restart transmit\n", __func__); + netif_wake_queue(priv->dev); + } + netif_tx_unlock(priv->dev); + } + + if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) { + stmmac_enable_eee_mode(priv); + mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer)); + } + spin_unlock(&priv->tx_lock); +} + +static inline void stmmac_enable_dma_irq(struct stmmac_priv *priv) +{ + priv->hw->dma->enable_dma_irq(priv->ioaddr); +} + +static inline void stmmac_disable_dma_irq(struct stmmac_priv *priv) +{ + priv->hw->dma->disable_dma_irq(priv->ioaddr); +} + +/** + * stmmac_tx_err: irq tx error mng function + * @priv: driver private structure + * Description: it cleans the descriptors and restarts the transmission + * in case of errors. + */ +static void stmmac_tx_err(struct stmmac_priv *priv) +{ + int i; + int txsize = priv->dma_tx_size; + netif_stop_queue(priv->dev); + + priv->hw->dma->stop_tx(priv->ioaddr); + dma_free_tx_skbufs(priv); + for (i = 0; i < txsize; i++) + if (priv->extend_desc) + priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic, + priv->mode, + (i == txsize - 1)); + else + priv->hw->desc->init_tx_desc(&priv->dma_tx[i], + priv->mode, + (i == txsize - 1)); + priv->dirty_tx = 0; + priv->cur_tx = 0; + priv->hw->dma->start_tx(priv->ioaddr); + + priv->dev->stats.tx_errors++; + netif_wake_queue(priv->dev); +} + +/** + * stmmac_dma_interrupt: DMA ISR + * @priv: driver private structure + * Description: this is the DMA ISR. It is called by the main ISR. + * It calls the dwmac dma routine to understand which type of interrupt + * happened. In case of there is a Normal interrupt and either TX or RX + * interrupt happened so the NAPI is scheduled. + */ +static void stmmac_dma_interrupt(struct stmmac_priv *priv) +{ + int status; + + status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats); + if (likely((status & handle_rx)) || (status & handle_tx)) { + if (likely(napi_schedule_prep(&priv->napi))) { + stmmac_disable_dma_irq(priv); + __napi_schedule(&priv->napi); + } + } + if (unlikely(status & tx_hard_error_bump_tc)) { + /* Try to bump up the dma threshold on this failure */ + if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { + tc += 64; + priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); + priv->xstats.threshold = tc; + } + } else if (unlikely(status == tx_hard_error)) + stmmac_tx_err(priv); +} + +/** + * stmmac_mmc_setup: setup the Mac Management Counters (MMC) + * @priv: driver private structure + * Description: this masks the MMC irq, in fact, the counters are managed in SW. + */ +static void stmmac_mmc_setup(struct stmmac_priv *priv) +{ + unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | + MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; + + dwmac_mmc_intr_all_mask(priv->ioaddr); + + if (priv->dma_cap.rmon) { + dwmac_mmc_ctrl(priv->ioaddr, mode); + memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); + } else + pr_info(" No MAC Management Counters available\n"); +} + +static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) +{ + u32 hwid = priv->hw->synopsys_uid; + + /* Check Synopsys Id (not available on old chips) */ + if (likely(hwid)) { + u32 uid = ((hwid & 0x0000ff00) >> 8); + u32 synid = (hwid & 0x000000ff); + + pr_info("stmmac - user ID: 0x%x, Synopsys ID: 0x%x\n", + uid, synid); + + return synid; + } + return 0; +} + +/** + * stmmac_selec_desc_mode: to select among: normal/alternate/extend descriptors + * @priv: driver private structure + * Description: select the Enhanced/Alternate or Normal descriptors. + * In case of Enhanced/Alternate, it looks at the extended descriptors are + * supported by the HW cap. register. + */ +static void stmmac_selec_desc_mode(struct stmmac_priv *priv) +{ + if (priv->plat->enh_desc) { + pr_info(" Enhanced/Alternate descriptors\n"); + + /* GMAC older than 3.50 has no extended descriptors */ + if (priv->synopsys_id >= DWMAC_CORE_3_50) { + pr_info("\tEnabled extended descriptors\n"); + priv->extend_desc = 1; + } else + pr_warn("Extended descriptors not supported\n"); + + priv->hw->desc = &enh_desc_ops; + } else { + pr_info(" Normal descriptors\n"); + priv->hw->desc = &ndesc_ops; + } +} + +/** + * stmmac_get_hw_features: get MAC capabilities from the HW cap. register. + * @priv: driver private structure + * Description: + * new GMAC chip generations have a new register to indicate the + * presence of the optional feature/functions. + * This can be also used to override the value passed through the + * platform and necessary for old MAC10/100 and GMAC chips. + */ +static int stmmac_get_hw_features(struct stmmac_priv *priv) +{ + u32 hw_cap = 0; + + if (priv->hw->dma->get_hw_feature) { + hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr); + + priv->dma_cap.mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL); + priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1; + priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2; + priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4; + priv->dma_cap.multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5; + priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6; + priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8; + priv->dma_cap.pmt_remote_wake_up = + (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9; + priv->dma_cap.pmt_magic_frame = + (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10; + /* MMC */ + priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11; + /* IEEE 1588-2002 */ + priv->dma_cap.time_stamp = + (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12; + /* IEEE 1588-2008 */ + priv->dma_cap.atime_stamp = + (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13; + /* 802.3az - Energy-Efficient Ethernet (EEE) */ + priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14; + priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15; + /* TX and RX csum */ + priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16; + priv->dma_cap.rx_coe_type1 = + (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17; + priv->dma_cap.rx_coe_type2 = + (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18; + priv->dma_cap.rxfifo_over_2048 = + (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19; + /* TX and RX number of channels */ + priv->dma_cap.number_rx_channel = + (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20; + priv->dma_cap.number_tx_channel = + (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22; + /* Alternate (enhanced) DESC mode */ + priv->dma_cap.enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; + } + + return hw_cap; +} + +/** + * stmmac_check_ether_addr: check if the MAC addr is valid + * @priv: driver private structure + * Description: + * it is to verify if the MAC address is valid, in case of failures it + * generates a random MAC address + */ +static void stmmac_check_ether_addr(struct stmmac_priv *priv) +{ + if (!is_valid_ether_addr(priv->dev->dev_addr)) { + priv->hw->mac->get_umac_addr((void __iomem *) + priv->dev->base_addr, + priv->dev->dev_addr, 0); + if (!is_valid_ether_addr(priv->dev->dev_addr)) + eth_hw_addr_random(priv->dev); + } + pr_warn("%s: device MAC address %pM\n", priv->dev->name, + priv->dev->dev_addr); +} + +/** + * stmmac_init_dma_engine: DMA init. + * @priv: driver private structure + * Description: + * It inits the DMA invoking the specific MAC/GMAC callback. + * Some DMA parameters can be passed from the platform; + * in case of these are not passed a default is kept for the MAC or GMAC. + */ +static int stmmac_init_dma_engine(struct stmmac_priv *priv) +{ + int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0; + int mixed_burst = 0; + int atds = 0; + + if (priv->plat->dma_cfg) { + pbl = priv->plat->dma_cfg->pbl; + fixed_burst = priv->plat->dma_cfg->fixed_burst; + mixed_burst = priv->plat->dma_cfg->mixed_burst; + burst_len = priv->plat->dma_cfg->burst_len; + } + + if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE)) + atds = 1; + + return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst, + burst_len, priv->dma_tx_phy, + priv->dma_rx_phy, atds); +} + +/** + * stmmac_tx_timer: mitigation sw timer for tx. + * @data: data pointer + * Description: + * This is the timer handler to directly invoke the stmmac_tx_clean. + */ +static void stmmac_tx_timer(unsigned long data) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)data; + + stmmac_tx_clean(priv); +} + +/** + * stmmac_init_tx_coalesce: init tx mitigation options. + * @priv: driver private structure + * Description: + * This inits the transmit coalesce parameters: i.e. timer rate, + * timer handler and default threshold used for enabling the + * interrupt on completion bit. + */ +static void stmmac_init_tx_coalesce(struct stmmac_priv *priv) +{ + priv->tx_coal_frames = STMMAC_TX_FRAMES; + priv->tx_coal_timer = STMMAC_COAL_TX_TIMER; + init_timer(&priv->txtimer); + priv->txtimer.expires = STMMAC_COAL_TIMER(priv->tx_coal_timer); + priv->txtimer.data = (unsigned long)priv; + priv->txtimer.function = stmmac_tx_timer; + add_timer(&priv->txtimer); +} + +/** + * stmmac_open - open entry point of the driver + * @dev : pointer to the device structure. + * Description: + * This function is the open entry point of the driver. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int stmmac_open(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int ret; + + clk_prepare_enable(priv->stmmac_clk); + + stmmac_check_ether_addr(priv); + + if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && + priv->pcs != STMMAC_PCS_RTBI) { + ret = stmmac_init_phy(dev); + if (ret) { + pr_err("%s: Cannot attach to PHY (error: %d)\n", + __func__, ret); + goto open_error; + } + } + + /* Create and initialize the TX/RX descriptors chains. */ + priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); + priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); + priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); + init_dma_desc_rings(dev); + + /* DMA initialization and SW reset */ + ret = stmmac_init_dma_engine(priv); + if (ret < 0) { + pr_err("%s: DMA initialization failed\n", __func__); + goto open_error; + } + + /* Copy the MAC addr into the HW */ + priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0); + + /* If required, perform hw setup of the bus. */ + if (priv->plat->bus_setup) + priv->plat->bus_setup(priv->ioaddr); + + /* Initialize the MAC Core */ + priv->hw->mac->core_init(priv->ioaddr); + + /* Request the IRQ lines */ + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + goto open_error; + } + + /* Request the Wake IRQ in case of another line is used for WoL */ + if (priv->wol_irq != dev->irq) { + ret = request_irq(priv->wol_irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n", + __func__, priv->wol_irq, ret); + goto open_error_wolirq; + } + } + + /* Request the IRQ lines */ + if (priv->lpi_irq != -ENXIO) { + ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED, + dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n", + __func__, priv->lpi_irq, ret); + goto open_error_lpiirq; + } + } + + /* Enable the MAC Rx/Tx */ + stmmac_set_mac(priv->ioaddr, true); + + /* Set the HW DMA mode and the COE */ + stmmac_dma_operation_mode(priv); + + /* Extra statistics */ + memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); + priv->xstats.threshold = tc; + + stmmac_mmc_setup(priv); + + ret = stmmac_init_ptp(priv); + if (ret) + pr_warn("%s: failed PTP initialisation\n", __func__); + +#ifdef CONFIG_GMAC_DEBUG_FS + ret = stmmac_init_fs(dev); + if (ret < 0) + pr_warn("%s: failed debugFS registration\n", __func__); +#endif + /* Start the ball rolling... */ + DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); + priv->hw->dma->start_tx(priv->ioaddr); + priv->hw->dma->start_rx(priv->ioaddr); + + /* Dump DMA/MAC registers */ + if (netif_msg_hw(priv)) { + priv->hw->mac->dump_regs(priv->ioaddr); + priv->hw->dma->dump_regs(priv->ioaddr); + } + + if (priv->phydev) + phy_start(priv->phydev); + + priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; + + priv->eee_enabled = stmmac_eee_init(priv); + + stmmac_init_tx_coalesce(priv); + + if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) { + priv->rx_riwt = MAX_DMA_RIWT; + priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT); + } + + if (priv->pcs && priv->hw->mac->ctrl_ane) + priv->hw->mac->ctrl_ane(priv->ioaddr, 0); + + napi_enable(&priv->napi); + netif_start_queue(dev); + + return 0; + +open_error_lpiirq: + if (priv->wol_irq != dev->irq) + free_irq(priv->wol_irq, dev); + +open_error_wolirq: + free_irq(dev->irq, dev); + +open_error: + if (priv->phydev) + phy_disconnect(priv->phydev); + + clk_disable_unprepare(priv->stmmac_clk); + + return ret; +} + +/** + * stmmac_release - close entry point of the driver + * @dev : device pointer. + * Description: + * This is the stop entry point of the driver. + */ +static int stmmac_release(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (priv->eee_enabled) + del_timer_sync(&priv->eee_ctrl_timer); + + /* Stop and disconnect the PHY */ + if (priv->phydev) { + phy_stop(priv->phydev); + phy_disconnect(priv->phydev); + priv->phydev = NULL; + } + + netif_stop_queue(dev); + + napi_disable(&priv->napi); + + del_timer_sync(&priv->txtimer); + + /* Free the IRQ lines */ + free_irq(dev->irq, dev); + if (priv->wol_irq != dev->irq) + free_irq(priv->wol_irq, dev); + if (priv->lpi_irq != -ENXIO) + free_irq(priv->lpi_irq, dev); + + /* Stop TX/RX DMA and clear the descriptors */ + priv->hw->dma->stop_tx(priv->ioaddr); + priv->hw->dma->stop_rx(priv->ioaddr); + + /* Release and free the Rx/Tx resources */ + free_dma_desc_resources(priv); + + /* Disable the MAC Rx/Tx */ + stmmac_set_mac(priv->ioaddr, false); + + netif_carrier_off(dev); + +#ifdef CONFIG_GMAC_DEBUG_FS + stmmac_exit_fs(); +#endif + clk_disable_unprepare(priv->stmmac_clk); + + stmmac_release_ptp(priv); + + return 0; +} + +/** + * stmmac_xmit: Tx entry point of the driver + * @skb : the socket buffer + * @dev : device pointer + * Description : this is the tx entry point of the driver. + * It programs the chain or the ring and supports oversized frames + * and SG feature. + */ +static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + unsigned int txsize = priv->dma_tx_size; + unsigned int entry; + int i, csum_insertion = 0, is_jumbo = 0; + int nfrags = skb_shinfo(skb)->nr_frags; + struct dma_desc *desc, *first; + unsigned int nopaged_len = skb_headlen(skb); + + if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + /* This is a hard error, log it. */ + pr_err("%s: Tx Ring full when queue awake\n", __func__); + } + return NETDEV_TX_BUSY; + } + + spin_lock(&priv->tx_lock); + + if (priv->tx_path_in_lpi_mode) + stmmac_disable_eee_mode(priv); + + entry = priv->cur_tx % txsize; + +#ifdef STMMAC_XMIT_DEBUG + if ((skb->len > ETH_FRAME_LEN) || nfrags) + pr_debug("%s: [entry %d]: skb addr %p len: %d nopagedlen: %d\n" + "\tn_frags: %d - ip_summed: %d - %s gso\n" + "\ttx_count_frames %d\n", __func__, entry, + skb, skb->len, nopaged_len, nfrags, skb->ip_summed, + !skb_is_gso(skb) ? "isn't" : "is", + priv->tx_count_frames); +#endif + + csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); + + if (priv->extend_desc) + desc = (struct dma_desc *)(priv->dma_etx + entry); + else + desc = priv->dma_tx + entry; + + first = desc; + +#ifdef STMMAC_XMIT_DEBUG + if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) + pr_debug("\tskb len: %d, nopaged_len: %d,\n" + "\t\tn_frags: %d, ip_summed: %d\n", + skb->len, nopaged_len, nfrags, skb->ip_summed); +#endif + priv->tx_skbuff[entry] = skb; + + /* To program the descriptors according to the size of the frame */ + if (priv->mode == STMMAC_RING_MODE) { + is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len, + priv->plat->enh_desc); + if (unlikely(is_jumbo)) + entry = priv->hw->ring->jumbo_frm(priv, skb, + csum_insertion); + } else { + is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len, + priv->plat->enh_desc); + if (unlikely(is_jumbo)) + entry = priv->hw->chain->jumbo_frm(priv, skb, + csum_insertion); + } + if (likely(!is_jumbo)) { + desc->des2 = dma_map_single(priv->device, skb->data, + nopaged_len, DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, + csum_insertion, priv->mode); + } else + desc = first; + + for (i = 0; i < nfrags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + int len = skb_frag_size(frag); + + entry = (++priv->cur_tx) % txsize; + if (priv->extend_desc) + desc = (struct dma_desc *)(priv->dma_etx + entry); + else + desc = priv->dma_tx + entry; + + TX_DBG("\t[entry %d] segment len: %d\n", entry, len); + desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len, + DMA_TO_DEVICE); + priv->tx_skbuff_dma[entry] = desc->des2; + priv->tx_skbuff[entry] = NULL; + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion, + priv->mode); + wmb(); + priv->hw->desc->set_tx_owner(desc); + wmb(); + } + + /* Finalize the latest segment. */ + priv->hw->desc->close_tx_desc(desc); + + wmb(); + /* According to the coalesce parameter the IC bit for the latest + * segment could be reset and the timer re-started to invoke the + * stmmac_tx function. This approach takes care about the fragments. + */ + priv->tx_count_frames += nfrags + 1; + if (priv->tx_coal_frames > priv->tx_count_frames) { + priv->hw->desc->clear_tx_ic(desc); + priv->xstats.tx_reset_ic_bit++; + TX_DBG("\t[entry %d]: tx_count_frames %d\n", entry, + priv->tx_count_frames); + mod_timer(&priv->txtimer, + STMMAC_COAL_TIMER(priv->tx_coal_timer)); + } else + priv->tx_count_frames = 0; + + /* To avoid raise condition */ + priv->hw->desc->set_tx_owner(first); + wmb(); + + priv->cur_tx++; + +#ifdef STMMAC_XMIT_DEBUG + if (netif_msg_pktdata(priv)) { + pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d", + __func__, (priv->cur_tx % txsize), + (priv->dirty_tx % txsize), entry, first, nfrags); + if (priv->extend_desc) + stmmac_display_ring((void *)priv->dma_etx, txsize, 1); + else + stmmac_display_ring((void *)priv->dma_tx, txsize, 0); + + pr_info(">>> frame to be transmitted: "); + print_pkt(skb->data, skb->len); + } +#endif + if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) { + TX_DBG("%s: stop transmitted packets\n", __func__); + netif_stop_queue(dev); + } + + dev->stats.tx_bytes += skb->len; + + if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en)) { + /* declare that device is doing timestamping */ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + priv->hw->desc->enable_tx_timestamp(first); + } + + if (!priv->hwts_tx_en) + skb_tx_timestamp(skb); + + priv->hw->dma->enable_dma_transmission(priv->ioaddr); + + spin_unlock(&priv->tx_lock); + + return NETDEV_TX_OK; +} + +/** + * stmmac_rx_refill: refill used skb preallocated buffers + * @priv: driver private structure + * Description : this is to reallocate the skb for the reception process + * that is based on zero-copy. + */ +static inline void stmmac_rx_refill(struct stmmac_priv *priv) +{ + unsigned int rxsize = priv->dma_rx_size; + int bfsize = priv->dma_buf_sz; + + for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) { + unsigned int entry = priv->dirty_rx % rxsize; + struct dma_desc *p; + + if (priv->extend_desc) + p = (struct dma_desc *)(priv->dma_erx + entry); + else + p = priv->dma_rx + entry; + + if (likely(priv->rx_skbuff[entry] == NULL)) { + struct sk_buff *skb; + + skb = netdev_alloc_skb_ip_align(priv->dev, bfsize); + + if (unlikely(skb == NULL)) + break; + + priv->rx_skbuff[entry] = skb; + priv->rx_skbuff_dma[entry] = + dma_map_single(priv->device, skb->data, bfsize, + DMA_FROM_DEVICE); + + p->des2 = priv->rx_skbuff_dma[entry]; + + priv->hw->ring->refill_desc3(priv, p); + + RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); + } + wmb(); + priv->hw->desc->set_rx_owner(p); + wmb(); + } +} + +/** + * stmmac_rx_refill: refill used skb preallocated buffers + * @priv: driver private structure + * @limit: napi bugget. + * Description : this the function called by the napi poll method. + * It gets all the frames inside the ring. + */ +static int stmmac_rx(struct stmmac_priv *priv, int limit) +{ + unsigned int rxsize = priv->dma_rx_size; + unsigned int entry = priv->cur_rx % rxsize; + unsigned int next_entry; + unsigned int count = 0; + int coe = priv->plat->rx_coe; + +#ifdef STMMAC_RX_DEBUG + if (netif_msg_hw(priv)) { + pr_debug(">>> stmmac_rx: descriptor ring:\n"); + if (priv->extend_desc) + stmmac_display_ring((void *)priv->dma_erx, rxsize, 1); + else + stmmac_display_ring((void *)priv->dma_rx, rxsize, 0); + } +#endif + while (count < limit) { + int status; + struct dma_desc *p; + + if (priv->extend_desc) + p = (struct dma_desc *)(priv->dma_erx + entry); + else + p = priv->dma_rx + entry; + + if (priv->hw->desc->get_rx_owner(p)) + break; + + count++; + + next_entry = (++priv->cur_rx) % rxsize; + if (priv->extend_desc) + prefetch(priv->dma_erx + next_entry); + else + prefetch(priv->dma_rx + next_entry); + + /* read the status of the incoming frame */ + status = priv->hw->desc->rx_status(&priv->dev->stats, + &priv->xstats, p); + if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status)) + priv->hw->desc->rx_extended_status(&priv->dev->stats, + &priv->xstats, + priv->dma_erx + + entry); + if (unlikely(status == discard_frame)) { + priv->dev->stats.rx_errors++; + if (priv->hwts_rx_en && !priv->extend_desc) { + /* DESC2 & DESC3 will be overwitten by device + * with timestamp value, hence reinitialize + * them in stmmac_rx_refill() function so that + * device can reuse it. + */ + priv->rx_skbuff[entry] = NULL; + dma_unmap_single(priv->device, + priv->rx_skbuff_dma[entry], + priv->dma_buf_sz, + DMA_FROM_DEVICE); + } + } else { + struct sk_buff *skb; + int frame_len; + + frame_len = priv->hw->desc->get_rx_frame_len(p, coe); + + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 + * Type frames (LLC/LLC-SNAP) + */ + if (unlikely(status != llc_snap)) + frame_len -= ETH_FCS_LEN; +#ifdef STMMAC_RX_DEBUG + if (frame_len > ETH_FRAME_LEN) + pr_debug("\tRX frame size %d, COE status: %d\n", + frame_len, status); + + if (netif_msg_hw(priv)) + pr_debug("\tdesc: %p [entry %d] buff=0x%x\n", + p, entry, p->des2); +#endif + skb = priv->rx_skbuff[entry]; + if (unlikely(!skb)) { + pr_err("%s: Inconsistent Rx descriptor chain\n", + priv->dev->name); + priv->dev->stats.rx_dropped++; + break; + } + prefetch(skb->data - NET_IP_ALIGN); + priv->rx_skbuff[entry] = NULL; + + stmmac_get_rx_hwtstamp(priv, entry, skb); + + skb_put(skb, frame_len); + dma_unmap_single(priv->device, + priv->rx_skbuff_dma[entry], + priv->dma_buf_sz, DMA_FROM_DEVICE); +#ifdef STMMAC_RX_DEBUG + if (netif_msg_pktdata(priv)) { + pr_info(" frame received (%dbytes)", frame_len); + print_pkt(skb->data, frame_len); + } +#endif + skb->protocol = eth_type_trans(skb, priv->dev); + + if (unlikely(!coe)) + skb_checksum_none_assert(skb); + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + + napi_gro_receive(&priv->napi, skb); + + priv->dev->stats.rx_packets++; + priv->dev->stats.rx_bytes += frame_len; + } + entry = next_entry; + } + + stmmac_rx_refill(priv); + + priv->xstats.rx_pkt_n += count; + + return count; +} + +/** + * stmmac_poll - stmmac poll method (NAPI) + * @napi : pointer to the napi structure. + * @budget : maximum number of packets that the current CPU can receive from + * all interfaces. + * Description : + * To look at the incoming frames and clear the tx resources. + */ +static int stmmac_poll(struct napi_struct *napi, int budget) +{ + struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi); + int work_done = 0; + + priv->xstats.napi_poll++; + stmmac_tx_clean(priv); + + work_done = stmmac_rx(priv, budget); + if (work_done < budget) { + napi_complete(napi); + stmmac_enable_dma_irq(priv); + } + return work_done; +} + +/** + * stmmac_tx_timeout + * @dev : Pointer to net device structure + * Description: this function is called when a packet transmission fails to + * complete within a reasonable time. The driver will mark the error in the + * netdev structure and arrange for the device to be reset to a sane state + * in order to transmit a new packet. + */ +static void stmmac_tx_timeout(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + /* Clear Tx resources and restart transmitting again */ + stmmac_tx_err(priv); +} + +/* Configuration changes (passed on by ifconfig) */ +static int stmmac_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) /* can't act on a running interface */ + return -EBUSY; + + /* Don't allow changing the I/O address */ + if (map->base_addr != dev->base_addr) { + pr_warn("%s: can't change I/O address\n", dev->name); + return -EOPNOTSUPP; + } + + /* Don't allow changing the IRQ */ + if (map->irq != dev->irq) { + pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq); + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * stmmac_set_rx_mode - entry point for multicast addressing + * @dev : pointer to the device structure + * Description: + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. + * Return value: + * void. + */ +static void stmmac_set_rx_mode(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + spin_lock(&priv->lock); + priv->hw->mac->set_filter(dev, priv->synopsys_id); + spin_unlock(&priv->lock); +} + +/** + * stmmac_change_mtu - entry point to change MTU size for the device. + * @dev : device pointer. + * @new_mtu : the new MTU size for the device. + * Description: the Maximum Transfer Unit (MTU) is used by the network layer + * to drive packet transmission. Ethernet has an MTU of 1500 octets + * (ETH_DATA_LEN). This value can be changed with ifconfig. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +static int stmmac_change_mtu(struct net_device *dev, int new_mtu) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int max_mtu; + + if (netif_running(dev)) { + pr_err("%s: must be stopped to change its MTU\n", dev->name); + return -EBUSY; + } + + if (priv->plat->enh_desc) + max_mtu = JUMBO_LEN; + else + max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); + + if ((new_mtu < 46) || (new_mtu > max_mtu)) { + pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu); + return -EINVAL; + } + + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static netdev_features_t stmmac_fix_features(struct net_device *dev, + netdev_features_t features) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (priv->plat->rx_coe == STMMAC_RX_COE_NONE) + features &= ~NETIF_F_RXCSUM; + else if (priv->plat->rx_coe == STMMAC_RX_COE_TYPE1) + features &= ~NETIF_F_IPV6_CSUM; + if (!priv->plat->tx_coe) + features &= ~NETIF_F_ALL_CSUM; + + /* Some GMAC devices have a bugged Jumbo frame support that + * needs to have the Tx COE disabled for oversized frames + * (due to limited buffer sizes). In this case we disable + * the TX csum insertionin the TDES and not use SF. + */ + if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) + features &= ~NETIF_F_ALL_CSUM; + + return features; +} + +/** + * stmmac_interrupt - main ISR + * @irq: interrupt number. + * @dev_id: to pass the net device pointer. + * Description: this is the main driver interrupt service routine. + * It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI + * interrupts. + */ +static irqreturn_t stmmac_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct stmmac_priv *priv = netdev_priv(dev); + + if (unlikely(!dev)) { + pr_err("%s: invalid dev pointer\n", __func__); + return IRQ_NONE; + } + + /* To handle GMAC own interrupts */ + if (priv->plat->has_gmac) { + int status = priv->hw->mac->host_irq_status((void __iomem *) + dev->base_addr, + &priv->xstats); + if (unlikely(status)) { + /* For LPI we need to save the tx status */ + if (status & CORE_IRQ_TX_PATH_IN_LPI_MODE) + priv->tx_path_in_lpi_mode = true; + if (status & CORE_IRQ_TX_PATH_EXIT_LPI_MODE) + priv->tx_path_in_lpi_mode = false; + } + } + + /* To handle DMA interrupts */ + stmmac_dma_interrupt(priv); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* Polling receive - used by NETCONSOLE and other diagnostic tools + * to allow network I/O with interrupts disabled. + */ +static void stmmac_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + stmmac_interrupt(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + +/** + * stmmac_ioctl - Entry point for the Ioctl + * @dev: Device pointer. + * @rq: An IOCTL specefic structure, that can contain a pointer to + * a proprietary structure used to pass information to the driver. + * @cmd: IOCTL command + * Description: + * Currently it supports the phy_mii_ioctl(...) and HW time stamping. + */ +static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + if (!netif_running(dev)) + return -EINVAL; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + if (!priv->phydev) + return -EINVAL; + ret = phy_mii_ioctl(priv->phydev, rq, cmd); + break; + case SIOCSHWTSTAMP: + ret = stmmac_hwtstamp_ioctl(dev, rq); + break; + default: + break; + } + + return ret; +} + +#ifdef CONFIG_GMAC_DEBUG_FS +static struct dentry *stmmac_fs_dir; +static struct dentry *stmmac_rings_status; +static struct dentry *stmmac_dma_cap; + +static void sysfs_display_ring(void *head, int size, int extend_desc, + struct seq_file *seq) +{ + int i; + struct dma_extended_desc *ep = (struct dma_extended_desc *)head; + struct dma_desc *p = (struct dma_desc *)head; + + for (i = 0; i < size; i++) { + u64 x; + if (extend_desc) { + x = *(u64 *) ep; + seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", + i, (unsigned int)virt_to_phys(ep), + (unsigned int)x, (unsigned int)(x >> 32), + ep->basic.des2, ep->basic.des3); + ep++; + } else { + x = *(u64 *) p; + seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n", + i, (unsigned int)virt_to_phys(ep), + (unsigned int)x, (unsigned int)(x >> 32), + p->des2, p->des3); + p++; + } + seq_printf(seq, "\n"); + } +} + +static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v) +{ + struct net_device *dev = seq->private; + struct stmmac_priv *priv = netdev_priv(dev); + unsigned int txsize = priv->dma_tx_size; + unsigned int rxsize = priv->dma_rx_size; + + if (priv->extend_desc) { + seq_printf(seq, "Extended RX descriptor ring:\n"); + sysfs_display_ring((void *)priv->dma_erx, rxsize, 1, seq); + seq_printf(seq, "Extended TX descriptor ring:\n"); + sysfs_display_ring((void *)priv->dma_etx, txsize, 1, seq); + } else { + seq_printf(seq, "RX descriptor ring:\n"); + sysfs_display_ring((void *)priv->dma_rx, rxsize, 0, seq); + seq_printf(seq, "TX descriptor ring:\n"); + sysfs_display_ring((void *)priv->dma_tx, txsize, 0, seq); + } + + return 0; +} + +static int stmmac_sysfs_ring_open(struct inode *inode, struct file *file) +{ + return single_open(file, stmmac_sysfs_ring_read, inode->i_private); +} + +static const struct file_operations stmmac_rings_status_fops = { + .owner = THIS_MODULE, + .open = stmmac_sysfs_ring_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v) +{ + struct net_device *dev = seq->private; + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->hw_cap_support) { + seq_printf(seq, "DMA HW features not supported\n"); + return 0; + } + + seq_printf(seq, "==============================\n"); + seq_printf(seq, "\tDMA HW features\n"); + seq_printf(seq, "==============================\n"); + + seq_printf(seq, "\t10/100 Mbps %s\n", + (priv->dma_cap.mbps_10_100) ? "Y" : "N"); + seq_printf(seq, "\t1000 Mbps %s\n", + (priv->dma_cap.mbps_1000) ? "Y" : "N"); + seq_printf(seq, "\tHalf duple %s\n", + (priv->dma_cap.half_duplex) ? "Y" : "N"); + seq_printf(seq, "\tHash Filter: %s\n", + (priv->dma_cap.hash_filter) ? "Y" : "N"); + seq_printf(seq, "\tMultiple MAC address registers: %s\n", + (priv->dma_cap.multi_addr) ? "Y" : "N"); + seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n", + (priv->dma_cap.pcs) ? "Y" : "N"); + seq_printf(seq, "\tSMA (MDIO) Interface: %s\n", + (priv->dma_cap.sma_mdio) ? "Y" : "N"); + seq_printf(seq, "\tPMT Remote wake up: %s\n", + (priv->dma_cap.pmt_remote_wake_up) ? "Y" : "N"); + seq_printf(seq, "\tPMT Magic Frame: %s\n", + (priv->dma_cap.pmt_magic_frame) ? "Y" : "N"); + seq_printf(seq, "\tRMON module: %s\n", + (priv->dma_cap.rmon) ? "Y" : "N"); + seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n", + (priv->dma_cap.time_stamp) ? "Y" : "N"); + seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n", + (priv->dma_cap.atime_stamp) ? "Y" : "N"); + seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n", + (priv->dma_cap.eee) ? "Y" : "N"); + seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N"); + seq_printf(seq, "\tChecksum Offload in TX: %s\n", + (priv->dma_cap.tx_coe) ? "Y" : "N"); + seq_printf(seq, "\tIP Checksum Offload (type1) in RX: %s\n", + (priv->dma_cap.rx_coe_type1) ? "Y" : "N"); + seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n", + (priv->dma_cap.rx_coe_type2) ? "Y" : "N"); + seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n", + (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N"); + seq_printf(seq, "\tNumber of Additional RX channel: %d\n", + priv->dma_cap.number_rx_channel); + seq_printf(seq, "\tNumber of Additional TX channel: %d\n", + priv->dma_cap.number_tx_channel); + seq_printf(seq, "\tEnhanced descriptors: %s\n", + (priv->dma_cap.enh_desc) ? "Y" : "N"); + + return 0; +} + +static int stmmac_sysfs_dma_cap_open(struct inode *inode, struct file *file) +{ + return single_open(file, stmmac_sysfs_dma_cap_read, inode->i_private); +} + +static const struct file_operations stmmac_dma_cap_fops = { + .owner = THIS_MODULE, + .open = stmmac_sysfs_dma_cap_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int stmmac_init_fs(struct net_device *dev) +{ + /* Create debugfs entries */ + stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL); + + if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) { + pr_err("ERROR %s, debugfs create directory failed\n", + STMMAC_RESOURCE_NAME); + + return -ENOMEM; + } + + /* Entry to report DMA RX/TX rings */ + stmmac_rings_status = debugfs_create_file("descriptors_status", + S_IRUGO, stmmac_fs_dir, dev, + &stmmac_rings_status_fops); + + if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) { + pr_info("ERROR creating stmmac ring debugfs file\n"); + debugfs_remove(stmmac_fs_dir); + + return -ENOMEM; + } + + /* Entry to report the DMA HW features */ + stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir, + dev, &stmmac_dma_cap_fops); + + if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) { + pr_info("ERROR creating stmmac MMC debugfs file\n"); + debugfs_remove(stmmac_rings_status); + debugfs_remove(stmmac_fs_dir); + + return -ENOMEM; + } + + return 0; +} + +static void stmmac_exit_fs(void) +{ + debugfs_remove(stmmac_rings_status); + debugfs_remove(stmmac_dma_cap); + debugfs_remove(stmmac_fs_dir); +} +#endif /* CONFIG_GMAC_DEBUG_FS */ + +static const struct net_device_ops stmmac_netdev_ops = { + .ndo_open = stmmac_open, + .ndo_start_xmit = stmmac_xmit, + .ndo_stop = stmmac_release, + .ndo_change_mtu = stmmac_change_mtu, + .ndo_fix_features = stmmac_fix_features, + .ndo_set_rx_mode = stmmac_set_rx_mode, + .ndo_tx_timeout = stmmac_tx_timeout, + .ndo_do_ioctl = stmmac_ioctl, + .ndo_set_config = stmmac_config, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = stmmac_poll_controller, +#endif + .ndo_set_mac_address = eth_mac_addr, +}; + +/** + * stmmac_hw_init - Init the MAC device + * @priv: driver private structure + * Description: this function detects which MAC device + * (GMAC/MAC10-100) has to attached, checks the HW capability + * (if supported) and sets the driver's features (for example + * to use the ring or chaine mode or support the normal/enh + * descriptor structure). + */ +static int stmmac_hw_init(struct stmmac_priv *priv) +{ + int ret; + struct mac_device_info *mac; + + /* Identify the MAC HW device */ + if (priv->plat->has_gmac) { + priv->dev->priv_flags |= IFF_UNICAST_FLT; + mac = dwmac1000_setup(priv->ioaddr); + } else { + mac = dwmac100_setup(priv->ioaddr); + } + if (!mac) + return -ENOMEM; + + priv->hw = mac; + + /* Get and dump the chip ID */ + priv->synopsys_id = stmmac_get_synopsys_id(priv); + + /* To use alternate (extended) or normal descriptor structures */ + stmmac_selec_desc_mode(priv); + + /* To use the chained or ring mode */ + if (chain_mode) { + priv->hw->chain = &chain_mode_ops; + pr_info(" Chain mode enabled\n"); + priv->mode = STMMAC_CHAIN_MODE; + } else { + priv->hw->ring = &ring_mode_ops; + pr_info(" Ring mode enabled\n"); + priv->mode = STMMAC_RING_MODE; + } + + /* Get the HW capability (new GMAC newer than 3.50a) */ + priv->hw_cap_support = stmmac_get_hw_features(priv); + if (priv->hw_cap_support) { + pr_info(" DMA HW capability register supported"); + + /* We can override some gmac/dma configuration fields: e.g. + * enh_desc, tx_coe (e.g. that are passed through the + * platform) with the values from the HW capability + * register (if supported). + */ + priv->plat->enh_desc = priv->dma_cap.enh_desc; + priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; + + priv->plat->tx_coe = priv->dma_cap.tx_coe; + + if (priv->dma_cap.rx_coe_type2) + priv->plat->rx_coe = STMMAC_RX_COE_TYPE2; + else if (priv->dma_cap.rx_coe_type1) + priv->plat->rx_coe = STMMAC_RX_COE_TYPE1; + + } else + pr_info(" No HW DMA feature register supported"); + + ret = priv->hw->mac->rx_ipc(priv->ioaddr); + if (!ret) { + pr_warn(" RX IPC Checksum Offload not configured.\n"); + priv->plat->rx_coe = STMMAC_RX_COE_NONE; + } + + if (priv->plat->rx_coe) + pr_info(" RX Checksum Offload Engine supported (type %d)\n", + priv->plat->rx_coe); + if (priv->plat->tx_coe) + pr_info(" TX Checksum insertion supported\n"); + + if (priv->plat->pmt) { + pr_info(" Wake-Up On Lan supported\n"); + device_set_wakeup_capable(priv->device, 1); + } + + return 0; +} + +/** + * stmmac_dvr_probe + * @device: device pointer + * @plat_dat: platform data pointer + * @addr: iobase memory address + * Description: this is the main probe function used to + * call the alloc_etherdev, allocate the priv structure. + */ +struct stmmac_priv *stmmac_dvr_probe(struct device *device, + struct plat_stmmacenet_data *plat_dat, + void __iomem *addr) +{ + int ret = 0; + struct net_device *ndev = NULL; + struct stmmac_priv *priv; + + ndev = alloc_etherdev(sizeof(struct stmmac_priv)); + if (!ndev) + return NULL; + + SET_NETDEV_DEV(ndev, device); + + priv = netdev_priv(ndev); + priv->device = device; + priv->dev = ndev; + + ether_setup(ndev); + + stmmac_set_ethtool_ops(ndev); + priv->pause = pause; + priv->plat = plat_dat; + priv->ioaddr = addr; + priv->dev->base_addr = (unsigned long)addr; + + /* Verify driver arguments */ + stmmac_verify_args(); + + /* Override with kernel parameters if supplied XXX CRS XXX + * this needs to have multiple instances + */ + if ((phyaddr >= 0) && (phyaddr <= 31)) + priv->plat->phy_addr = phyaddr; + + /* Init MAC and get the capabilities */ + ret = stmmac_hw_init(priv); + if (ret) + goto error_free_netdev; + + ndev->netdev_ops = &stmmac_netdev_ops; + + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA; + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); +#ifdef STMMAC_VLAN_TAG_USED + /* Both mac100 and gmac support receive VLAN tag detection */ + ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; +#endif + priv->msg_enable = netif_msg_init(debug, default_msg_level); + + if (flow_ctrl) + priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ + + /* Rx Watchdog is available in the COREs newer than the 3.40. + * In some case, for example on bugged HW this feature + * has to be disable and this can be done by passing the + * riwt_off field from the platform. + */ + if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) { + priv->use_riwt = 1; + pr_info(" Enable RX Mitigation via HW Watchdog Timer\n"); + } + + netif_napi_add(ndev, &priv->napi, stmmac_poll, 64); + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->tx_lock); + + ret = register_netdev(ndev); + if (ret) { + pr_err("%s: ERROR %i registering the device\n", __func__, ret); + goto error_netdev_register; + } + + priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME); + if (IS_ERR(priv->stmmac_clk)) { + pr_warn("%s: warning: cannot get CSR clock\n", __func__); + goto error_clk_get; + } + + /* If a specific clk_csr value is passed from the platform + * this means that the CSR Clock Range selection cannot be + * changed at run-time and it is fixed. Viceversa the driver'll try to + * set the MDC clock dynamically according to the csr actual + * clock input. + */ + if (!priv->plat->clk_csr) + stmmac_clk_csr_set(priv); + else + priv->clk_csr = priv->plat->clk_csr; + + stmmac_check_pcs_mode(priv); + + if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && + priv->pcs != STMMAC_PCS_RTBI) { + /* MDIO bus Registration */ + ret = stmmac_mdio_register(ndev); + if (ret < 0) { + pr_debug("%s: MDIO bus (id: %d) registration failed", + __func__, priv->plat->bus_id); + goto error_mdio_register; + } + } + + return priv; + +error_mdio_register: + clk_put(priv->stmmac_clk); +error_clk_get: + unregister_netdev(ndev); +error_netdev_register: + netif_napi_del(&priv->napi); +error_free_netdev: + free_netdev(ndev); + + return NULL; +} + +/** + * stmmac_dvr_remove + * @ndev: net device pointer + * Description: this function resets the TX/RX processes, disables the MAC RX/TX + * changes the link status, releases the DMA descriptor rings. + */ +int stmmac_dvr_remove(struct net_device *ndev) +{ + struct stmmac_priv *priv = netdev_priv(ndev); + + pr_info("%s:\n\tremoving driver", __func__); + + priv->hw->dma->stop_rx(priv->ioaddr); + priv->hw->dma->stop_tx(priv->ioaddr); + + stmmac_set_mac(priv->ioaddr, false); + if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI && + priv->pcs != STMMAC_PCS_RTBI) + stmmac_mdio_unregister(ndev); + netif_carrier_off(ndev); + unregister_netdev(ndev); + free_netdev(ndev); + + return 0; +} + +#ifdef CONFIG_PM +int stmmac_suspend(struct net_device *ndev) +{ + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned long flags; + + if (!ndev || !netif_running(ndev)) + return 0; + + if (priv->phydev) + phy_stop(priv->phydev); + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_detach(ndev); + netif_stop_queue(ndev); + + napi_disable(&priv->napi); + + /* Stop TX/RX DMA */ + priv->hw->dma->stop_tx(priv->ioaddr); + priv->hw->dma->stop_rx(priv->ioaddr); + + stmmac_clear_descriptors(priv); + + /* Enable Power down mode by programming the PMT regs */ + if (device_may_wakeup(priv->device)) + priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); + else { + stmmac_set_mac(priv->ioaddr, false); + /* Disable clock in case of PWM is off */ + clk_disable_unprepare(priv->stmmac_clk); + } + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +int stmmac_resume(struct net_device *ndev) +{ + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned long flags; + + if (!netif_running(ndev)) + return 0; + + spin_lock_irqsave(&priv->lock, flags); + + /* Power Down bit, into the PM register, is cleared + * automatically as soon as a magic packet or a Wake-up frame + * is received. Anyway, it's better to manually clear + * this bit because it can generate problems while resuming + * from another devices (e.g. serial console). + */ + if (device_may_wakeup(priv->device)) + priv->hw->mac->pmt(priv->ioaddr, 0); + else + /* enable the clk prevously disabled */ + clk_prepare_enable(priv->stmmac_clk); + + netif_device_attach(ndev); + + /* Enable the MAC and DMA */ + stmmac_set_mac(priv->ioaddr, true); + priv->hw->dma->start_tx(priv->ioaddr); + priv->hw->dma->start_rx(priv->ioaddr); + + napi_enable(&priv->napi); + + netif_start_queue(ndev); + + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->phydev) + phy_start(priv->phydev); + + return 0; +} + +int stmmac_freeze(struct net_device *ndev) +{ + if (!ndev || !netif_running(ndev)) + return 0; + + return stmmac_release(ndev); +} + +int stmmac_restore(struct net_device *ndev) +{ + if (!ndev || !netif_running(ndev)) + return 0; + + return stmmac_open(ndev); +} +#endif /* CONFIG_PM */ + +/* Driver can be configured w/ and w/ both PCI and Platf drivers + * depending on the configuration selected. + */ +static int __init stmmac_init(void) +{ + int ret; + + ret = stmmac_register_platform(); + if (ret) + goto err; + ret = stmmac_register_pci(); + if (ret) + goto err_pci; + return 0; +err_pci: + stmmac_unregister_platform(); +err: + pr_err("stmmac: driver registration failed\n"); + return ret; +} + +static void __exit stmmac_exit(void) +{ + stmmac_unregister_platform(); + stmmac_unregister_pci(); +} + +module_init(stmmac_init); +module_exit(stmmac_exit); + +#ifndef MODULE +static int __init stmmac_cmdline_opt(char *str) +{ + char *opt; + + if (!str || !*str) + return -EINVAL; + while ((opt = strsep(&str, ",")) != NULL) { + if (!strncmp(opt, "debug:", 6)) { + if (kstrtoint(opt + 6, 0, &debug)) + goto err; + } else if (!strncmp(opt, "phyaddr:", 8)) { + if (kstrtoint(opt + 8, 0, &phyaddr)) + goto err; + } else if (!strncmp(opt, "dma_txsize:", 11)) { + if (kstrtoint(opt + 11, 0, &dma_txsize)) + goto err; + } else if (!strncmp(opt, "dma_rxsize:", 11)) { + if (kstrtoint(opt + 11, 0, &dma_rxsize)) + goto err; + } else if (!strncmp(opt, "buf_sz:", 7)) { + if (kstrtoint(opt + 7, 0, &buf_sz)) + goto err; + } else if (!strncmp(opt, "tc:", 3)) { + if (kstrtoint(opt + 3, 0, &tc)) + goto err; + } else if (!strncmp(opt, "watchdog:", 9)) { + if (kstrtoint(opt + 9, 0, &watchdog)) + goto err; + } else if (!strncmp(opt, "flow_ctrl:", 10)) { + if (kstrtoint(opt + 10, 0, &flow_ctrl)) + goto err; + } else if (!strncmp(opt, "pause:", 6)) { + if (kstrtoint(opt + 6, 0, &pause)) + goto err; + } else if (!strncmp(opt, "eee_timer:", 10)) { + if (kstrtoint(opt + 10, 0, &eee_timer)) + goto err; + } else if (!strncmp(opt, "chain_mode:", 11)) { + if (kstrtoint(opt + 11, 0, &chain_mode)) + goto err; + } + } + return 0; + +err: + pr_err("%s: ERROR broken module parameter conversion", __func__); + return -EINVAL; +} + +__setup("stmmaceth=", stmmac_cmdline_opt); +#endif /* MODULE */ + +MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver"); +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c b/drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c new file mode 100755 index 000000000000..4b148e9c217c --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c @@ -0,0 +1,270 @@ +/******************************************************************************* + 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 + Maintainer: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include +#include +#include + +#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 + */ +static int stmmac_mdio_reset(struct mii_bus *bus) +{ + struct net_device *ndev = bus->priv; + struct stmmac_priv *priv = netdev_priv(ndev); + unsigned int mii_address = priv->hw->mii.addr; + + if (priv->plat->mdio_bus_data->phy_reset) { + pr_debug("stmmac_mdio_reset: calling phy_reset\n"); + priv->plat->mdio_bus_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); + 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 + irqlist = priv->mii_irq; + + 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_warning("%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; +} diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_pci.c b/drivers/net/ethernet/rockchip/gmac/stmmac_pci.c new file mode 100755 index 000000000000..023b7c29cb2f --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_pci.c @@ -0,0 +1,196 @@ +/******************************************************************************* + 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 + Author: Giuseppe Cavallaro +*******************************************************************************/ + +#include +#include "stmmac.h" + +struct plat_stmmacenet_data plat_dat; +struct stmmac_mdio_bus_data mdio_data; +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; +} + +/** + * 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 (!priv) { + pr_err("%s: main driver probe failed", __func__); + ret = -ENODEV; + 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_set_drvdata(pdev, NULL); + pci_iounmap(pdev, priv->ioaddr); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + int ret; + + ret = stmmac_suspend(ndev); + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return ret; +} + +static int stmmac_pci_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + return stmmac_resume(ndev); +} +#endif + +#define STMMAC_VENDOR_ID 0x700 +#define STMMAC_DEVICE_ID 0x1108 + +static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = { + {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, + {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 "); +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c b/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c new file mode 100755 index 000000000000..1d3780f55ba2 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c @@ -0,0 +1,252 @@ +/******************************************************************************* + 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 +*******************************************************************************/ + +#include +#include +#include +#include +#include "stmmac.h" + +#ifdef CONFIG_OF +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; + + if (!np) + return -ENODEV; + + *mac = of_get_mac_address(np); + plat->interface = of_get_phy_mode(np); + plat->mdio_bus_data = devm_kzalloc(&pdev->dev, + sizeof(struct stmmac_mdio_bus_data), + GFP_KERNEL); + + /* + * 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")) { + plat->has_gmac = 1; + plat->pmt = 1; + } + + 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); + if (!res) + return -ENODEV; + + addr = devm_ioremap_resource(dev, res); + if (IS_ERR(addr)) + return PTR_ERR(addr); + + if (pdev->dev.of_node) { + 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; + } + + ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); + if (ret) { + pr_err("%s: main dt probe failed", __func__); + return ret; + } + } else { + plat_dat = pdev->dev.platform_data; + } + + /* Custom initialisation (if needed)*/ + if (plat_dat->init) { + ret = plat_dat->init(pdev); + if (unlikely(ret)) + return ret; + } + + priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); + if (!priv) { + pr_err("%s: main driver probe failed", __func__); + return -ENODEV; + } + + /* 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 == -ENXIO) { + pr_err("%s: ERROR: MAC IRQ configuration " + "information not found\n", __func__); + return -ENXIO; + } + + /* + * On some platforms e.g. SPEAr the wake up irq differs from the mac irq + * The external wake up irq can be passed through the platform code + * named as "eth_wake_irq" + * + * In case the wake up interrupt is not passed from the platform + * so the driver will continue to use the mac irq (ndev->irq) + */ + priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); + if (priv->wol_irq == -ENXIO) + priv->wol_irq = priv->dev->irq; + + priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); + + platform_set_drvdata(pdev, priv->dev); + + 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); + + platform_set_drvdata(pdev, NULL); + + return ret; +} + +#ifdef CONFIG_PM +static int stmmac_pltfr_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + return stmmac_suspend(ndev); +} + +static int stmmac_pltfr_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + + return stmmac_resume(ndev); +} + +int stmmac_pltfr_freeze(struct device *dev) +{ + int ret; + struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + + ret = stmmac_freeze(ndev); + if (plat_dat->exit) + plat_dat->exit(pdev); + + return ret; +} + +int stmmac_pltfr_restore(struct device *dev) +{ + struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); + struct net_device *ndev = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + + if (plat_dat->init) + plat_dat->init(pdev); + + return stmmac_restore(ndev); +} + +static const struct dev_pm_ops stmmac_pltfr_pm_ops = { + .suspend = stmmac_pltfr_suspend, + .resume = stmmac_pltfr_resume, + .freeze = stmmac_pltfr_freeze, + .thaw = stmmac_pltfr_restore, + .restore = stmmac_pltfr_restore, +}; +#else +static const struct dev_pm_ops stmmac_pltfr_pm_ops; +#endif /* CONFIG_PM */ + +static const struct of_device_id stmmac_dt_ids[] = { + { .compatible = "st,spear600-gmac"}, + { .compatible = "snps,dwmac-3.70a"}, + { .compatible = "snps,dwmac"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, stmmac_dt_ids); + +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 "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c b/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c new file mode 100755 index 000000000000..b8b0eeed0f92 --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c @@ -0,0 +1,211 @@ +/******************************************************************************* + 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 +*******************************************************************************/ +#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->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->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, + .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); + pr_debug("Removed PTP HW clock successfully on %s\n", + priv->dev->name); + } +} diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h b/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h new file mode 100755 index 000000000000..3dbc047622fa --- /dev/null +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h @@ -0,0 +1,74 @@ +/****************************************************************************** + 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 +******************************************************************************/ + +#ifndef __STMMAC_PTP_H__ +#define __STMMAC_PTP_H__ + +#define STMMAC_SYSCLOCK 62500000 + +/* 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__ */ diff --git a/drivers/net/ethernet/rk/vmac/Kconfig b/drivers/net/ethernet/rockchip/vmac/Kconfig similarity index 100% rename from drivers/net/ethernet/rk/vmac/Kconfig rename to drivers/net/ethernet/rockchip/vmac/Kconfig diff --git a/drivers/net/ethernet/rk/vmac/Makefile b/drivers/net/ethernet/rockchip/vmac/Makefile similarity index 100% rename from drivers/net/ethernet/rk/vmac/Makefile rename to drivers/net/ethernet/rockchip/vmac/Makefile diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac.c b/drivers/net/ethernet/rockchip/vmac/rk29_vmac.c similarity index 100% rename from drivers/net/ethernet/rk/vmac/rk29_vmac.c rename to drivers/net/ethernet/rockchip/vmac/rk29_vmac.c diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac.h b/drivers/net/ethernet/rockchip/vmac/rk29_vmac.h similarity index 100% rename from drivers/net/ethernet/rk/vmac/rk29_vmac.h rename to drivers/net/ethernet/rockchip/vmac/rk29_vmac.h diff --git a/drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c b/drivers/net/ethernet/rockchip/vmac/rk29_vmac_phy.c similarity index 97% rename from drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c rename to drivers/net/ethernet/rockchip/vmac/rk29_vmac_phy.c index 24614f90a43e..3b328d3ffbdf 100755 --- a/drivers/net/ethernet/rk/vmac/rk29_vmac_phy.c +++ b/drivers/net/ethernet/rockchip/vmac/rk29_vmac_phy.c @@ -148,14 +148,14 @@ static int vmac_phy_remove(struct platform_device *pdev) } static struct of_device_id vmac_phy_of_match[] = { - { .compatible = "vmac-phy" }, + { .compatible = "rockchip,vmac-phy" }, { } }; MODULE_DEVICE_TABLE(of, vmac_phy_of_match); static struct platform_driver vmac_phy_driver = { .driver = { - .name = "vmac-phy", + .name = "rockchip,vmac-phy", .owner = THIS_MODULE, .of_match_table = of_match_ptr(vmac_phy_of_match), }, @@ -166,4 +166,4 @@ static struct platform_driver vmac_phy_driver = { module_platform_driver(vmac_phy_driver); MODULE_DESCRIPTION("VMAC PHY Power Driver"); -MODULE_LICENSE("GPL"); \ No newline at end of file +MODULE_LICENSE("GPL"); -- 2.34.1