stmmac: Move the STMicroelectronics driver
Move the STMicroelectronics driver into driver/net/ethernet/stmicro/ and make the necessary Kconfig and Makefile changes. CC: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
@@ -30,6 +30,7 @@ source "drivers/net/ethernet/qlogic/Kconfig"
|
||||
source "drivers/net/ethernet/racal/Kconfig"
|
||||
source "drivers/net/ethernet/sfc/Kconfig"
|
||||
source "drivers/net/ethernet/smsc/Kconfig"
|
||||
source "drivers/net/ethernet/stmicro/Kconfig"
|
||||
source "drivers/net/ethernet/sun/Kconfig"
|
||||
source "drivers/net/ethernet/tehuti/Kconfig"
|
||||
|
||||
|
@@ -21,5 +21,6 @@ obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
|
||||
obj-$(CONFIG_NET_VENDOR_RACAL) += racal/
|
||||
obj-$(CONFIG_SFC) += sfc/
|
||||
obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
|
||||
obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
|
||||
obj-$(CONFIG_NET_VENDOR_SUN) += sun/
|
||||
obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
|
||||
|
22
drivers/net/ethernet/stmicro/Kconfig
Normal file
22
drivers/net/ethernet/stmicro/Kconfig
Normal file
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# STMicroelectronics device configuration
|
||||
#
|
||||
|
||||
config NET_VENDOR_STMICRO
|
||||
bool "STMicroelectronics devices"
|
||||
depends on HAS_IOMEM
|
||||
---help---
|
||||
If you have a network (Ethernet) card belonging to this class, say Y
|
||||
and read the Ethernet-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
Note that the answer to this question doesn't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about STMicroelectronics cards. If you say Y, you will
|
||||
be asked for your specific card in the following questions.
|
||||
|
||||
if NET_VENDOR_STMICRO
|
||||
|
||||
source "drivers/net/ethernet/stmicro/stmmac/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_STMICRO
|
5
drivers/net/ethernet/stmicro/Makefile
Normal file
5
drivers/net/ethernet/stmicro/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for the STMicroelectronics device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_STMMAC_ETH) += stmmac/
|
57
drivers/net/ethernet/stmicro/stmmac/Kconfig
Normal file
57
drivers/net/ethernet/stmicro/stmmac/Kconfig
Normal file
@@ -0,0 +1,57 @@
|
||||
config STMMAC_ETH
|
||||
tristate "STMicroelectronics 10/100/1000 Ethernet driver"
|
||||
depends on HAS_IOMEM
|
||||
select MII
|
||||
select PHYLIB
|
||||
select CRC32
|
||||
---help---
|
||||
This is the driver for the Ethernet IPs are built around a
|
||||
Synopsys IP Core and only tested on the STMicroelectronics
|
||||
platforms.
|
||||
|
||||
if STMMAC_ETH
|
||||
|
||||
config STMMAC_DA
|
||||
bool "STMMAC DMA arbitration scheme"
|
||||
default n
|
||||
---help---
|
||||
Selecting this option, rx has priority over Tx (only for Giga
|
||||
Ethernet device).
|
||||
By default, the DMA arbitration scheme is based on Round-robin
|
||||
(rx:tx priority is 1:1).
|
||||
|
||||
config STMMAC_DUAL_MAC
|
||||
bool "STMMAC: dual mac support (EXPERIMENTAL)"
|
||||
default n
|
||||
depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER
|
||||
---help---
|
||||
Some ST SoCs (for example the stx7141 and stx7200c2) have two
|
||||
Ethernet Controllers. This option turns on the second Ethernet
|
||||
device on this kind of platforms.
|
||||
|
||||
config STMMAC_TIMER
|
||||
bool "STMMAC Timer optimisation"
|
||||
default n
|
||||
depends on RTC_HCTOSYS_DEVICE
|
||||
---help---
|
||||
Use an external timer for mitigating the number of network
|
||||
interrupts. Currently, for SH architectures, it is possible
|
||||
to use the TMU channel 2 and the SH-RTC device.
|
||||
|
||||
choice
|
||||
prompt "Select Timer device"
|
||||
depends on STMMAC_TIMER
|
||||
|
||||
config STMMAC_TMU_TIMER
|
||||
bool "TMU channel 2"
|
||||
depends on CPU_SH4
|
||||
---help---
|
||||
|
||||
config STMMAC_RTC_TIMER
|
||||
bool "Real time clock"
|
||||
depends on RTC_CLASS
|
||||
---help---
|
||||
|
||||
endchoice
|
||||
|
||||
endif
|
5
drivers/net/ethernet/stmicro/stmmac/Makefile
Normal file
5
drivers/net/ethernet/stmicro/stmmac/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
|
||||
stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
|
||||
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
|
||||
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
|
||||
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o $(stmmac-y)
|
252
drivers/net/ethernet/stmicro/stmmac/common.h
Normal file
252
drivers/net/ethernet/stmicro/stmmac/common.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Common Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
#define STMMAC_VLAN_TAG_USED
|
||||
#include <linux/if_vlan.h>
|
||||
#endif
|
||||
|
||||
#include "descs.h"
|
||||
|
||||
#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
|
||||
|
||||
#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 tx_heartbeat;
|
||||
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 rx_partial;
|
||||
unsigned long rx_runt;
|
||||
unsigned long rx_toolong;
|
||||
unsigned long rx_collision;
|
||||
unsigned long rx_crc;
|
||||
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 errors */
|
||||
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;
|
||||
/* Extra info */
|
||||
unsigned long threshold;
|
||||
unsigned long tx_pkt_n;
|
||||
unsigned long rx_pkt_n;
|
||||
unsigned long poll_n;
|
||||
unsigned long sched_timer_n;
|
||||
unsigned long normal_irq_n;
|
||||
};
|
||||
|
||||
#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)
|
||||
|
||||
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
|
||||
|
||||
enum rx_frame_status { /* IPC status */
|
||||
good_frame = 0,
|
||||
discard_frame = 1,
|
||||
csum_none = 2,
|
||||
llc_snap = 4,
|
||||
};
|
||||
|
||||
enum tx_dma_irq_status {
|
||||
tx_hard_error = 1,
|
||||
tx_hard_error_bump_tc = 2,
|
||||
handle_tx_rx = 3,
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* MAC Management Counters register */
|
||||
#define MMC_CONTROL 0x00000100 /* MMC Control */
|
||||
#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
|
||||
#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
|
||||
#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
|
||||
#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
|
||||
|
||||
#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
|
||||
#define MMC_CONTROL_MAX_FRM_SHIFT 3
|
||||
#define MMC_CONTROL_MAX_FRAME 0x7FF
|
||||
|
||||
struct stmmac_desc_ops {
|
||||
/* DMA RX descriptor ring initialization */
|
||||
void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
|
||||
int disable_rx_ic);
|
||||
/* DMA TX descriptor ring initialization */
|
||||
void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size);
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
/* 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);
|
||||
/* Return the reception status looking at the RDES1 */
|
||||
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p);
|
||||
};
|
||||
|
||||
struct stmmac_dma_ops {
|
||||
/* DMA core initialization */
|
||||
int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
|
||||
/* 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);
|
||||
};
|
||||
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
|
||||
/* Support checksum offload engine */
|
||||
int (*rx_coe) (void __iomem *ioaddr);
|
||||
/* Dump MAC registers */
|
||||
void (*dump_regs) (void __iomem *ioaddr);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
void (*host_irq_status) (void __iomem *ioaddr);
|
||||
/* Multicast filter setting */
|
||||
void (*set_filter) (struct net_device *dev);
|
||||
/* 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);
|
||||
};
|
||||
|
||||
struct mac_link {
|
||||
int port;
|
||||
int duplex;
|
||||
int speed;
|
||||
};
|
||||
|
||||
struct mii_regs {
|
||||
unsigned int addr; /* MII Address */
|
||||
unsigned int data; /* MII Data */
|
||||
};
|
||||
|
||||
struct mac_device_info {
|
||||
const struct stmmac_ops *mac;
|
||||
const struct stmmac_desc_ops *desc;
|
||||
const struct stmmac_dma_ops *dma;
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
struct mac_link link;
|
||||
};
|
||||
|
||||
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 dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
163
drivers/net/ethernet/stmicro/stmmac/descs.h
Normal file
163
drivers/net/ethernet/stmicro/stmmac/descs.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
Header File to describe the DMA descriptors.
|
||||
Enhanced descriptors have been in case of DWMAC1000 Cores.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
struct dma_desc {
|
||||
/* Receive descriptor */
|
||||
union {
|
||||
struct {
|
||||
/* RDES0 */
|
||||
u32 reserved1:1;
|
||||
u32 crc_error:1;
|
||||
u32 dribbling:1;
|
||||
u32 mii_error:1;
|
||||
u32 receive_watchdog:1;
|
||||
u32 frame_type:1;
|
||||
u32 collision:1;
|
||||
u32 frame_too_long:1;
|
||||
u32 last_descriptor:1;
|
||||
u32 first_descriptor:1;
|
||||
u32 multicast_frame:1;
|
||||
u32 run_frame:1;
|
||||
u32 length_error:1;
|
||||
u32 partial_frame_error:1;
|
||||
u32 descriptor_error:1;
|
||||
u32 error_summary:1;
|
||||
u32 frame_length:14;
|
||||
u32 filtering_fail:1;
|
||||
u32 own:1;
|
||||
/* RDES1 */
|
||||
u32 buffer1_size:11;
|
||||
u32 buffer2_size:11;
|
||||
u32 reserved2:2;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 reserved3:5;
|
||||
u32 disable_ic:1;
|
||||
} rx;
|
||||
struct {
|
||||
/* RDES0 */
|
||||
u32 payload_csum_error: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 heartbeat_fail:1;
|
||||
u32 excessive_collisions:1;
|
||||
u32 late_collision:1;
|
||||
u32 no_carrier:1;
|
||||
u32 loss_carrier:1;
|
||||
u32 reserved1:3;
|
||||
u32 error_summary:1;
|
||||
u32 reserved2:15;
|
||||
u32 own:1;
|
||||
/* TDES1 */
|
||||
u32 buffer1_size:11;
|
||||
u32 buffer2_size:11;
|
||||
u32 reserved3:1;
|
||||
u32 disable_padding:1;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 crc_disable:1;
|
||||
u32 reserved4: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;
|
||||
};
|
||||
|
||||
/* Transmit checksum insertion control */
|
||||
enum tdes_csum_insertion {
|
||||
cic_disabled = 0, /* Checksum Insertion Control */
|
||||
cic_only_ip = 1, /* Only IP header */
|
||||
cic_no_pseudoheader = 2, /* IP header but pseudoheader
|
||||
* is not calculated */
|
||||
cic_full = 3, /* IP header and pseudoheader */
|
||||
};
|
121
drivers/net/ethernet/stmicro/stmmac/dwmac100.h
Normal file
121
drivers/net/ethernet/stmicro/stmmac/dwmac100.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*******************************************************************************
|
||||
MAC 10/100 Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* MAC BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
/* MAC CSR offset */
|
||||
#define MAC_CONTROL 0x00000000 /* MAC Control */
|
||||
#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
|
||||
#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
|
||||
#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
|
||||
#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
|
||||
#define MAC_MII_ADDR 0x00000014 /* MII Address */
|
||||
#define MAC_MII_DATA 0x00000018 /* MII Data */
|
||||
#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
|
||||
#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
|
||||
#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
|
||||
|
||||
/* MAC CTRL defines */
|
||||
#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
|
||||
#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
|
||||
#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
|
||||
#define MAC_CONTROL_PS 0x08000000 /* Port Select */
|
||||
#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
|
||||
#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
|
||||
#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
|
||||
#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
|
||||
#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
|
||||
#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
|
||||
#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
|
||||
#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
|
||||
#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
|
||||
#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
|
||||
#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
|
||||
#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
|
||||
#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
|
||||
#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
|
||||
#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
|
||||
#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
|
||||
#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
|
||||
#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
|
||||
#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
|
||||
#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define MAC_CORE_INIT (MAC_CONTROL_HBD | MAC_CONTROL_ASTP)
|
||||
|
||||
/* MAC FLOW CTRL defines */
|
||||
#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define MAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
|
||||
#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
|
||||
#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* MII ADDR defines */
|
||||
#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* DMA BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
|
||||
#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
#define DMA_BUS_MODE_DEFAULT 0x00000000
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
|
||||
|
||||
/* Transmit Threshold Control */
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
|
||||
DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
|
||||
DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
|
||||
DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
|
||||
DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
|
||||
DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
|
||||
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
|
||||
};
|
||||
|
||||
/* STMAC110 DMA Missed Frame Counter register defines */
|
||||
#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
|
||||
#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
|
||||
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
208
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
Normal file
208
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
#define GMAC_CONTROL 0x00000000 /* Configuration */
|
||||
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
|
||||
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
|
||||
#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
|
||||
#define GMAC_MII_ADDR 0x00000010 /* MII Address */
|
||||
#define GMAC_MII_DATA 0x00000014 /* MII Data */
|
||||
#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
|
||||
#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
|
||||
|
||||
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
|
||||
enum dwmac1000_irq_status {
|
||||
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,
|
||||
};
|
||||
|
||||
/* GMAC HW ADDR regs */
|
||||
#define GMAC_ADDR_HIGH(reg) (0x00000040+(reg * 8))
|
||||
#define GMAC_ADDR_LOW(reg) (0x00000044+(reg * 8))
|
||||
#define GMAC_MAX_UNICAST_ADDRESSES 16
|
||||
|
||||
#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_LINK 0x000000cc /* Auto-Neg. link partener ability */
|
||||
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
|
||||
#define GMAC_TBI 0x000000d4 /* TBI extend status */
|
||||
#define GMAC_GMII_STATUS 0x000000d8 /* S/R-GMII status */
|
||||
|
||||
/* 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 during tx */
|
||||
#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 /* Automatic 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
|
||||
|
||||
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_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 17
|
||||
#define DMA_BUS_MODE_USP 0x00800000
|
||||
#define DMA_BUS_MODE_4PBL 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)*/
|
||||
#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */
|
||||
#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;
|
251
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
Normal file
251
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/io.h>
|
||||
#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);
|
||||
|
||||
/* STBus Bridge Configuration */
|
||||
/*writel(0xc5608, ioaddr + 0x00007000);*/
|
||||
|
||||
/* Freeze MMC counters */
|
||||
writel(0x8, ioaddr + GMAC_MMC_CTRL);
|
||||
/* Mask GMAC interrupts */
|
||||
writel(0x207, ioaddr + GMAC_INT_MASK);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
/* Tag detection without filtering */
|
||||
writel(0x0, ioaddr + GMAC_VLAN_TAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dwmac1000_rx_coe_supported(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)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *) dev->base_addr;
|
||||
unsigned int value = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Handle multiple unicast addresses (perfect filtering)*/
|
||||
if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES)
|
||||
/* Switch to promiscuous mode is 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 "\tFrame Filter reg: 0x%08x\n\tHash regs: "
|
||||
"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 void dwmac1000_irq_status(void __iomem *ioaddr)
|
||||
{
|
||||
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
|
||||
|
||||
/* Not used events (e.g. MMC interrupts) are not handled. */
|
||||
if ((intr_status & mmc_tx_irq))
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_TX_INTR));
|
||||
if (unlikely(intr_status & mmc_rx_irq))
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_RX_INTR));
|
||||
if (unlikely(intr_status & mmc_rx_csum_offload_irq))
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
|
||||
if (unlikely(intr_status & pmt_irq)) {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n");
|
||||
/* clear the PMT bits 5 and 6 by reading the PMT
|
||||
* status register. */
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac1000_ops = {
|
||||
.core_init = dwmac1000_core_init,
|
||||
.rx_coe = dwmac1000_rx_coe_supported,
|
||||
.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,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
|
||||
{
|
||||
struct mac_device_info *mac;
|
||||
u32 uid = readl(ioaddr + GMAC_VERSION);
|
||||
|
||||
pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
|
||||
((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
|
||||
|
||||
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;
|
||||
|
||||
return mac;
|
||||
}
|
155
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
Normal file
155
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "dwmac1000.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
|
||||
u32 dma_rx)
|
||||
{
|
||||
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 = 15000;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL |
|
||||
((pbl << DMA_BUS_MODE_PBL_SHIFT) |
|
||||
(pbl << DMA_BUS_MODE_RPBL_SHIFT));
|
||||
|
||||
#ifdef CONFIG_STMMAC_DA
|
||||
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
|
||||
#endif
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
|
||||
/* The base address of the RX/TX descriptor 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 store and forward mode"
|
||||
" (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: disabling RX store and forward 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);
|
||||
}
|
||||
|
||||
/* Not yet implemented --- no RMON module */
|
||||
static void dwmac1000_dma_diagnostic_fr(void *data,
|
||||
struct stmmac_extra_stats *x, void __iomem *ioaddr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac1000_dma_ops = {
|
||||
.init = dwmac1000_dma_init,
|
||||
.dump_regs = dwmac1000_dump_dma_regs,
|
||||
.dma_mode = dwmac1000_dma_operation_mode,
|
||||
.dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.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,
|
||||
};
|
204
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
Normal file
204
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
|
||||
static void dwmac100_core_init(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 int dwmac100_rx_coe_supported(void __iomem *ioaddr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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));
|
||||
pr_info("\n\tMAC management counter registers\n");
|
||||
pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
|
||||
MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
|
||||
pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
|
||||
MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
|
||||
pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
|
||||
MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
|
||||
pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
|
||||
MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
|
||||
pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
|
||||
MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
|
||||
}
|
||||
|
||||
static void dwmac100_irq_status(void __iomem *ioaddr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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: CTRL reg: 0x%08x Hash regs: "
|
||||
"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 for this Ethernet Controller.
|
||||
* Tested on ST platforms only.
|
||||
*/
|
||||
static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac100_ops = {
|
||||
.core_init = dwmac100_core_init,
|
||||
.rx_coe = dwmac100_rx_coe_supported,
|
||||
.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;
|
||||
|
||||
return mac;
|
||||
}
|
143
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
Normal file
143
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
|
||||
u32 dma_rx)
|
||||
{
|
||||
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 = 15000;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
/* The base address of the RX/TX descriptor 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 receive 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,
|
||||
};
|
108
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
Normal file
108
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*******************************************************************************
|
||||
DWMAC DMA Header file.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
/* 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 */
|
||||
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
|
||||
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
|
||||
|
||||
/* 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_GPI 0x10000000 /* PMT interrupt */
|
||||
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
|
||||
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
|
||||
#define DMA_STATUS_GMI 0x08000000
|
||||
#define DMA_STATUS_GLI 0x04000000
|
||||
#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);
|
258
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
Normal file
258
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#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
|
||||
|
||||
/* 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 (intr_status & DMA_STATUS_NIS) {
|
||||
x->normal_irq_n++;
|
||||
if (likely((intr_status & DMA_STATUS_RI) ||
|
||||
(intr_status & (DMA_STATUS_TI))))
|
||||
ret = handle_tx_rx;
|
||||
}
|
||||
/* 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];
|
||||
writel(data, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
337
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
Normal file
337
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
Normal file
@@ -0,0 +1,337 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the enhanced descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "common.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 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.payload_csum_error);
|
||||
|
||||
if (unlikely(p->des01.erx.dribbling)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
|
||||
ret = discard_frame;
|
||||
}
|
||||
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, unsigned int ring_size,
|
||||
int disable_rx_ic)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ring_size; i++) {
|
||||
p->des01.erx.own = 1;
|
||||
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
|
||||
/* To support jumbo frames */
|
||||
p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
|
||||
if (i == ring_size - 1)
|
||||
p->des01.erx.end_ring = 1;
|
||||
if (disable_rx_ic)
|
||||
p->des01.erx.disable_ic = 1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ring_size; i++) {
|
||||
p->des01.etx.own = 0;
|
||||
if (i == ring_size - 1)
|
||||
p->des01.etx.end_ring = 1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
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 ter = p->des01.etx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
p->des01.etx.end_ring = ter;
|
||||
}
|
||||
|
||||
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag)
|
||||
{
|
||||
p->des01.etx.first_segment = is_fs;
|
||||
if (unlikely(len > BUF_SIZE_4KiB)) {
|
||||
p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
|
||||
p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
|
||||
} else {
|
||||
p->des01.etx.buffer1_size = len;
|
||||
}
|
||||
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)
|
||||
{
|
||||
return p->des01.erx.frame_length;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
221
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
Normal file
221
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the normal descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "common.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 (unlikely(p->des01.tx.heartbeat_fail)) {
|
||||
x->tx_heartbeat++;
|
||||
stats->tx_heartbeat_errors++;
|
||||
ret = -1;
|
||||
}
|
||||
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 csum_none because the device
|
||||
* is not able to compute the csum in HW. */
|
||||
static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = csum_none;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.rx.last_descriptor == 0)) {
|
||||
pr_warning("ndesc Error: Oversized Ethernet "
|
||||
"frame spanned multiple buffers\n");
|
||||
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.partial_frame_error))
|
||||
x->rx_partial++;
|
||||
if (unlikely(p->des01.rx.run_frame))
|
||||
x->rx_runt++;
|
||||
if (unlikely(p->des01.rx.frame_too_long))
|
||||
x->rx_toolong++;
|
||||
if (unlikely(p->des01.rx.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))
|
||||
ret = discard_frame;
|
||||
|
||||
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;
|
||||
}
|
||||
if (p->des01.rx.multicast_frame) {
|
||||
x->rx_multicast++;
|
||||
stats->multicast++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
|
||||
int disable_rx_ic)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ring_size; i++) {
|
||||
p->des01.rx.own = 1;
|
||||
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
|
||||
if (i == ring_size - 1)
|
||||
p->des01.rx.end_ring = 1;
|
||||
if (disable_rx_ic)
|
||||
p->des01.rx.disable_ic = 1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ring_size; i++) {
|
||||
p->des01.tx.own = 0;
|
||||
if (i == ring_size - 1)
|
||||
p->des01.tx.end_ring = 1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
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 ter = p->des01.tx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
/* set termination field */
|
||||
p->des01.tx.end_ring = ter;
|
||||
}
|
||||
|
||||
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag)
|
||||
{
|
||||
p->des01.tx.first_segment = is_fs;
|
||||
p->des01.tx.buffer1_size = len;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return p->des01.rx.frame_length;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
85
drivers/net/ethernet/stmicro/stmmac/stmmac.h
Normal file
85
drivers/net/ethernet/stmicro/stmmac/stmmac.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#define DRV_MODULE_VERSION "July_2011"
|
||||
#include <linux/stmmac.h>
|
||||
|
||||
#include "common.h"
|
||||
#ifdef CONFIG_STMMAC_TIMER
|
||||
#include "stmmac_timer.h"
|
||||
#endif
|
||||
|
||||
struct stmmac_priv {
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
struct dma_desc *dma_tx ____cacheline_aligned;
|
||||
dma_addr_t dma_tx_phy;
|
||||
struct sk_buff **tx_skbuff;
|
||||
unsigned int cur_tx;
|
||||
unsigned int dirty_tx;
|
||||
unsigned int dma_tx_size;
|
||||
int tx_coalesce;
|
||||
|
||||
struct dma_desc *dma_rx ;
|
||||
unsigned int cur_rx;
|
||||
unsigned int dirty_rx;
|
||||
struct sk_buff **rx_skbuff;
|
||||
dma_addr_t *rx_skbuff_dma;
|
||||
struct sk_buff_head rx_recycle;
|
||||
|
||||
struct net_device *dev;
|
||||
dma_addr_t dma_rx_phy;
|
||||
unsigned int dma_rx_size;
|
||||
unsigned int dma_buf_sz;
|
||||
struct device *device;
|
||||
struct mac_device_info *hw;
|
||||
void __iomem *ioaddr;
|
||||
|
||||
struct stmmac_extra_stats xstats;
|
||||
struct napi_struct napi;
|
||||
|
||||
int rx_coe;
|
||||
int no_csum_insertion;
|
||||
|
||||
struct phy_device *phydev;
|
||||
int oldlink;
|
||||
int speed;
|
||||
int oldduplex;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
int mii_irq[PHY_MAX_ADDR];
|
||||
|
||||
u32 msg_enable;
|
||||
spinlock_t lock;
|
||||
int wolopts;
|
||||
int wolenabled;
|
||||
#ifdef CONFIG_STMMAC_TIMER
|
||||
struct stmmac_timer *tm;
|
||||
#endif
|
||||
struct plat_stmmacenet_data *plat;
|
||||
};
|
||||
|
||||
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;
|
359
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
Normal file
359
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Ethtool support
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1054
|
||||
#define MAC100_ETHTOOL_NAME "st_mac100"
|
||||
#define GMAC_ETHTOOL_NAME "st_gmac"
|
||||
|
||||
struct stmmac_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int sizeof_stat;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define STMMAC_STAT(m) \
|
||||
{ #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
|
||||
offsetof(struct stmmac_priv, xstats.m)}
|
||||
|
||||
static const struct stmmac_stats stmmac_gstrings_stats[] = {
|
||||
STMMAC_STAT(tx_underflow),
|
||||
STMMAC_STAT(tx_carrier),
|
||||
STMMAC_STAT(tx_losscarrier),
|
||||
STMMAC_STAT(tx_heartbeat),
|
||||
STMMAC_STAT(tx_deferred),
|
||||
STMMAC_STAT(tx_vlan),
|
||||
STMMAC_STAT(rx_vlan),
|
||||
STMMAC_STAT(tx_jabber),
|
||||
STMMAC_STAT(tx_frame_flushed),
|
||||
STMMAC_STAT(tx_payload_error),
|
||||
STMMAC_STAT(tx_ip_header_error),
|
||||
STMMAC_STAT(rx_desc),
|
||||
STMMAC_STAT(rx_partial),
|
||||
STMMAC_STAT(rx_runt),
|
||||
STMMAC_STAT(rx_toolong),
|
||||
STMMAC_STAT(rx_collision),
|
||||
STMMAC_STAT(rx_crc),
|
||||
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(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),
|
||||
STMMAC_STAT(threshold),
|
||||
STMMAC_STAT(tx_pkt_n),
|
||||
STMMAC_STAT(rx_pkt_n),
|
||||
STMMAC_STAT(poll_n),
|
||||
STMMAC_STAT(sched_timer_n),
|
||||
STMMAC_STAT(normal_irq_n),
|
||||
};
|
||||
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
|
||||
|
||||
static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!priv->plat->has_gmac)
|
||||
strcpy(info->driver, MAC100_ETHTOOL_NAME);
|
||||
else
|
||||
strcpy(info->driver, GMAC_ETHTOOL_NAME);
|
||||
|
||||
strcpy(info->version, DRV_MODULE_VERSION);
|
||||
info->fw_version[0] = '\0';
|
||||
info->n_stats = STMMAC_STATS_LEN;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_getsettings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int rc;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/* Update HW stats if supported */
|
||||
priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
|
||||
priv->ioaddr);
|
||||
|
||||
for (i = 0; i < STMMAC_STATS_LEN; i++) {
|
||||
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
|
||||
data[i] = (stmmac_gstrings_stats[i].sizeof_stat ==
|
||||
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_get_sset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return STMMAC_STATS_LEN;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
||||
{
|
||||
int i;
|
||||
u8 *p = data;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
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;
|
||||
|
||||
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(dev->irq);
|
||||
} else {
|
||||
device_set_wakeup_enable(priv->device, 0);
|
||||
disable_irq_wake(dev->irq);
|
||||
}
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->wolopts = wol->wolopts;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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_sset_count = stmmac_get_sset_count,
|
||||
};
|
||||
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
|
||||
}
|
1895
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Normal file
1895
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
Normal file
File diff suppressed because it is too large
Load Diff
247
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
Normal file
247
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Ethernet Driver -- MDIO bus implementation
|
||||
Provides Bus interface for MII registers
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Carl Shaw <carl.shaw@st.com>
|
||||
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
#define MII_BUSY 0x00000001
|
||||
#define MII_WRITE 0x00000002
|
||||
|
||||
/**
|
||||
* 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->plat->clk_csr & 7) << 2);
|
||||
|
||||
do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
|
||||
writel(regValue, priv->ioaddr + mii_address);
|
||||
do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
|
||||
|
||||
/* 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->plat->clk_csr & 7) << 2);
|
||||
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
|
||||
|
||||
/* 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 */
|
||||
do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 MII Bus";
|
||||
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, "%x", mdio_bus_data->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;
|
||||
}
|
||||
|
||||
priv->mii = new_bus;
|
||||
|
||||
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->bus_id == mdio_bus_data->bus_id) &&
|
||||
(priv->plat->phy_addr == -1))
|
||||
priv->plat->phy_addr = addr;
|
||||
|
||||
act = (priv->plat->bus_id == mdio_bus_data->bus_id) &&
|
||||
(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);
|
||||
|
||||
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);
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
priv->mii = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
134
drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
Normal file
134
drivers/net/ethernet/stmicro/stmmac/stmmac_timer.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*******************************************************************************
|
||||
STMMAC external timer support.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include "stmmac_timer.h"
|
||||
|
||||
static void stmmac_timer_handler(void *data)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)data;
|
||||
|
||||
stmmac_schedule(dev);
|
||||
}
|
||||
|
||||
#define STMMAC_TIMER_MSG(timer, freq) \
|
||||
printk(KERN_INFO "stmmac_timer: %s Timer ON (freq %dHz)\n", timer, freq);
|
||||
|
||||
#if defined(CONFIG_STMMAC_RTC_TIMER)
|
||||
#include <linux/rtc.h>
|
||||
static struct rtc_device *stmmac_rtc;
|
||||
static rtc_task_t stmmac_task;
|
||||
|
||||
static void stmmac_rtc_start(unsigned int new_freq)
|
||||
{
|
||||
rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq);
|
||||
rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1);
|
||||
}
|
||||
|
||||
static void stmmac_rtc_stop(void)
|
||||
{
|
||||
rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
|
||||
}
|
||||
|
||||
int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
|
||||
{
|
||||
stmmac_task.private_data = dev;
|
||||
stmmac_task.func = stmmac_timer_handler;
|
||||
|
||||
stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
|
||||
if (stmmac_rtc == NULL) {
|
||||
pr_err("open rtc device failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rtc_irq_register(stmmac_rtc, &stmmac_task);
|
||||
|
||||
/* Periodic mode is not supported */
|
||||
if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) {
|
||||
pr_err("set periodic failed\n");
|
||||
rtc_irq_unregister(stmmac_rtc, &stmmac_task);
|
||||
rtc_class_close(stmmac_rtc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
STMMAC_TIMER_MSG(CONFIG_RTC_HCTOSYS_DEVICE, tm->freq);
|
||||
|
||||
tm->timer_start = stmmac_rtc_start;
|
||||
tm->timer_stop = stmmac_rtc_stop;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_close_ext_timer(void)
|
||||
{
|
||||
rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
|
||||
rtc_irq_unregister(stmmac_rtc, &stmmac_task);
|
||||
rtc_class_close(stmmac_rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_STMMAC_TMU_TIMER)
|
||||
#include <linux/clk.h>
|
||||
#define TMU_CHANNEL "tmu2_clk"
|
||||
static struct clk *timer_clock;
|
||||
|
||||
static void stmmac_tmu_start(unsigned int new_freq)
|
||||
{
|
||||
clk_set_rate(timer_clock, new_freq);
|
||||
clk_enable(timer_clock);
|
||||
}
|
||||
|
||||
static void stmmac_tmu_stop(void)
|
||||
{
|
||||
clk_disable(timer_clock);
|
||||
}
|
||||
|
||||
int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
|
||||
{
|
||||
timer_clock = clk_get(NULL, TMU_CHANNEL);
|
||||
|
||||
if (timer_clock == NULL)
|
||||
return -1;
|
||||
|
||||
if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) {
|
||||
timer_clock = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
STMMAC_TIMER_MSG("TMU2", tm->freq);
|
||||
tm->timer_start = stmmac_tmu_start;
|
||||
tm->timer_stop = stmmac_tmu_stop;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_close_ext_timer(void)
|
||||
{
|
||||
clk_disable(timer_clock);
|
||||
tmu2_unregister_user();
|
||||
clk_put(timer_clock);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
42
drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
Normal file
42
drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
STMMAC external timer Header File.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
struct stmmac_timer {
|
||||
void (*timer_start) (unsigned int new_freq);
|
||||
void (*timer_stop) (void);
|
||||
unsigned int freq;
|
||||
unsigned int enable;
|
||||
};
|
||||
|
||||
/* Open the HW timer device and return 0 in case of success */
|
||||
int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm);
|
||||
/* Stop the timer and release it */
|
||||
int stmmac_close_ext_timer(void);
|
||||
/* Function used for scheduling task within the stmmac */
|
||||
void stmmac_schedule(struct net_device *dev);
|
||||
|
||||
#if defined(CONFIG_STMMAC_TMU_TIMER)
|
||||
extern int tmu2_register_user(void *fnt, void *data);
|
||||
extern void tmu2_unregister_user(void);
|
||||
#endif
|
Reference in New Issue
Block a user