ibm_emac: Remove the ibm_emac driver
The arch/ppc sub-tree has been removed in the powerpc git tree. The old ibm_emac driver is no longer used by anything as a result of this. This removes it, leaving the ibm_newemac driver as the proper driver to use for PowerPC boards with the EMAC hardware. Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
ebaac8c9a5
commit
84aee4889e
20 changed files with 0 additions and 5289 deletions
|
@ -3231,14 +3231,6 @@ L: linux-kernel@vger.kernel.org
|
|||
T: git git.infradead.org/battery-2.6.git
|
||||
S: Maintained
|
||||
|
||||
POWERPC 4xx EMAC DRIVER
|
||||
P: Eugene Surovegin
|
||||
M: ebs@ebshome.net
|
||||
W: http://kernel.ebshome.net/emac/
|
||||
L: linuxppc-dev@ozlabs.org
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
PNP SUPPORT
|
||||
P: Adam Belay
|
||||
M: ambx1@neo.rr.com
|
||||
|
|
|
@ -1255,7 +1255,6 @@ config IBMVETH
|
|||
To compile this driver as a module, choose M here. The module will
|
||||
be called ibmveth.
|
||||
|
||||
source "drivers/net/ibm_emac/Kconfig"
|
||||
source "drivers/net/ibm_newemac/Kconfig"
|
||||
|
||||
config NET_PCI
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
obj-$(CONFIG_E1000) += e1000/
|
||||
obj-$(CONFIG_E1000E) += e1000e/
|
||||
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
|
||||
obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
|
||||
obj-$(CONFIG_IGB) += igb/
|
||||
obj-$(CONFIG_IXGBE) += ixgbe/
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
config IBM_EMAC
|
||||
tristate "PowerPC 4xx on-chip Ethernet support"
|
||||
depends on 4xx && !PPC_MERGE
|
||||
help
|
||||
This driver supports the PowerPC 4xx EMAC family of on-chip
|
||||
Ethernet controllers.
|
||||
|
||||
config IBM_EMAC_RXB
|
||||
int "Number of receive buffers"
|
||||
depends on IBM_EMAC
|
||||
default "128"
|
||||
|
||||
config IBM_EMAC_TXB
|
||||
int "Number of transmit buffers"
|
||||
depends on IBM_EMAC
|
||||
default "64"
|
||||
|
||||
config IBM_EMAC_POLL_WEIGHT
|
||||
int "MAL NAPI polling weight"
|
||||
depends on IBM_EMAC
|
||||
default "32"
|
||||
|
||||
config IBM_EMAC_RX_COPY_THRESHOLD
|
||||
int "RX skb copy threshold (bytes)"
|
||||
depends on IBM_EMAC
|
||||
default "256"
|
||||
|
||||
config IBM_EMAC_RX_SKB_HEADROOM
|
||||
int "Additional RX skb headroom (bytes)"
|
||||
depends on IBM_EMAC
|
||||
default "0"
|
||||
help
|
||||
Additional receive skb headroom. Note, that driver
|
||||
will always reserve at least 2 bytes to make IP header
|
||||
aligned, so usually there is no need to add any additional
|
||||
headroom.
|
||||
|
||||
If unsure, set to 0.
|
||||
|
||||
config IBM_EMAC_PHY_RX_CLK_FIX
|
||||
bool "PHY Rx clock workaround"
|
||||
depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
|
||||
help
|
||||
Enable this if EMAC attached to a PHY which doesn't generate
|
||||
RX clock if there is no link, if this is the case, you will
|
||||
see "TX disable timeout" or "RX disable timeout" in the system
|
||||
log.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config IBM_EMAC_DEBUG
|
||||
bool "Debugging"
|
||||
depends on IBM_EMAC
|
||||
default n
|
||||
|
||||
config IBM_EMAC_ZMII
|
||||
bool
|
||||
depends on IBM_EMAC && (NP405H || NP405L || 44x)
|
||||
default y
|
||||
|
||||
config IBM_EMAC_RGMII
|
||||
bool
|
||||
depends on IBM_EMAC && 440GX
|
||||
default y
|
||||
|
||||
config IBM_EMAC_TAH
|
||||
bool
|
||||
depends on IBM_EMAC && 440GX
|
||||
default y
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#
|
||||
# Makefile for the PowerPC 4xx on-chip ethernet driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IBM_EMAC) += ibm_emac.o
|
||||
|
||||
ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o
|
||||
ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += ibm_emac_zmii.o
|
||||
ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += ibm_emac_rgmii.o
|
||||
ibm_emac-$(CONFIG_IBM_EMAC_TAH) += ibm_emac_tah.o
|
||||
ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += ibm_emac_debug.o
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac.h
|
||||
*
|
||||
* Register definitions for PowerPC 4xx on-chip ethernet contoller
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2002-2004 MontaVista Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __IBM_EMAC_H_
|
||||
#define __IBM_EMAC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* This is a simple check to prevent use of this driver on non-tested SoCs */
|
||||
#if !defined(CONFIG_405GP) && !defined(CONFIG_405GPR) && !defined(CONFIG_405EP) && \
|
||||
!defined(CONFIG_440GP) && !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && \
|
||||
!defined(CONFIG_440EP) && !defined(CONFIG_NP405H) && !defined(CONFIG_440SPE) && \
|
||||
!defined(CONFIG_440GR)
|
||||
#error "Unknown SoC. Please, check chip user manual and make sure EMAC defines are OK"
|
||||
#endif
|
||||
|
||||
/* EMAC registers Write Access rules */
|
||||
struct emac_regs {
|
||||
u32 mr0; /* special */
|
||||
u32 mr1; /* Reset */
|
||||
u32 tmr0; /* special */
|
||||
u32 tmr1; /* special */
|
||||
u32 rmr; /* Reset */
|
||||
u32 isr; /* Always */
|
||||
u32 iser; /* Reset */
|
||||
u32 iahr; /* Reset, R, T */
|
||||
u32 ialr; /* Reset, R, T */
|
||||
u32 vtpid; /* Reset, R, T */
|
||||
u32 vtci; /* Reset, R, T */
|
||||
u32 ptr; /* Reset, T */
|
||||
u32 iaht1; /* Reset, R */
|
||||
u32 iaht2; /* Reset, R */
|
||||
u32 iaht3; /* Reset, R */
|
||||
u32 iaht4; /* Reset, R */
|
||||
u32 gaht1; /* Reset, R */
|
||||
u32 gaht2; /* Reset, R */
|
||||
u32 gaht3; /* Reset, R */
|
||||
u32 gaht4; /* Reset, R */
|
||||
u32 lsah;
|
||||
u32 lsal;
|
||||
u32 ipgvr; /* Reset, T */
|
||||
u32 stacr; /* special */
|
||||
u32 trtr; /* special */
|
||||
u32 rwmr; /* Reset */
|
||||
u32 octx;
|
||||
u32 ocrx;
|
||||
u32 ipcr;
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_ETHTOOL_REGS_VER 0
|
||||
#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32))
|
||||
#else
|
||||
#define EMAC_ETHTOOL_REGS_VER 1
|
||||
#define EMAC_ETHTOOL_REGS_SIZE sizeof(struct emac_regs)
|
||||
#endif
|
||||
|
||||
/* EMACx_MR0 */
|
||||
#define EMAC_MR0_RXI 0x80000000
|
||||
#define EMAC_MR0_TXI 0x40000000
|
||||
#define EMAC_MR0_SRST 0x20000000
|
||||
#define EMAC_MR0_TXE 0x10000000
|
||||
#define EMAC_MR0_RXE 0x08000000
|
||||
#define EMAC_MR0_WKE 0x04000000
|
||||
|
||||
/* EMACx_MR1 */
|
||||
#define EMAC_MR1_FDE 0x80000000
|
||||
#define EMAC_MR1_ILE 0x40000000
|
||||
#define EMAC_MR1_VLE 0x20000000
|
||||
#define EMAC_MR1_EIFC 0x10000000
|
||||
#define EMAC_MR1_APP 0x08000000
|
||||
#define EMAC_MR1_IST 0x01000000
|
||||
|
||||
#define EMAC_MR1_MF_MASK 0x00c00000
|
||||
#define EMAC_MR1_MF_10 0x00000000
|
||||
#define EMAC_MR1_MF_100 0x00400000
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_MR1_MF_1000 0x00000000
|
||||
#define EMAC_MR1_MF_1000GPCS 0x00000000
|
||||
#define EMAC_MR1_MF_IPPA(id) 0x00000000
|
||||
#else
|
||||
#define EMAC_MR1_MF_1000 0x00800000
|
||||
#define EMAC_MR1_MF_1000GPCS 0x00c00000
|
||||
#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6)
|
||||
#endif
|
||||
|
||||
#define EMAC_TX_FIFO_SIZE 2048
|
||||
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_MR1_RFS_4K 0x00300000
|
||||
#define EMAC_MR1_RFS_16K 0x00000000
|
||||
#define EMAC_RX_FIFO_SIZE(gige) 4096
|
||||
#define EMAC_MR1_TFS_2K 0x00080000
|
||||
#define EMAC_MR1_TR0_MULT 0x00008000
|
||||
#define EMAC_MR1_JPSM 0x00000000
|
||||
#define EMAC_MR1_MWSW_001 0x00000000
|
||||
#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
|
||||
#else
|
||||
#define EMAC_MR1_RFS_4K 0x00180000
|
||||
#define EMAC_MR1_RFS_16K 0x00280000
|
||||
#define EMAC_RX_FIFO_SIZE(gige) ((gige) ? 16384 : 4096)
|
||||
#define EMAC_MR1_TFS_2K 0x00020000
|
||||
#define EMAC_MR1_TR 0x00008000
|
||||
#define EMAC_MR1_MWSW_001 0x00001000
|
||||
#define EMAC_MR1_JPSM 0x00000800
|
||||
#define EMAC_MR1_OBCI_MASK 0x00000038
|
||||
#define EMAC_MR1_OBCI_50 0x00000000
|
||||
#define EMAC_MR1_OBCI_66 0x00000008
|
||||
#define EMAC_MR1_OBCI_83 0x00000010
|
||||
#define EMAC_MR1_OBCI_100 0x00000018
|
||||
#define EMAC_MR1_OBCI_100P 0x00000020
|
||||
#define EMAC_MR1_OBCI(freq) ((freq) <= 50 ? EMAC_MR1_OBCI_50 : \
|
||||
(freq) <= 66 ? EMAC_MR1_OBCI_66 : \
|
||||
(freq) <= 83 ? EMAC_MR1_OBCI_83 : \
|
||||
(freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P)
|
||||
#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \
|
||||
EMAC_MR1_OBCI(opb))
|
||||
#endif
|
||||
|
||||
/* EMACx_TMR0 */
|
||||
#define EMAC_TMR0_GNP 0x80000000
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_TMR0_DEFAULT 0x00000000
|
||||
#else
|
||||
#define EMAC_TMR0_TFAE_2_32 0x00000001
|
||||
#define EMAC_TMR0_TFAE_4_64 0x00000002
|
||||
#define EMAC_TMR0_TFAE_8_128 0x00000003
|
||||
#define EMAC_TMR0_TFAE_16_256 0x00000004
|
||||
#define EMAC_TMR0_TFAE_32_512 0x00000005
|
||||
#define EMAC_TMR0_TFAE_64_1024 0x00000006
|
||||
#define EMAC_TMR0_TFAE_128_2048 0x00000007
|
||||
#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32
|
||||
#endif
|
||||
#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT)
|
||||
|
||||
/* EMACx_TMR1 */
|
||||
|
||||
/* IBM manuals are not very clear here.
|
||||
* This is my interpretation of how things are. --ebs
|
||||
*/
|
||||
#if defined(CONFIG_40x)
|
||||
#define EMAC_FIFO_ENTRY_SIZE 8
|
||||
#define EMAC_MAL_BURST_SIZE (16 * 4)
|
||||
#else
|
||||
#define EMAC_FIFO_ENTRY_SIZE 16
|
||||
#define EMAC_MAL_BURST_SIZE (64 * 4)
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16))
|
||||
#else
|
||||
#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14))
|
||||
#endif
|
||||
|
||||
/* EMACx_RMR */
|
||||
#define EMAC_RMR_SP 0x80000000
|
||||
#define EMAC_RMR_SFCS 0x40000000
|
||||
#define EMAC_RMR_RRP 0x20000000
|
||||
#define EMAC_RMR_RFP 0x10000000
|
||||
#define EMAC_RMR_ROP 0x08000000
|
||||
#define EMAC_RMR_RPIR 0x04000000
|
||||
#define EMAC_RMR_PPP 0x02000000
|
||||
#define EMAC_RMR_PME 0x01000000
|
||||
#define EMAC_RMR_PMME 0x00800000
|
||||
#define EMAC_RMR_IAE 0x00400000
|
||||
#define EMAC_RMR_MIAE 0x00200000
|
||||
#define EMAC_RMR_BAE 0x00100000
|
||||
#define EMAC_RMR_MAE 0x00080000
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_RMR_BASE 0x00000000
|
||||
#else
|
||||
#define EMAC_RMR_RFAF_2_32 0x00000001
|
||||
#define EMAC_RMR_RFAF_4_64 0x00000002
|
||||
#define EMAC_RMR_RFAF_8_128 0x00000003
|
||||
#define EMAC_RMR_RFAF_16_256 0x00000004
|
||||
#define EMAC_RMR_RFAF_32_512 0x00000005
|
||||
#define EMAC_RMR_RFAF_64_1024 0x00000006
|
||||
#define EMAC_RMR_RFAF_128_2048 0x00000007
|
||||
#define EMAC_RMR_BASE EMAC_RMR_RFAF_128_2048
|
||||
#endif
|
||||
|
||||
/* EMACx_ISR & EMACx_ISER */
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_ISR_TXPE 0x00000000
|
||||
#define EMAC_ISR_RXPE 0x00000000
|
||||
#define EMAC_ISR_TXUE 0x00000000
|
||||
#define EMAC_ISR_RXOE 0x00000000
|
||||
#else
|
||||
#define EMAC_ISR_TXPE 0x20000000
|
||||
#define EMAC_ISR_RXPE 0x10000000
|
||||
#define EMAC_ISR_TXUE 0x08000000
|
||||
#define EMAC_ISR_RXOE 0x04000000
|
||||
#endif
|
||||
#define EMAC_ISR_OVR 0x02000000
|
||||
#define EMAC_ISR_PP 0x01000000
|
||||
#define EMAC_ISR_BP 0x00800000
|
||||
#define EMAC_ISR_RP 0x00400000
|
||||
#define EMAC_ISR_SE 0x00200000
|
||||
#define EMAC_ISR_ALE 0x00100000
|
||||
#define EMAC_ISR_BFCS 0x00080000
|
||||
#define EMAC_ISR_PTLE 0x00040000
|
||||
#define EMAC_ISR_ORE 0x00020000
|
||||
#define EMAC_ISR_IRE 0x00010000
|
||||
#define EMAC_ISR_SQE 0x00000080
|
||||
#define EMAC_ISR_TE 0x00000040
|
||||
#define EMAC_ISR_MOS 0x00000002
|
||||
#define EMAC_ISR_MOF 0x00000001
|
||||
|
||||
/* EMACx_STACR */
|
||||
#define EMAC_STACR_PHYD_MASK 0xffff
|
||||
#define EMAC_STACR_PHYD_SHIFT 16
|
||||
#define EMAC_STACR_OC 0x00008000
|
||||
#define EMAC_STACR_PHYE 0x00004000
|
||||
#define EMAC_STACR_STAC_MASK 0x00003000
|
||||
#define EMAC_STACR_STAC_READ 0x00001000
|
||||
#define EMAC_STACR_STAC_WRITE 0x00002000
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_STACR_OPBC_MASK 0x00000C00
|
||||
#define EMAC_STACR_OPBC_50 0x00000000
|
||||
#define EMAC_STACR_OPBC_66 0x00000400
|
||||
#define EMAC_STACR_OPBC_83 0x00000800
|
||||
#define EMAC_STACR_OPBC_100 0x00000C00
|
||||
#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \
|
||||
(freq) <= 66 ? EMAC_STACR_OPBC_66 : \
|
||||
(freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100)
|
||||
#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb)
|
||||
#else
|
||||
#define EMAC_STACR_BASE(opb) 0x00000000
|
||||
#endif
|
||||
#define EMAC_STACR_PCDA_MASK 0x1f
|
||||
#define EMAC_STACR_PCDA_SHIFT 5
|
||||
#define EMAC_STACR_PRA_MASK 0x1f
|
||||
|
||||
/*
|
||||
* For the 440SPe, AMCC inexplicably changed the polarity of
|
||||
* the "operation complete" bit in the MII control register.
|
||||
*/
|
||||
#if defined(CONFIG_440SPE)
|
||||
static inline int emac_phy_done(u32 stacr)
|
||||
{
|
||||
return !(stacr & EMAC_STACR_OC);
|
||||
};
|
||||
#define EMAC_STACR_START EMAC_STACR_OC
|
||||
|
||||
#else /* CONFIG_440SPE */
|
||||
static inline int emac_phy_done(u32 stacr)
|
||||
{
|
||||
return stacr & EMAC_STACR_OC;
|
||||
};
|
||||
#define EMAC_STACR_START 0
|
||||
#endif /* !CONFIG_440SPE */
|
||||
|
||||
/* EMACx_TRTR */
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_TRTR_SHIFT 27
|
||||
#else
|
||||
#define EMAC_TRTR_SHIFT 24
|
||||
#endif
|
||||
#define EMAC_TRTR(size) ((((size) >> 6) - 1) << EMAC_TRTR_SHIFT)
|
||||
|
||||
/* EMACx_RWMR */
|
||||
#if !defined(CONFIG_IBM_EMAC4)
|
||||
#define EMAC_RWMR(l,h) (((l) << 23) | ( ((h) & 0x1ff) << 7))
|
||||
#else
|
||||
#define EMAC_RWMR(l,h) (((l) << 22) | ( ((h) & 0x3ff) << 6))
|
||||
#endif
|
||||
|
||||
/* EMAC specific TX descriptor control fields (write access) */
|
||||
#define EMAC_TX_CTRL_GFCS 0x0200
|
||||
#define EMAC_TX_CTRL_GP 0x0100
|
||||
#define EMAC_TX_CTRL_ISA 0x0080
|
||||
#define EMAC_TX_CTRL_RSA 0x0040
|
||||
#define EMAC_TX_CTRL_IVT 0x0020
|
||||
#define EMAC_TX_CTRL_RVT 0x0010
|
||||
#define EMAC_TX_CTRL_TAH_CSUM 0x000e
|
||||
|
||||
/* EMAC specific TX descriptor status fields (read access) */
|
||||
#define EMAC_TX_ST_BFCS 0x0200
|
||||
#define EMAC_TX_ST_LCS 0x0080
|
||||
#define EMAC_TX_ST_ED 0x0040
|
||||
#define EMAC_TX_ST_EC 0x0020
|
||||
#define EMAC_TX_ST_LC 0x0010
|
||||
#define EMAC_TX_ST_MC 0x0008
|
||||
#define EMAC_TX_ST_SC 0x0004
|
||||
#define EMAC_TX_ST_UR 0x0002
|
||||
#define EMAC_TX_ST_SQE 0x0001
|
||||
#if !defined(CONFIG_IBM_EMAC_TAH)
|
||||
#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
|
||||
EMAC_TX_ST_EC | EMAC_TX_ST_LC | \
|
||||
EMAC_TX_ST_MC | EMAC_TX_ST_UR))
|
||||
#else
|
||||
#define EMAC_IS_BAD_TX(v) ((v) & (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
|
||||
EMAC_TX_ST_EC | EMAC_TX_ST_LC))
|
||||
#endif
|
||||
|
||||
/* EMAC specific RX descriptor status fields (read access) */
|
||||
#define EMAC_RX_ST_OE 0x0200
|
||||
#define EMAC_RX_ST_PP 0x0100
|
||||
#define EMAC_RX_ST_BP 0x0080
|
||||
#define EMAC_RX_ST_RP 0x0040
|
||||
#define EMAC_RX_ST_SE 0x0020
|
||||
#define EMAC_RX_ST_AE 0x0010
|
||||
#define EMAC_RX_ST_BFCS 0x0008
|
||||
#define EMAC_RX_ST_PTL 0x0004
|
||||
#define EMAC_RX_ST_ORE 0x0002
|
||||
#define EMAC_RX_ST_IRE 0x0001
|
||||
#define EMAC_RX_TAH_BAD_CSUM 0x0003
|
||||
#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \
|
||||
EMAC_RX_ST_RP | EMAC_RX_ST_SE | \
|
||||
EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \
|
||||
EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \
|
||||
EMAC_RX_ST_IRE )
|
||||
#endif /* __IBM_EMAC_H_ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,222 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_core.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Johnnie Peters <jpeters@mvista.com>
|
||||
* Copyright 2000, 2001 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __IBM_EMAC_CORE_H_
|
||||
#define __IBM_EMAC_CORE_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
#include "ibm_emac.h"
|
||||
#include "ibm_emac_phy.h"
|
||||
#include "ibm_emac_zmii.h"
|
||||
#include "ibm_emac_rgmii.h"
|
||||
#include "ibm_emac_mal.h"
|
||||
#include "ibm_emac_tah.h"
|
||||
|
||||
#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB
|
||||
#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB
|
||||
|
||||
/* Simple sanity check */
|
||||
#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
|
||||
#error Invalid number of buffer descriptors (greater than 256)
|
||||
#endif
|
||||
|
||||
// XXX
|
||||
#define EMAC_MIN_MTU 46
|
||||
#define EMAC_MAX_MTU 9000
|
||||
|
||||
/* Maximum L2 header length (VLAN tagged, no FCS) */
|
||||
#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4)
|
||||
|
||||
/* RX BD size for the given MTU */
|
||||
static inline int emac_rx_size(int mtu)
|
||||
{
|
||||
if (mtu > ETH_DATA_LEN)
|
||||
return MAL_MAX_RX_SIZE;
|
||||
else
|
||||
return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD);
|
||||
}
|
||||
|
||||
#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment())
|
||||
|
||||
#define EMAC_RX_SKB_HEADROOM \
|
||||
EMAC_DMA_ALIGN(CONFIG_IBM_EMAC_RX_SKB_HEADROOM)
|
||||
|
||||
/* Size of RX skb for the given MTU */
|
||||
static inline int emac_rx_skb_size(int mtu)
|
||||
{
|
||||
int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
|
||||
return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM;
|
||||
}
|
||||
|
||||
/* RX DMA sync size */
|
||||
static inline int emac_rx_sync_size(int mtu)
|
||||
{
|
||||
return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2);
|
||||
}
|
||||
|
||||
/* Driver statistcs is split into two parts to make it more cache friendly:
|
||||
* - normal statistics (packet count, etc)
|
||||
* - error statistics
|
||||
*
|
||||
* When statistics is requested by ethtool, these parts are concatenated,
|
||||
* normal one goes first.
|
||||
*
|
||||
* Please, keep these structures in sync with emac_stats_keys.
|
||||
*/
|
||||
|
||||
/* Normal TX/RX Statistics */
|
||||
struct ibm_emac_stats {
|
||||
u64 rx_packets;
|
||||
u64 rx_bytes;
|
||||
u64 tx_packets;
|
||||
u64 tx_bytes;
|
||||
u64 rx_packets_csum;
|
||||
u64 tx_packets_csum;
|
||||
};
|
||||
|
||||
/* Error statistics */
|
||||
struct ibm_emac_error_stats {
|
||||
u64 tx_undo;
|
||||
|
||||
/* Software RX Errors */
|
||||
u64 rx_dropped_stack;
|
||||
u64 rx_dropped_oom;
|
||||
u64 rx_dropped_error;
|
||||
u64 rx_dropped_resize;
|
||||
u64 rx_dropped_mtu;
|
||||
u64 rx_stopped;
|
||||
/* BD reported RX errors */
|
||||
u64 rx_bd_errors;
|
||||
u64 rx_bd_overrun;
|
||||
u64 rx_bd_bad_packet;
|
||||
u64 rx_bd_runt_packet;
|
||||
u64 rx_bd_short_event;
|
||||
u64 rx_bd_alignment_error;
|
||||
u64 rx_bd_bad_fcs;
|
||||
u64 rx_bd_packet_too_long;
|
||||
u64 rx_bd_out_of_range;
|
||||
u64 rx_bd_in_range;
|
||||
/* EMAC IRQ reported RX errors */
|
||||
u64 rx_parity;
|
||||
u64 rx_fifo_overrun;
|
||||
u64 rx_overrun;
|
||||
u64 rx_bad_packet;
|
||||
u64 rx_runt_packet;
|
||||
u64 rx_short_event;
|
||||
u64 rx_alignment_error;
|
||||
u64 rx_bad_fcs;
|
||||
u64 rx_packet_too_long;
|
||||
u64 rx_out_of_range;
|
||||
u64 rx_in_range;
|
||||
|
||||
/* Software TX Errors */
|
||||
u64 tx_dropped;
|
||||
/* BD reported TX errors */
|
||||
u64 tx_bd_errors;
|
||||
u64 tx_bd_bad_fcs;
|
||||
u64 tx_bd_carrier_loss;
|
||||
u64 tx_bd_excessive_deferral;
|
||||
u64 tx_bd_excessive_collisions;
|
||||
u64 tx_bd_late_collision;
|
||||
u64 tx_bd_multple_collisions;
|
||||
u64 tx_bd_single_collision;
|
||||
u64 tx_bd_underrun;
|
||||
u64 tx_bd_sqe;
|
||||
/* EMAC IRQ reported TX errors */
|
||||
u64 tx_parity;
|
||||
u64 tx_underrun;
|
||||
u64 tx_sqe;
|
||||
u64 tx_errors;
|
||||
};
|
||||
|
||||
#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct ibm_emac_stats) + \
|
||||
sizeof(struct ibm_emac_error_stats)) \
|
||||
/ sizeof(u64))
|
||||
|
||||
struct ocp_enet_private {
|
||||
struct net_device *ndev; /* 0 */
|
||||
struct emac_regs __iomem *emacp;
|
||||
|
||||
struct mal_descriptor *tx_desc;
|
||||
int tx_cnt;
|
||||
int tx_slot;
|
||||
int ack_slot;
|
||||
|
||||
struct mal_descriptor *rx_desc;
|
||||
int rx_slot;
|
||||
struct sk_buff *rx_sg_skb; /* 1 */
|
||||
int rx_skb_size;
|
||||
int rx_sync_size;
|
||||
|
||||
struct ibm_emac_stats stats;
|
||||
struct ocp_device *tah_dev;
|
||||
|
||||
struct ibm_ocp_mal *mal;
|
||||
struct mal_commac commac;
|
||||
|
||||
struct sk_buff *tx_skb[NUM_TX_BUFF];
|
||||
struct sk_buff *rx_skb[NUM_RX_BUFF];
|
||||
|
||||
struct ocp_device *zmii_dev;
|
||||
int zmii_input;
|
||||
struct ocp_enet_private *mdio_dev;
|
||||
struct ocp_device *rgmii_dev;
|
||||
int rgmii_input;
|
||||
|
||||
struct ocp_def *def;
|
||||
|
||||
struct mii_phy phy;
|
||||
struct timer_list link_timer;
|
||||
int reset_failed;
|
||||
|
||||
int stop_timeout; /* in us */
|
||||
|
||||
struct ibm_emac_error_stats estats;
|
||||
struct net_device_stats nstats;
|
||||
|
||||
struct device* ldev;
|
||||
};
|
||||
|
||||
/* Ethtool get_regs complex data.
|
||||
* We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
|
||||
* when available.
|
||||
*
|
||||
* Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
|
||||
* MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
|
||||
* Each register component is preceded with emac_ethtool_regs_subhdr.
|
||||
* Order of the optional headers follows their relative bit posititions
|
||||
* in emac_ethtool_regs_hdr.components
|
||||
*/
|
||||
#define EMAC_ETHTOOL_REGS_ZMII 0x00000001
|
||||
#define EMAC_ETHTOOL_REGS_RGMII 0x00000002
|
||||
#define EMAC_ETHTOOL_REGS_TAH 0x00000004
|
||||
|
||||
struct emac_ethtool_regs_hdr {
|
||||
u32 components;
|
||||
};
|
||||
|
||||
struct emac_ethtool_regs_subhdr {
|
||||
u32 version;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
#endif /* __IBM_EMAC_CORE_H_ */
|
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_debug.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
|
||||
static void emac_desc_dump(int idx, struct ocp_enet_private *p)
|
||||
{
|
||||
int i;
|
||||
printk("** EMAC%d TX BDs **\n"
|
||||
" tx_cnt = %d tx_slot = %d ack_slot = %d\n",
|
||||
idx, p->tx_cnt, p->tx_slot, p->ack_slot);
|
||||
for (i = 0; i < NUM_TX_BUFF / 2; ++i)
|
||||
printk
|
||||
("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
|
||||
i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ',
|
||||
p->tx_desc[i].ctrl, p->tx_desc[i].data_len,
|
||||
NUM_TX_BUFF / 2 + i,
|
||||
p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr,
|
||||
p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ',
|
||||
p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl,
|
||||
p->tx_desc[NUM_TX_BUFF / 2 + i].data_len);
|
||||
|
||||
printk("** EMAC%d RX BDs **\n"
|
||||
" rx_slot = %d rx_stopped = %d rx_skb_size = %d rx_sync_size = %d\n"
|
||||
" rx_sg_skb = 0x%p\n",
|
||||
idx, p->rx_slot, p->commac.rx_stopped, p->rx_skb_size,
|
||||
p->rx_sync_size, p->rx_sg_skb);
|
||||
for (i = 0; i < NUM_RX_BUFF / 2; ++i)
|
||||
printk
|
||||
("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
|
||||
i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ',
|
||||
p->rx_desc[i].ctrl, p->rx_desc[i].data_len,
|
||||
NUM_RX_BUFF / 2 + i,
|
||||
p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr,
|
||||
p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ',
|
||||
p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl,
|
||||
p->rx_desc[NUM_RX_BUFF / 2 + i].data_len);
|
||||
}
|
||||
|
||||
static void emac_mac_dump(int idx, struct ocp_enet_private *dev)
|
||||
{
|
||||
struct emac_regs __iomem *p = dev->emacp;
|
||||
|
||||
printk("** EMAC%d registers **\n"
|
||||
"MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
|
||||
"RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
|
||||
"IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
|
||||
"IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
|
||||
"GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
|
||||
"LSA = %04x%08x IPGVR = 0x%04x\n"
|
||||
"STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
|
||||
"OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
|
||||
idx, in_be32(&p->mr0), in_be32(&p->mr1),
|
||||
in_be32(&p->tmr0), in_be32(&p->tmr1),
|
||||
in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
|
||||
in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
|
||||
in_be32(&p->vtci),
|
||||
in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
|
||||
in_be32(&p->iaht4),
|
||||
in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
|
||||
in_be32(&p->gaht4),
|
||||
in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
|
||||
in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
|
||||
in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
|
||||
);
|
||||
|
||||
emac_desc_dump(idx, dev);
|
||||
}
|
||||
|
||||
static void emac_mal_dump(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
int i;
|
||||
|
||||
printk("** MAL%d Registers **\n"
|
||||
"CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
|
||||
"TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
|
||||
"RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
|
||||
mal->def->index,
|
||||
get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
|
||||
get_mal_dcrn(mal, MAL_IER),
|
||||
get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
|
||||
get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR),
|
||||
get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR),
|
||||
get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR)
|
||||
);
|
||||
|
||||
printk("TX|");
|
||||
for (i = 0; i < maldata->num_tx_chans; ++i) {
|
||||
if (i && !(i % 4))
|
||||
printk("\n ");
|
||||
printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i)));
|
||||
}
|
||||
printk("\nRX|");
|
||||
for (i = 0; i < maldata->num_rx_chans; ++i) {
|
||||
if (i && !(i % 4))
|
||||
printk("\n ");
|
||||
printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i)));
|
||||
}
|
||||
printk("\n ");
|
||||
for (i = 0; i < maldata->num_rx_chans; ++i) {
|
||||
u32 r = get_mal_dcrn(mal, MAL_RCBS(i));
|
||||
if (i && !(i % 3))
|
||||
printk("\n ");
|
||||
printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static struct ocp_enet_private *__emacs[4];
|
||||
static struct ibm_ocp_mal *__mals[1];
|
||||
|
||||
void emac_dbg_register(int idx, struct ocp_enet_private *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (idx >= ARRAY_SIZE(__emacs)) {
|
||||
printk(KERN_WARNING
|
||||
"invalid index %d when registering EMAC for debugging\n",
|
||||
idx);
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
__emacs[idx] = dev;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void mal_dbg_register(int idx, struct ibm_ocp_mal *mal)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (idx >= ARRAY_SIZE(__mals)) {
|
||||
printk(KERN_WARNING
|
||||
"invalid index %d when registering MAL for debugging\n",
|
||||
idx);
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
__mals[idx] = mal;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void emac_dbg_dump_all(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(__mals); ++i)
|
||||
if (__mals[i])
|
||||
emac_mal_dump(__mals[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
|
||||
if (__emacs[i])
|
||||
emac_mac_dump(i, __emacs[i]);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MAGIC_SYSRQ)
|
||||
static void emac_sysrq_handler(int key, struct tty_struct *tty)
|
||||
{
|
||||
emac_dbg_dump_all();
|
||||
}
|
||||
|
||||
static struct sysrq_key_op emac_sysrq_op = {
|
||||
.handler = emac_sysrq_handler,
|
||||
.help_msg = "emaC",
|
||||
.action_msg = "Show EMAC(s) status",
|
||||
};
|
||||
|
||||
int __init emac_init_debug(void)
|
||||
{
|
||||
return register_sysrq_key('c', &emac_sysrq_op);
|
||||
}
|
||||
|
||||
void __exit emac_fini_debug(void)
|
||||
{
|
||||
unregister_sysrq_key('c', &emac_sysrq_op);
|
||||
}
|
||||
|
||||
#else
|
||||
int __init emac_init_debug(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void __exit emac_fini_debug(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_debug.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __IBM_EMAC_DEBUG_H_
|
||||
#define __IBM_EMAC_DEBUG_H_
|
||||
|
||||
#include <linux/init.h>
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_mal.h"
|
||||
|
||||
#if defined(CONFIG_IBM_EMAC_DEBUG)
|
||||
void emac_dbg_register(int idx, struct ocp_enet_private *dev);
|
||||
void mal_dbg_register(int idx, struct ibm_ocp_mal *mal);
|
||||
int emac_init_debug(void) __init;
|
||||
void emac_fini_debug(void) __exit;
|
||||
void emac_dbg_dump_all(void);
|
||||
# define DBG_LEVEL 1
|
||||
#else
|
||||
# define emac_dbg_register(x,y) ((void)0)
|
||||
# define mal_dbg_register(x,y) ((void)0)
|
||||
# define emac_init_debug() ((void)0)
|
||||
# define emac_fini_debug() ((void)0)
|
||||
# define emac_dbg_dump_all() ((void)0)
|
||||
# define DBG_LEVEL 0
|
||||
#endif
|
||||
|
||||
#if DBG_LEVEL > 0
|
||||
# define DBG(f,x...) printk("emac" f, ##x)
|
||||
# define MAL_DBG(f,x...) printk("mal" f, ##x)
|
||||
# define ZMII_DBG(f,x...) printk("zmii" f, ##x)
|
||||
# define RGMII_DBG(f,x...) printk("rgmii" f, ##x)
|
||||
# define NL "\n"
|
||||
#else
|
||||
# define DBG(f,x...) ((void)0)
|
||||
# define MAL_DBG(f,x...) ((void)0)
|
||||
# define ZMII_DBG(f,x...) ((void)0)
|
||||
# define RGMII_DBG(f,x...) ((void)0)
|
||||
#endif
|
||||
#if DBG_LEVEL > 1
|
||||
# define DBG2(f,x...) DBG(f, ##x)
|
||||
# define MAL_DBG2(f,x...) MAL_DBG(f, ##x)
|
||||
# define ZMII_DBG2(f,x...) ZMII_DBG(f, ##x)
|
||||
# define RGMII_DBG2(f,x...) RGMII_DBG(f, ##x)
|
||||
#else
|
||||
# define DBG2(f,x...) ((void)0)
|
||||
# define MAL_DBG2(f,x...) ((void)0)
|
||||
# define ZMII_DBG2(f,x...) ((void)0)
|
||||
# define RGMII_DBG2(f,x...) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif /* __IBM_EMAC_DEBUG_H_ */
|
|
@ -1,570 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_mal.c
|
||||
*
|
||||
* Memory Access Layer (MAL) support
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Benjamin Herrenschmidt <benh@kernel.crashing.org>,
|
||||
* David Gibson <hermes@gibson.dropbear.id.au>,
|
||||
*
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/ocp.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_mal.h"
|
||||
#include "ibm_emac_debug.h"
|
||||
|
||||
int __init mal_register_commac(struct ibm_ocp_mal *mal,
|
||||
struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
MAL_DBG("%d: reg(%08x, %08x)" NL, mal->def->index,
|
||||
commac->tx_chan_mask, commac->rx_chan_mask);
|
||||
|
||||
/* Don't let multiple commacs claim the same channel(s) */
|
||||
if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
|
||||
(mal->rx_chan_mask & commac->rx_chan_mask)) {
|
||||
local_irq_restore(flags);
|
||||
printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
|
||||
mal->def->index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mal->tx_chan_mask |= commac->tx_chan_mask;
|
||||
mal->rx_chan_mask |= commac->rx_chan_mask;
|
||||
list_add(&commac->list, &mal->list);
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
MAL_DBG("%d: unreg(%08x, %08x)" NL, mal->def->index,
|
||||
commac->tx_chan_mask, commac->rx_chan_mask);
|
||||
|
||||
mal->tx_chan_mask &= ~commac->tx_chan_mask;
|
||||
mal->rx_chan_mask &= ~commac->rx_chan_mask;
|
||||
list_del_init(&commac->list);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size)
|
||||
{
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
BUG_ON(channel < 0 || channel >= maldata->num_rx_chans ||
|
||||
size > MAL_MAX_RX_SIZE);
|
||||
|
||||
MAL_DBG("%d: set_rbcs(%d, %lu)" NL, mal->def->index, channel, size);
|
||||
|
||||
if (size & 0xf) {
|
||||
printk(KERN_WARNING
|
||||
"mal%d: incorrect RX size %lu for the channel %d\n",
|
||||
mal->def->index, size, channel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
BUG_ON(channel < 0 || channel >= maldata->num_tx_chans);
|
||||
return channel * NUM_TX_BUFF;
|
||||
}
|
||||
|
||||
int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
BUG_ON(channel < 0 || channel >= maldata->num_rx_chans);
|
||||
return maldata->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF;
|
||||
}
|
||||
|
||||
void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
local_bh_disable();
|
||||
MAL_DBG("%d: enable_tx(%d)" NL, mal->def->index, channel);
|
||||
set_mal_dcrn(mal, MAL_TXCASR,
|
||||
get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel));
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel));
|
||||
MAL_DBG("%d: disable_tx(%d)" NL, mal->def->index, channel);
|
||||
}
|
||||
|
||||
void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
local_bh_disable();
|
||||
MAL_DBG("%d: enable_rx(%d)" NL, mal->def->index, channel);
|
||||
set_mal_dcrn(mal, MAL_RXCASR,
|
||||
get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel));
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel)
|
||||
{
|
||||
set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
|
||||
MAL_DBG("%d: disable_rx(%d)" NL, mal->def->index, channel);
|
||||
}
|
||||
|
||||
void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac)
|
||||
{
|
||||
local_bh_disable();
|
||||
MAL_DBG("%d: poll_add(%p)" NL, mal->def->index, commac);
|
||||
list_add_tail(&commac->poll_list, &mal->poll_list);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac)
|
||||
{
|
||||
local_bh_disable();
|
||||
MAL_DBG("%d: poll_del(%p)" NL, mal->def->index, commac);
|
||||
list_del(&commac->poll_list);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
/* synchronized by mal_poll() */
|
||||
static inline void mal_enable_eob_irq(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
MAL_DBG2("%d: enable_irq" NL, mal->def->index);
|
||||
set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE);
|
||||
}
|
||||
|
||||
/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */
|
||||
static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE);
|
||||
MAL_DBG2("%d: disable_irq" NL, mal->def->index);
|
||||
}
|
||||
|
||||
static irqreturn_t mal_serr(int irq, void *dev_instance)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
u32 esr = get_mal_dcrn(mal, MAL_ESR);
|
||||
|
||||
/* Clear the error status register */
|
||||
set_mal_dcrn(mal, MAL_ESR, esr);
|
||||
|
||||
MAL_DBG("%d: SERR %08x" NL, mal->def->index, esr);
|
||||
|
||||
if (esr & MAL_ESR_EVB) {
|
||||
if (esr & MAL_ESR_DE) {
|
||||
/* We ignore Descriptor error,
|
||||
* TXDE or RXDE interrupt will be generated anyway.
|
||||
*/
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (esr & MAL_ESR_PEIN) {
|
||||
/* PLB error, it's probably buggy hardware or
|
||||
* incorrect physical address in BD (i.e. bug)
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR
|
||||
"mal%d: system error, PLB (ESR = 0x%08x)\n",
|
||||
mal->def->index, esr);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* OPB error, it's probably buggy hardware or incorrect EBC setup */
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR
|
||||
"mal%d: system error, OPB (ESR = 0x%08x)\n",
|
||||
mal->def->index, esr);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline void mal_schedule_poll(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
if (likely(napi_schedule_prep(&mal->napi))) {
|
||||
MAL_DBG2("%d: schedule_poll" NL, mal->def->index);
|
||||
mal_disable_eob_irq(mal);
|
||||
__napi_schedule(&mal->napi);
|
||||
} else
|
||||
MAL_DBG2("%d: already in poll" NL, mal->def->index);
|
||||
}
|
||||
|
||||
static irqreturn_t mal_txeob(int irq, void *dev_instance)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
|
||||
MAL_DBG2("%d: txeob %08x" NL, mal->def->index, r);
|
||||
mal_schedule_poll(mal);
|
||||
set_mal_dcrn(mal, MAL_TXEOBISR, r);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mal_rxeob(int irq, void *dev_instance)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
|
||||
MAL_DBG2("%d: rxeob %08x" NL, mal->def->index, r);
|
||||
mal_schedule_poll(mal);
|
||||
set_mal_dcrn(mal, MAL_RXEOBISR, r);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mal_txde(int irq, void *dev_instance)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
|
||||
set_mal_dcrn(mal, MAL_TXDEIR, deir);
|
||||
|
||||
MAL_DBG("%d: txde %08x" NL, mal->def->index, deir);
|
||||
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR
|
||||
"mal%d: TX descriptor error (TXDEIR = 0x%08x)\n",
|
||||
mal->def->index, deir);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mal_rxde(int irq, void *dev_instance)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = dev_instance;
|
||||
struct list_head *l;
|
||||
u32 deir = get_mal_dcrn(mal, MAL_RXDEIR);
|
||||
|
||||
MAL_DBG("%d: rxde %08x" NL, mal->def->index, deir);
|
||||
|
||||
list_for_each(l, &mal->list) {
|
||||
struct mal_commac *mc = list_entry(l, struct mal_commac, list);
|
||||
if (deir & mc->rx_chan_mask) {
|
||||
mc->rx_stopped = 1;
|
||||
mc->ops->rxde(mc->dev);
|
||||
}
|
||||
}
|
||||
|
||||
mal_schedule_poll(mal);
|
||||
set_mal_dcrn(mal, MAL_RXDEIR, deir);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mal_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi);
|
||||
struct list_head *l;
|
||||
int received = 0;
|
||||
|
||||
MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget,
|
||||
rx_work_limit);
|
||||
again:
|
||||
/* Process TX skbs */
|
||||
list_for_each(l, &mal->poll_list) {
|
||||
struct mal_commac *mc =
|
||||
list_entry(l, struct mal_commac, poll_list);
|
||||
mc->ops->poll_tx(mc->dev);
|
||||
}
|
||||
|
||||
/* Process RX skbs.
|
||||
* We _might_ need something more smart here to enforce polling fairness.
|
||||
*/
|
||||
list_for_each(l, &mal->poll_list) {
|
||||
struct mal_commac *mc =
|
||||
list_entry(l, struct mal_commac, poll_list);
|
||||
int n = mc->ops->poll_rx(mc->dev, budget);
|
||||
if (n) {
|
||||
received += n;
|
||||
budget -= n;
|
||||
if (budget <= 0)
|
||||
goto more_work; // XXX What if this is the last one ?
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to disable IRQs to protect from RXDE IRQ here */
|
||||
local_irq_disable();
|
||||
__napi_complete(napi);
|
||||
mal_enable_eob_irq(mal);
|
||||
local_irq_enable();
|
||||
|
||||
/* Check for "rotting" packet(s) */
|
||||
list_for_each(l, &mal->poll_list) {
|
||||
struct mal_commac *mc =
|
||||
list_entry(l, struct mal_commac, poll_list);
|
||||
if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) {
|
||||
MAL_DBG2("%d: rotting packet" NL, mal->def->index);
|
||||
if (napi_reschedule(napi))
|
||||
mal_disable_eob_irq(mal);
|
||||
else
|
||||
MAL_DBG2("%d: already in poll list" NL,
|
||||
mal->def->index);
|
||||
|
||||
if (budget > 0)
|
||||
goto again;
|
||||
else
|
||||
goto more_work;
|
||||
}
|
||||
mc->ops->poll_tx(mc->dev);
|
||||
}
|
||||
|
||||
more_work:
|
||||
MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received);
|
||||
return received;
|
||||
}
|
||||
|
||||
static void mal_reset(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
int n = 10;
|
||||
MAL_DBG("%d: reset" NL, mal->def->index);
|
||||
|
||||
set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);
|
||||
|
||||
/* Wait for reset to complete (1 system clock) */
|
||||
while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)
|
||||
--n;
|
||||
|
||||
if (unlikely(!n))
|
||||
printk(KERN_ERR "mal%d: reset timeout\n", mal->def->index);
|
||||
}
|
||||
|
||||
int mal_get_regs_len(struct ibm_ocp_mal *mal)
|
||||
{
|
||||
return sizeof(struct emac_ethtool_regs_subhdr) +
|
||||
sizeof(struct ibm_mal_regs);
|
||||
}
|
||||
|
||||
void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf)
|
||||
{
|
||||
struct emac_ethtool_regs_subhdr *hdr = buf;
|
||||
struct ibm_mal_regs *regs = (struct ibm_mal_regs *)(hdr + 1);
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
int i;
|
||||
|
||||
hdr->version = MAL_VERSION;
|
||||
hdr->index = mal->def->index;
|
||||
|
||||
regs->tx_count = maldata->num_tx_chans;
|
||||
regs->rx_count = maldata->num_rx_chans;
|
||||
|
||||
regs->cfg = get_mal_dcrn(mal, MAL_CFG);
|
||||
regs->esr = get_mal_dcrn(mal, MAL_ESR);
|
||||
regs->ier = get_mal_dcrn(mal, MAL_IER);
|
||||
regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR);
|
||||
regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR);
|
||||
regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR);
|
||||
regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR);
|
||||
regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR);
|
||||
regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR);
|
||||
regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR);
|
||||
regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR);
|
||||
|
||||
for (i = 0; i < regs->tx_count; ++i)
|
||||
regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i));
|
||||
|
||||
for (i = 0; i < regs->rx_count; ++i) {
|
||||
regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i));
|
||||
regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i));
|
||||
}
|
||||
return regs + 1;
|
||||
}
|
||||
|
||||
static int __init mal_probe(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct ibm_ocp_mal *mal;
|
||||
struct ocp_func_mal_data *maldata;
|
||||
int err = 0, i, bd_size;
|
||||
|
||||
MAL_DBG("%d: probe" NL, ocpdev->def->index);
|
||||
|
||||
maldata = ocpdev->def->additions;
|
||||
if (maldata == NULL) {
|
||||
printk(KERN_ERR "mal%d: missing additional data!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mal = kzalloc(sizeof(struct ibm_ocp_mal), GFP_KERNEL);
|
||||
if (!mal) {
|
||||
printk(KERN_ERR
|
||||
"mal%d: out of memory allocating MAL structure!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* XXX This only works for native dcr for now */
|
||||
mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0);
|
||||
|
||||
mal->def = ocpdev->def;
|
||||
|
||||
INIT_LIST_HEAD(&mal->poll_list);
|
||||
mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
|
||||
mal->napi.poll = mal_poll;
|
||||
|
||||
INIT_LIST_HEAD(&mal->list);
|
||||
|
||||
/* Load power-on reset defaults */
|
||||
mal_reset(mal);
|
||||
|
||||
/* Set the MAL configuration register */
|
||||
set_mal_dcrn(mal, MAL_CFG, MAL_CFG_DEFAULT | MAL_CFG_PLBB |
|
||||
MAL_CFG_OPBBL | MAL_CFG_LEA);
|
||||
|
||||
mal_enable_eob_irq(mal);
|
||||
|
||||
/* Allocate space for BD rings */
|
||||
BUG_ON(maldata->num_tx_chans <= 0 || maldata->num_tx_chans > 32);
|
||||
BUG_ON(maldata->num_rx_chans <= 0 || maldata->num_rx_chans > 32);
|
||||
bd_size = sizeof(struct mal_descriptor) *
|
||||
(NUM_TX_BUFF * maldata->num_tx_chans +
|
||||
NUM_RX_BUFF * maldata->num_rx_chans);
|
||||
mal->bd_virt =
|
||||
dma_alloc_coherent(&ocpdev->dev, bd_size, &mal->bd_dma, GFP_KERNEL);
|
||||
|
||||
if (!mal->bd_virt) {
|
||||
printk(KERN_ERR
|
||||
"mal%d: out of memory allocating RX/TX descriptors!\n",
|
||||
mal->def->index);
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
memset(mal->bd_virt, 0, bd_size);
|
||||
|
||||
for (i = 0; i < maldata->num_tx_chans; ++i)
|
||||
set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
|
||||
sizeof(struct mal_descriptor) *
|
||||
mal_tx_bd_offset(mal, i));
|
||||
|
||||
for (i = 0; i < maldata->num_rx_chans; ++i)
|
||||
set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma +
|
||||
sizeof(struct mal_descriptor) *
|
||||
mal_rx_bd_offset(mal, i));
|
||||
|
||||
err = request_irq(maldata->serr_irq, mal_serr, 0, "MAL SERR", mal);
|
||||
if (err)
|
||||
goto fail2;
|
||||
err = request_irq(maldata->txde_irq, mal_txde, 0, "MAL TX DE", mal);
|
||||
if (err)
|
||||
goto fail3;
|
||||
err = request_irq(maldata->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
|
||||
if (err)
|
||||
goto fail4;
|
||||
err = request_irq(maldata->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
|
||||
if (err)
|
||||
goto fail5;
|
||||
err = request_irq(maldata->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
|
||||
if (err)
|
||||
goto fail6;
|
||||
|
||||
/* Enable all MAL SERR interrupt sources */
|
||||
set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
|
||||
|
||||
/* Advertise this instance to the rest of the world */
|
||||
ocp_set_drvdata(ocpdev, mal);
|
||||
|
||||
mal_dbg_register(mal->def->index, mal);
|
||||
|
||||
printk(KERN_INFO "mal%d: initialized, %d TX channels, %d RX channels\n",
|
||||
mal->def->index, maldata->num_tx_chans, maldata->num_rx_chans);
|
||||
return 0;
|
||||
|
||||
fail6:
|
||||
free_irq(maldata->rxde_irq, mal);
|
||||
fail5:
|
||||
free_irq(maldata->txeob_irq, mal);
|
||||
fail4:
|
||||
free_irq(maldata->txde_irq, mal);
|
||||
fail3:
|
||||
free_irq(maldata->serr_irq, mal);
|
||||
fail2:
|
||||
dma_free_coherent(&ocpdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
|
||||
fail:
|
||||
kfree(mal);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit mal_remove(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct ibm_ocp_mal *mal = ocp_get_drvdata(ocpdev);
|
||||
struct ocp_func_mal_data *maldata = mal->def->additions;
|
||||
|
||||
MAL_DBG("%d: remove" NL, mal->def->index);
|
||||
|
||||
/* Synchronize with scheduled polling */
|
||||
napi_disable(&mal->napi);
|
||||
|
||||
if (!list_empty(&mal->list)) {
|
||||
/* This is *very* bad */
|
||||
printk(KERN_EMERG
|
||||
"mal%d: commac list is not empty on remove!\n",
|
||||
mal->def->index);
|
||||
}
|
||||
|
||||
ocp_set_drvdata(ocpdev, NULL);
|
||||
|
||||
free_irq(maldata->serr_irq, mal);
|
||||
free_irq(maldata->txde_irq, mal);
|
||||
free_irq(maldata->txeob_irq, mal);
|
||||
free_irq(maldata->rxde_irq, mal);
|
||||
free_irq(maldata->rxeob_irq, mal);
|
||||
|
||||
mal_reset(mal);
|
||||
|
||||
mal_dbg_register(mal->def->index, NULL);
|
||||
|
||||
dma_free_coherent(&ocpdev->dev,
|
||||
sizeof(struct mal_descriptor) *
|
||||
(NUM_TX_BUFF * maldata->num_tx_chans +
|
||||
NUM_RX_BUFF * maldata->num_rx_chans), mal->bd_virt,
|
||||
mal->bd_dma);
|
||||
|
||||
kfree(mal);
|
||||
}
|
||||
|
||||
/* Structure for a device driver */
|
||||
static struct ocp_device_id mal_ids[] = {
|
||||
{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_MAL },
|
||||
{ .vendor = OCP_VENDOR_INVALID}
|
||||
};
|
||||
|
||||
static struct ocp_driver mal_driver = {
|
||||
.name = "mal",
|
||||
.id_table = mal_ids,
|
||||
|
||||
.probe = mal_probe,
|
||||
.remove = mal_remove,
|
||||
};
|
||||
|
||||
int __init mal_init(void)
|
||||
{
|
||||
MAL_DBG(": init" NL);
|
||||
return ocp_register_driver(&mal_driver);
|
||||
}
|
||||
|
||||
void __exit mal_exit(void)
|
||||
{
|
||||
MAL_DBG(": exit" NL);
|
||||
ocp_unregister_driver(&mal_driver);
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_mal.h
|
||||
*
|
||||
* Memory Access Layer (MAL) support
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2002 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef __IBM_EMAC_MAL_H_
|
||||
#define __IBM_EMAC_MAL_H_
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/dcr.h>
|
||||
|
||||
/*
|
||||
* These MAL "versions" probably aren't the real versions IBM uses for these
|
||||
* MAL cores, I assigned them just to make #ifdefs in this file nicer and
|
||||
* reflect the fact that 40x and 44x have slightly different MALs. --ebs
|
||||
*/
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405GPR) || defined(CONFIG_405EP) || \
|
||||
defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_NP405H)
|
||||
#define MAL_VERSION 1
|
||||
#elif defined(CONFIG_440GP) || defined(CONFIG_440GX) || defined(CONFIG_440SP) || \
|
||||
defined(CONFIG_440SPE)
|
||||
#define MAL_VERSION 2
|
||||
#else
|
||||
#error "Unknown SoC, please check chip manual and choose MAL 'version'"
|
||||
#endif
|
||||
|
||||
/* MALx DCR registers */
|
||||
#define MAL_CFG 0x00
|
||||
#define MAL_CFG_SR 0x80000000
|
||||
#define MAL_CFG_PLBB 0x00004000
|
||||
#define MAL_CFG_OPBBL 0x00000080
|
||||
#define MAL_CFG_EOPIE 0x00000004
|
||||
#define MAL_CFG_LEA 0x00000002
|
||||
#define MAL_CFG_SD 0x00000001
|
||||
#if MAL_VERSION == 1
|
||||
#define MAL_CFG_PLBP_MASK 0x00c00000
|
||||
#define MAL_CFG_PLBP_10 0x00800000
|
||||
#define MAL_CFG_GA 0x00200000
|
||||
#define MAL_CFG_OA 0x00100000
|
||||
#define MAL_CFG_PLBLE 0x00080000
|
||||
#define MAL_CFG_PLBT_MASK 0x00078000
|
||||
#define MAL_CFG_DEFAULT (MAL_CFG_PLBP_10 | MAL_CFG_PLBT_MASK)
|
||||
#elif MAL_VERSION == 2
|
||||
#define MAL_CFG_RPP_MASK 0x00c00000
|
||||
#define MAL_CFG_RPP_10 0x00800000
|
||||
#define MAL_CFG_RMBS_MASK 0x00300000
|
||||
#define MAL_CFG_WPP_MASK 0x000c0000
|
||||
#define MAL_CFG_WPP_10 0x00080000
|
||||
#define MAL_CFG_WMBS_MASK 0x00030000
|
||||
#define MAL_CFG_PLBLE 0x00008000
|
||||
#define MAL_CFG_DEFAULT (MAL_CFG_RMBS_MASK | MAL_CFG_WMBS_MASK | \
|
||||
MAL_CFG_RPP_10 | MAL_CFG_WPP_10)
|
||||
#else
|
||||
#error "Unknown MAL version"
|
||||
#endif
|
||||
|
||||
#define MAL_ESR 0x01
|
||||
#define MAL_ESR_EVB 0x80000000
|
||||
#define MAL_ESR_CIDT 0x40000000
|
||||
#define MAL_ESR_CID_MASK 0x3e000000
|
||||
#define MAL_ESR_CID_SHIFT 25
|
||||
#define MAL_ESR_DE 0x00100000
|
||||
#define MAL_ESR_OTE 0x00040000
|
||||
#define MAL_ESR_OSE 0x00020000
|
||||
#define MAL_ESR_PEIN 0x00010000
|
||||
#define MAL_ESR_DEI 0x00000010
|
||||
#define MAL_ESR_OTEI 0x00000004
|
||||
#define MAL_ESR_OSEI 0x00000002
|
||||
#define MAL_ESR_PBEI 0x00000001
|
||||
#if MAL_VERSION == 1
|
||||
#define MAL_ESR_ONE 0x00080000
|
||||
#define MAL_ESR_ONEI 0x00000008
|
||||
#elif MAL_VERSION == 2
|
||||
#define MAL_ESR_PTE 0x00800000
|
||||
#define MAL_ESR_PRE 0x00400000
|
||||
#define MAL_ESR_PWE 0x00200000
|
||||
#define MAL_ESR_PTEI 0x00000080
|
||||
#define MAL_ESR_PREI 0x00000040
|
||||
#define MAL_ESR_PWEI 0x00000020
|
||||
#else
|
||||
#error "Unknown MAL version"
|
||||
#endif
|
||||
|
||||
#define MAL_IER 0x02
|
||||
#define MAL_IER_DE 0x00000010
|
||||
#define MAL_IER_OTE 0x00000004
|
||||
#define MAL_IER_OE 0x00000002
|
||||
#define MAL_IER_PE 0x00000001
|
||||
#if MAL_VERSION == 1
|
||||
#define MAL_IER_NWE 0x00000008
|
||||
#define MAL_IER_SOC_EVENTS MAL_IER_NWE
|
||||
#elif MAL_VERSION == 2
|
||||
#define MAL_IER_PT 0x00000080
|
||||
#define MAL_IER_PRE 0x00000040
|
||||
#define MAL_IER_PWE 0x00000020
|
||||
#define MAL_IER_SOC_EVENTS (MAL_IER_PT | MAL_IER_PRE | MAL_IER_PWE)
|
||||
#else
|
||||
#error "Unknown MAL version"
|
||||
#endif
|
||||
#define MAL_IER_EVENTS (MAL_IER_SOC_EVENTS | MAL_IER_OTE | \
|
||||
MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
|
||||
|
||||
#define MAL_TXCASR 0x04
|
||||
#define MAL_TXCARR 0x05
|
||||
#define MAL_TXEOBISR 0x06
|
||||
#define MAL_TXDEIR 0x07
|
||||
#define MAL_RXCASR 0x10
|
||||
#define MAL_RXCARR 0x11
|
||||
#define MAL_RXEOBISR 0x12
|
||||
#define MAL_RXDEIR 0x13
|
||||
#define MAL_TXCTPR(n) ((n) + 0x20)
|
||||
#define MAL_RXCTPR(n) ((n) + 0x40)
|
||||
#define MAL_RCBS(n) ((n) + 0x60)
|
||||
|
||||
/* In reality MAL can handle TX buffers up to 4095 bytes long,
|
||||
* but this isn't a good round number :) --ebs
|
||||
*/
|
||||
#define MAL_MAX_TX_SIZE 4080
|
||||
#define MAL_MAX_RX_SIZE 4080
|
||||
|
||||
static inline int mal_rx_size(int len)
|
||||
{
|
||||
len = (len + 0xf) & ~0xf;
|
||||
return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len;
|
||||
}
|
||||
|
||||
static inline int mal_tx_chunks(int len)
|
||||
{
|
||||
return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
|
||||
}
|
||||
|
||||
#define MAL_CHAN_MASK(n) (0x80000000 >> (n))
|
||||
|
||||
/* MAL Buffer Descriptor structure */
|
||||
struct mal_descriptor {
|
||||
u16 ctrl; /* MAL / Commac status control bits */
|
||||
u16 data_len; /* Max length is 4K-1 (12 bits) */
|
||||
u32 data_ptr; /* pointer to actual data buffer */
|
||||
};
|
||||
|
||||
/* the following defines are for the MadMAL status and control registers. */
|
||||
/* MADMAL transmit and receive status/control bits */
|
||||
#define MAL_RX_CTRL_EMPTY 0x8000
|
||||
#define MAL_RX_CTRL_WRAP 0x4000
|
||||
#define MAL_RX_CTRL_CM 0x2000
|
||||
#define MAL_RX_CTRL_LAST 0x1000
|
||||
#define MAL_RX_CTRL_FIRST 0x0800
|
||||
#define MAL_RX_CTRL_INTR 0x0400
|
||||
#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST)
|
||||
#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE)
|
||||
|
||||
#define MAL_TX_CTRL_READY 0x8000
|
||||
#define MAL_TX_CTRL_WRAP 0x4000
|
||||
#define MAL_TX_CTRL_CM 0x2000
|
||||
#define MAL_TX_CTRL_LAST 0x1000
|
||||
#define MAL_TX_CTRL_INTR 0x0400
|
||||
|
||||
struct mal_commac_ops {
|
||||
void (*poll_tx) (void *dev);
|
||||
int (*poll_rx) (void *dev, int budget);
|
||||
int (*peek_rx) (void *dev);
|
||||
void (*rxde) (void *dev);
|
||||
};
|
||||
|
||||
struct mal_commac {
|
||||
struct mal_commac_ops *ops;
|
||||
void *dev;
|
||||
struct list_head poll_list;
|
||||
int rx_stopped;
|
||||
|
||||
u32 tx_chan_mask;
|
||||
u32 rx_chan_mask;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct ibm_ocp_mal {
|
||||
dcr_host_t dcrhost;
|
||||
|
||||
struct list_head poll_list;
|
||||
struct napi_struct napi;
|
||||
|
||||
struct list_head list;
|
||||
u32 tx_chan_mask;
|
||||
u32 rx_chan_mask;
|
||||
|
||||
dma_addr_t bd_dma;
|
||||
struct mal_descriptor *bd_virt;
|
||||
|
||||
struct ocp_def *def;
|
||||
};
|
||||
|
||||
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
|
||||
{
|
||||
return dcr_read(mal->dcrhost, reg);
|
||||
}
|
||||
|
||||
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
|
||||
{
|
||||
dcr_write(mal->dcrhost, reg, val);
|
||||
}
|
||||
|
||||
/* Register MAL devices */
|
||||
int mal_init(void) __init;
|
||||
void mal_exit(void) __exit;
|
||||
|
||||
int mal_register_commac(struct ibm_ocp_mal *mal,
|
||||
struct mal_commac *commac) __init;
|
||||
void mal_unregister_commac(struct ibm_ocp_mal *mal, struct mal_commac *commac);
|
||||
int mal_set_rcbs(struct ibm_ocp_mal *mal, int channel, unsigned long size);
|
||||
|
||||
/* Returns BD ring offset for a particular channel
|
||||
(in 'struct mal_descriptor' elements)
|
||||
*/
|
||||
int mal_tx_bd_offset(struct ibm_ocp_mal *mal, int channel);
|
||||
int mal_rx_bd_offset(struct ibm_ocp_mal *mal, int channel);
|
||||
|
||||
void mal_enable_tx_channel(struct ibm_ocp_mal *mal, int channel);
|
||||
void mal_disable_tx_channel(struct ibm_ocp_mal *mal, int channel);
|
||||
void mal_enable_rx_channel(struct ibm_ocp_mal *mal, int channel);
|
||||
void mal_disable_rx_channel(struct ibm_ocp_mal *mal, int channel);
|
||||
|
||||
/* Add/remove EMAC to/from MAL polling list */
|
||||
void mal_poll_add(struct ibm_ocp_mal *mal, struct mal_commac *commac);
|
||||
void mal_poll_del(struct ibm_ocp_mal *mal, struct mal_commac *commac);
|
||||
|
||||
/* Ethtool MAL registers */
|
||||
struct ibm_mal_regs {
|
||||
u32 tx_count;
|
||||
u32 rx_count;
|
||||
|
||||
u32 cfg;
|
||||
u32 esr;
|
||||
u32 ier;
|
||||
u32 tx_casr;
|
||||
u32 tx_carr;
|
||||
u32 tx_eobisr;
|
||||
u32 tx_deir;
|
||||
u32 rx_casr;
|
||||
u32 rx_carr;
|
||||
u32 rx_eobisr;
|
||||
u32 rx_deir;
|
||||
u32 tx_ctpr[32];
|
||||
u32 rx_ctpr[32];
|
||||
u32 rcbs[32];
|
||||
};
|
||||
|
||||
int mal_get_regs_len(struct ibm_ocp_mal *mal);
|
||||
void *mal_dump_regs(struct ibm_ocp_mal *mal, void *buf);
|
||||
|
||||
#endif /* __IBM_EMAC_MAL_H_ */
|
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_phy.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
|
||||
* Borrowed from sungem_phy.c, though I only kept the generic MII
|
||||
* driver for now.
|
||||
*
|
||||
* This file should be shared with other drivers or eventually
|
||||
* merged as the "low level" part of miilib
|
||||
*
|
||||
* (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
|
||||
* (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/ocp.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_phy.h"
|
||||
|
||||
static inline int phy_read(struct mii_phy *phy, int reg)
|
||||
{
|
||||
return phy->mdio_read(phy->dev, phy->address, reg);
|
||||
}
|
||||
|
||||
static inline void phy_write(struct mii_phy *phy, int reg, int val)
|
||||
{
|
||||
phy->mdio_write(phy->dev, phy->address, reg, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* polls MII_BMCR until BMCR_RESET bit clears or operation times out.
|
||||
*
|
||||
* returns:
|
||||
* >= 0 => success, value in BMCR returned to caller
|
||||
* -EBUSY => failure, RESET bit never cleared
|
||||
* otherwise => failure, lower level PHY read failed
|
||||
*/
|
||||
static int mii_spin_reset_complete(struct mii_phy *phy)
|
||||
{
|
||||
int val;
|
||||
int limit = 10000;
|
||||
|
||||
while (limit--) {
|
||||
val = phy_read(phy, MII_BMCR);
|
||||
if (val >= 0 && !(val & BMCR_RESET))
|
||||
return val; /* success */
|
||||
udelay(10);
|
||||
}
|
||||
if (val & BMCR_RESET)
|
||||
val = -EBUSY;
|
||||
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "emac%d: PHY reset timeout (%d)\n",
|
||||
((struct ocp_enet_private *)phy->dev->priv)->def->index,
|
||||
val);
|
||||
return val;
|
||||
}
|
||||
|
||||
int mii_reset_phy(struct mii_phy *phy)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = phy_read(phy, MII_BMCR);
|
||||
val &= ~BMCR_ISOLATE;
|
||||
val |= BMCR_RESET;
|
||||
phy_write(phy, MII_BMCR, val);
|
||||
|
||||
udelay(300);
|
||||
|
||||
val = mii_spin_reset_complete(phy);
|
||||
if (val >= 0 && (val & BMCR_ISOLATE))
|
||||
phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
|
||||
|
||||
return val < 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
|
||||
{
|
||||
int ctl, adv;
|
||||
|
||||
phy->autoneg = AUTONEG_ENABLE;
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
phy->advertising = advertise;
|
||||
|
||||
/* Setup standard advertise */
|
||||
adv = phy_read(phy, MII_ADVERTISE);
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
|
||||
ADVERTISE_PAUSE_ASYM);
|
||||
if (advertise & ADVERTISED_10baseT_Half)
|
||||
adv |= ADVERTISE_10HALF;
|
||||
if (advertise & ADVERTISED_10baseT_Full)
|
||||
adv |= ADVERTISE_10FULL;
|
||||
if (advertise & ADVERTISED_100baseT_Half)
|
||||
adv |= ADVERTISE_100HALF;
|
||||
if (advertise & ADVERTISED_100baseT_Full)
|
||||
adv |= ADVERTISE_100FULL;
|
||||
if (advertise & ADVERTISED_Pause)
|
||||
adv |= ADVERTISE_PAUSE_CAP;
|
||||
if (advertise & ADVERTISED_Asym_Pause)
|
||||
adv |= ADVERTISE_PAUSE_ASYM;
|
||||
phy_write(phy, MII_ADVERTISE, adv);
|
||||
|
||||
if (phy->features &
|
||||
(SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
|
||||
adv = phy_read(phy, MII_CTRL1000);
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
if (advertise & ADVERTISED_1000baseT_Full)
|
||||
adv |= ADVERTISE_1000FULL;
|
||||
if (advertise & ADVERTISED_1000baseT_Half)
|
||||
adv |= ADVERTISE_1000HALF;
|
||||
phy_write(phy, MII_CTRL1000, adv);
|
||||
}
|
||||
|
||||
/* Start/Restart aneg */
|
||||
/* on some PHYs (e.g. National DP83843) a write to MII_ADVERTISE
|
||||
* causes BMCR_RESET to be set on the next read of MII_BMCR, which
|
||||
* if not checked for causes the PHY to be reset below */
|
||||
ctl = mii_spin_reset_complete(phy);
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
|
||||
ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
|
||||
{
|
||||
int ctl;
|
||||
|
||||
phy->autoneg = AUTONEG_DISABLE;
|
||||
phy->speed = speed;
|
||||
phy->duplex = fd;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
|
||||
/* First reset the PHY */
|
||||
mii_reset_phy(phy);
|
||||
|
||||
ctl = phy_read(phy, MII_BMCR);
|
||||
if (ctl < 0)
|
||||
return ctl;
|
||||
ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE | BMCR_SPEED1000);
|
||||
|
||||
/* Select speed & duplex */
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
break;
|
||||
case SPEED_100:
|
||||
ctl |= BMCR_SPEED100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
ctl |= BMCR_SPEED1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (fd == DUPLEX_FULL)
|
||||
ctl |= BMCR_FULLDPLX;
|
||||
phy_write(phy, MII_BMCR, ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int genmii_poll_link(struct mii_phy *phy)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Clear latched value with dummy read */
|
||||
phy_read(phy, MII_BMSR);
|
||||
status = phy_read(phy, MII_BMSR);
|
||||
if (status < 0 || (status & BMSR_LSTATUS) == 0)
|
||||
return 0;
|
||||
if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int genmii_read_link(struct mii_phy *phy)
|
||||
{
|
||||
if (phy->autoneg == AUTONEG_ENABLE) {
|
||||
int glpa = 0;
|
||||
int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
|
||||
if (lpa < 0)
|
||||
return lpa;
|
||||
|
||||
if (phy->features &
|
||||
(SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
|
||||
int adv = phy_read(phy, MII_CTRL1000);
|
||||
glpa = phy_read(phy, MII_STAT1000);
|
||||
|
||||
if (glpa < 0 || adv < 0)
|
||||
return adv;
|
||||
|
||||
glpa &= adv << 2;
|
||||
}
|
||||
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
|
||||
if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
|
||||
phy->speed = SPEED_1000;
|
||||
if (glpa & LPA_1000FULL)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
|
||||
phy->speed = SPEED_100;
|
||||
if (lpa & LPA_100FULL)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
} else if (lpa & LPA_10FULL)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
|
||||
if (phy->duplex == DUPLEX_FULL) {
|
||||
phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
|
||||
phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
int bmcr = phy_read(phy, MII_BMCR);
|
||||
if (bmcr < 0)
|
||||
return bmcr;
|
||||
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
phy->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
phy->speed = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
phy->speed = SPEED_100;
|
||||
else
|
||||
phy->speed = SPEED_10;
|
||||
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generic implementation for most 10/100/1000 PHYs */
|
||||
static struct mii_phy_ops generic_phy_ops = {
|
||||
.setup_aneg = genmii_setup_aneg,
|
||||
.setup_forced = genmii_setup_forced,
|
||||
.poll_link = genmii_poll_link,
|
||||
.read_link = genmii_read_link
|
||||
};
|
||||
|
||||
static struct mii_phy_def genmii_phy_def = {
|
||||
.phy_id = 0x00000000,
|
||||
.phy_id_mask = 0x00000000,
|
||||
.name = "Generic MII",
|
||||
.ops = &generic_phy_ops
|
||||
};
|
||||
|
||||
/* CIS8201 */
|
||||
#define MII_CIS8201_10BTCSR 0x16
|
||||
#define TENBTCSR_ECHO_DISABLE 0x2000
|
||||
#define MII_CIS8201_EPCR 0x17
|
||||
#define EPCR_MODE_MASK 0x3000
|
||||
#define EPCR_GMII_MODE 0x0000
|
||||
#define EPCR_RGMII_MODE 0x1000
|
||||
#define EPCR_TBI_MODE 0x2000
|
||||
#define EPCR_RTBI_MODE 0x3000
|
||||
#define MII_CIS8201_ACSR 0x1c
|
||||
#define ACSR_PIN_PRIO_SELECT 0x0004
|
||||
|
||||
static int cis8201_init(struct mii_phy *phy)
|
||||
{
|
||||
int epcr;
|
||||
|
||||
epcr = phy_read(phy, MII_CIS8201_EPCR);
|
||||
if (epcr < 0)
|
||||
return epcr;
|
||||
|
||||
epcr &= ~EPCR_MODE_MASK;
|
||||
|
||||
switch (phy->mode) {
|
||||
case PHY_MODE_TBI:
|
||||
epcr |= EPCR_TBI_MODE;
|
||||
break;
|
||||
case PHY_MODE_RTBI:
|
||||
epcr |= EPCR_RTBI_MODE;
|
||||
break;
|
||||
case PHY_MODE_GMII:
|
||||
epcr |= EPCR_GMII_MODE;
|
||||
break;
|
||||
case PHY_MODE_RGMII:
|
||||
default:
|
||||
epcr |= EPCR_RGMII_MODE;
|
||||
}
|
||||
|
||||
phy_write(phy, MII_CIS8201_EPCR, epcr);
|
||||
|
||||
/* MII regs override strap pins */
|
||||
phy_write(phy, MII_CIS8201_ACSR,
|
||||
phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
|
||||
|
||||
/* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
|
||||
phy_write(phy, MII_CIS8201_10BTCSR,
|
||||
phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mii_phy_ops cis8201_phy_ops = {
|
||||
.init = cis8201_init,
|
||||
.setup_aneg = genmii_setup_aneg,
|
||||
.setup_forced = genmii_setup_forced,
|
||||
.poll_link = genmii_poll_link,
|
||||
.read_link = genmii_read_link
|
||||
};
|
||||
|
||||
static struct mii_phy_def cis8201_phy_def = {
|
||||
.phy_id = 0x000fc410,
|
||||
.phy_id_mask = 0x000ffff0,
|
||||
.name = "CIS8201 Gigabit Ethernet",
|
||||
.ops = &cis8201_phy_ops
|
||||
};
|
||||
|
||||
static struct mii_phy_def *mii_phy_table[] = {
|
||||
&cis8201_phy_def,
|
||||
&genmii_phy_def,
|
||||
NULL
|
||||
};
|
||||
|
||||
int mii_phy_probe(struct mii_phy *phy, int address)
|
||||
{
|
||||
struct mii_phy_def *def;
|
||||
int i;
|
||||
int id;
|
||||
|
||||
phy->autoneg = AUTONEG_DISABLE;
|
||||
phy->advertising = 0;
|
||||
phy->address = address;
|
||||
phy->speed = SPEED_10;
|
||||
phy->duplex = DUPLEX_HALF;
|
||||
phy->pause = phy->asym_pause = 0;
|
||||
|
||||
/* Take PHY out of isolate mode and reset it. */
|
||||
if (mii_reset_phy(phy))
|
||||
return -ENODEV;
|
||||
|
||||
/* Read ID and find matching entry */
|
||||
id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
|
||||
if (id < 0)
|
||||
return -ENODEV;
|
||||
for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
|
||||
if ((id & def->phy_id_mask) == def->phy_id)
|
||||
break;
|
||||
/* Should never be NULL (we have a generic entry), but... */
|
||||
if (!def)
|
||||
return -ENODEV;
|
||||
|
||||
phy->def = def;
|
||||
|
||||
/* Determine PHY features if needed */
|
||||
phy->features = def->features;
|
||||
if (!phy->features) {
|
||||
u16 bmsr = phy_read(phy, MII_BMSR);
|
||||
if (bmsr & BMSR_ANEGCAPABLE)
|
||||
phy->features |= SUPPORTED_Autoneg;
|
||||
if (bmsr & BMSR_10HALF)
|
||||
phy->features |= SUPPORTED_10baseT_Half;
|
||||
if (bmsr & BMSR_10FULL)
|
||||
phy->features |= SUPPORTED_10baseT_Full;
|
||||
if (bmsr & BMSR_100HALF)
|
||||
phy->features |= SUPPORTED_100baseT_Half;
|
||||
if (bmsr & BMSR_100FULL)
|
||||
phy->features |= SUPPORTED_100baseT_Full;
|
||||
if (bmsr & BMSR_ESTATEN) {
|
||||
u16 esr = phy_read(phy, MII_ESTATUS);
|
||||
if (esr & ESTATUS_1000_TFULL)
|
||||
phy->features |= SUPPORTED_1000baseT_Full;
|
||||
if (esr & ESTATUS_1000_THALF)
|
||||
phy->features |= SUPPORTED_1000baseT_Half;
|
||||
}
|
||||
phy->features |= SUPPORTED_MII;
|
||||
}
|
||||
|
||||
/* Setup default advertising */
|
||||
phy->advertising = phy->features;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_phy.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, PHY support
|
||||
*
|
||||
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||
* February 2003
|
||||
*
|
||||
* Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This file basically duplicates sungem_phy.{c,h} with different PHYs
|
||||
* supported. I'm looking into merging that in a single mii layer more
|
||||
* flexible than mii.c
|
||||
*/
|
||||
|
||||
#ifndef _IBM_OCP_PHY_H_
|
||||
#define _IBM_OCP_PHY_H_
|
||||
|
||||
struct mii_phy;
|
||||
|
||||
/* Operations supported by any kind of PHY */
|
||||
struct mii_phy_ops {
|
||||
int (*init) (struct mii_phy * phy);
|
||||
int (*suspend) (struct mii_phy * phy, int wol_options);
|
||||
int (*setup_aneg) (struct mii_phy * phy, u32 advertise);
|
||||
int (*setup_forced) (struct mii_phy * phy, int speed, int fd);
|
||||
int (*poll_link) (struct mii_phy * phy);
|
||||
int (*read_link) (struct mii_phy * phy);
|
||||
};
|
||||
|
||||
/* Structure used to statically define an mii/gii based PHY */
|
||||
struct mii_phy_def {
|
||||
u32 phy_id; /* Concatenated ID1 << 16 | ID2 */
|
||||
u32 phy_id_mask; /* Significant bits */
|
||||
u32 features; /* Ethtool SUPPORTED_* defines or
|
||||
0 for autodetect */
|
||||
int magic_aneg; /* Autoneg does all speed test for us */
|
||||
const char *name;
|
||||
const struct mii_phy_ops *ops;
|
||||
};
|
||||
|
||||
/* An instance of a PHY, partially borrowed from mii_if_info */
|
||||
struct mii_phy {
|
||||
struct mii_phy_def *def;
|
||||
u32 advertising; /* Ethtool ADVERTISED_* defines */
|
||||
u32 features; /* Copied from mii_phy_def.features
|
||||
or determined automaticaly */
|
||||
int address; /* PHY address */
|
||||
int mode; /* PHY mode */
|
||||
|
||||
/* 1: autoneg enabled, 0: disabled */
|
||||
int autoneg;
|
||||
|
||||
/* forced speed & duplex (no autoneg)
|
||||
* partner speed & duplex & pause (autoneg)
|
||||
*/
|
||||
int speed;
|
||||
int duplex;
|
||||
int pause;
|
||||
int asym_pause;
|
||||
|
||||
/* Provided by host chip */
|
||||
struct net_device *dev;
|
||||
int (*mdio_read) (struct net_device * dev, int addr, int reg);
|
||||
void (*mdio_write) (struct net_device * dev, int addr, int reg,
|
||||
int val);
|
||||
};
|
||||
|
||||
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
|
||||
* filled, the remaining fields will be filled on return
|
||||
*/
|
||||
int mii_phy_probe(struct mii_phy *phy, int address);
|
||||
int mii_reset_phy(struct mii_phy *phy);
|
||||
|
||||
#endif /* _IBM_OCP_PHY_H_ */
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_rgmii.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
* Copyright 2004 MontaVista Software, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_debug.h"
|
||||
|
||||
/* RGMIIx_FER */
|
||||
#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4))
|
||||
#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4))
|
||||
#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4))
|
||||
#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4))
|
||||
#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4))
|
||||
|
||||
/* RGMIIx_SSR */
|
||||
#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
|
||||
#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
|
||||
#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
|
||||
|
||||
/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
|
||||
static inline int rgmii_valid_mode(int phy_mode)
|
||||
{
|
||||
return phy_mode == PHY_MODE_GMII ||
|
||||
phy_mode == PHY_MODE_RGMII ||
|
||||
phy_mode == PHY_MODE_TBI ||
|
||||
phy_mode == PHY_MODE_RTBI;
|
||||
}
|
||||
|
||||
static inline const char *rgmii_mode_name(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case PHY_MODE_RGMII:
|
||||
return "RGMII";
|
||||
case PHY_MODE_TBI:
|
||||
return "TBI";
|
||||
case PHY_MODE_GMII:
|
||||
return "GMII";
|
||||
case PHY_MODE_RTBI:
|
||||
return "RTBI";
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 rgmii_mode_mask(int mode, int input)
|
||||
{
|
||||
switch (mode) {
|
||||
case PHY_MODE_RGMII:
|
||||
return RGMII_FER_RGMII(input);
|
||||
case PHY_MODE_TBI:
|
||||
return RGMII_FER_TBI(input);
|
||||
case PHY_MODE_GMII:
|
||||
return RGMII_FER_GMII(input);
|
||||
case PHY_MODE_RTBI:
|
||||
return RGMII_FER_RTBI(input);
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static int __init rgmii_init(struct ocp_device *ocpdev, int input, int mode)
|
||||
{
|
||||
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
|
||||
struct rgmii_regs *p;
|
||||
|
||||
RGMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, mode);
|
||||
|
||||
if (!dev) {
|
||||
dev = kzalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR
|
||||
"rgmii%d: couldn't allocate device structure!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
p = (struct rgmii_regs *)ioremap(ocpdev->def->paddr,
|
||||
sizeof(struct rgmii_regs));
|
||||
if (!p) {
|
||||
printk(KERN_ERR
|
||||
"rgmii%d: could not ioremap device registers!\n",
|
||||
ocpdev->def->index);
|
||||
kfree(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->base = p;
|
||||
ocp_set_drvdata(ocpdev, dev);
|
||||
|
||||
/* Disable all inputs by default */
|
||||
out_be32(&p->fer, 0);
|
||||
} else
|
||||
p = dev->base;
|
||||
|
||||
/* Enable this input */
|
||||
out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
|
||||
|
||||
printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n",
|
||||
ocpdev->def->index, input, rgmii_mode_name(mode));
|
||||
|
||||
++dev->users;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init rgmii_attach(void *emac)
|
||||
{
|
||||
struct ocp_enet_private *dev = emac;
|
||||
struct ocp_func_emac_data *emacdata = dev->def->additions;
|
||||
|
||||
/* Check if we need to attach to a RGMII */
|
||||
if (emacdata->rgmii_idx >= 0 && rgmii_valid_mode(emacdata->phy_mode)) {
|
||||
dev->rgmii_input = emacdata->rgmii_mux;
|
||||
dev->rgmii_dev =
|
||||
ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_RGMII,
|
||||
emacdata->rgmii_idx);
|
||||
if (!dev->rgmii_dev) {
|
||||
printk(KERN_ERR "emac%d: unknown rgmii%d!\n",
|
||||
dev->def->index, emacdata->rgmii_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (rgmii_init
|
||||
(dev->rgmii_dev, dev->rgmii_input, emacdata->phy_mode)) {
|
||||
printk(KERN_ERR
|
||||
"emac%d: rgmii%d initialization failed!\n",
|
||||
dev->def->index, emacdata->rgmii_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed)
|
||||
{
|
||||
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
|
||||
u32 ssr = in_be32(&dev->base->ssr) & ~RGMII_SSR_MASK(input);
|
||||
|
||||
RGMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);
|
||||
|
||||
if (speed == SPEED_1000)
|
||||
ssr |= RGMII_SSR_1000(input);
|
||||
else if (speed == SPEED_100)
|
||||
ssr |= RGMII_SSR_100(input);
|
||||
|
||||
out_be32(&dev->base->ssr, ssr);
|
||||
}
|
||||
|
||||
void __rgmii_fini(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
|
||||
BUG_ON(!dev || dev->users == 0);
|
||||
|
||||
RGMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);
|
||||
|
||||
/* Disable this input */
|
||||
out_be32(&dev->base->fer,
|
||||
in_be32(&dev->base->fer) & ~RGMII_FER_MASK(input));
|
||||
|
||||
if (!--dev->users) {
|
||||
/* Free everything if this is the last user */
|
||||
ocp_set_drvdata(ocpdev, NULL);
|
||||
iounmap((void *)dev->base);
|
||||
kfree(dev);
|
||||
}
|
||||
}
|
||||
|
||||
int __rgmii_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return sizeof(struct emac_ethtool_regs_subhdr) +
|
||||
sizeof(struct rgmii_regs);
|
||||
}
|
||||
|
||||
void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf)
|
||||
{
|
||||
struct ibm_ocp_rgmii *dev = ocp_get_drvdata(ocpdev);
|
||||
struct emac_ethtool_regs_subhdr *hdr = buf;
|
||||
struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
|
||||
|
||||
hdr->version = 0;
|
||||
hdr->index = ocpdev->def->index;
|
||||
memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
|
||||
return regs + 1;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_rgmii.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
|
||||
*
|
||||
* Based on ocp_zmii.h/ibm_emac_zmii.h
|
||||
* Armin Kuster akuster@mvista.com
|
||||
*
|
||||
* Copyright 2004 MontaVista Software, Inc.
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _IBM_EMAC_RGMII_H_
|
||||
#define _IBM_EMAC_RGMII_H_
|
||||
|
||||
|
||||
/* RGMII bridge */
|
||||
struct rgmii_regs {
|
||||
u32 fer; /* Function enable register */
|
||||
u32 ssr; /* Speed select register */
|
||||
};
|
||||
|
||||
/* RGMII device */
|
||||
struct ibm_ocp_rgmii {
|
||||
struct rgmii_regs __iomem *base;
|
||||
int users; /* number of EMACs using this RGMII bridge */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IBM_EMAC_RGMII
|
||||
int rgmii_attach(void *emac) __init;
|
||||
|
||||
void __rgmii_fini(struct ocp_device *ocpdev, int input);
|
||||
static inline void rgmii_fini(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
if (ocpdev)
|
||||
__rgmii_fini(ocpdev, input);
|
||||
}
|
||||
|
||||
void rgmii_set_speed(struct ocp_device *ocpdev, int input, int speed);
|
||||
|
||||
int __rgmii_get_regs_len(struct ocp_device *ocpdev);
|
||||
static inline int rgmii_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return ocpdev ? __rgmii_get_regs_len(ocpdev) : 0;
|
||||
}
|
||||
|
||||
void *rgmii_dump_regs(struct ocp_device *ocpdev, void *buf);
|
||||
#else
|
||||
# define rgmii_attach(x) 0
|
||||
# define rgmii_fini(x,y) ((void)0)
|
||||
# define rgmii_set_speed(x,y,z) ((void)0)
|
||||
# define rgmii_get_regs_len(x) 0
|
||||
# define rgmii_dump_regs(x,buf) (buf)
|
||||
#endif /* !CONFIG_IBM_EMAC_RGMII */
|
||||
|
||||
#endif /* _IBM_EMAC_RGMII_H_ */
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_tah.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
|
||||
*
|
||||
* Copyright 2004 MontaVista Software, Inc.
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
|
||||
static int __init tah_init(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct tah_regs *p;
|
||||
|
||||
if (ocp_get_drvdata(ocpdev)) {
|
||||
printk(KERN_ERR "tah%d: already in use!\n", ocpdev->def->index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
|
||||
p = (struct tah_regs *)ioremap(ocpdev->def->paddr, sizeof(*p));
|
||||
if (!p) {
|
||||
printk(KERN_ERR "tah%d: could not ioremap device registers!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ocp_set_drvdata(ocpdev, p);
|
||||
__tah_reset(ocpdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init tah_attach(void *emac)
|
||||
{
|
||||
struct ocp_enet_private *dev = emac;
|
||||
struct ocp_func_emac_data *emacdata = dev->def->additions;
|
||||
|
||||
/* Check if we need to attach to a TAH */
|
||||
if (emacdata->tah_idx >= 0) {
|
||||
dev->tah_dev = ocp_find_device(OCP_ANY_ID, OCP_FUNC_TAH,
|
||||
emacdata->tah_idx);
|
||||
if (!dev->tah_dev) {
|
||||
printk(KERN_ERR "emac%d: unknown tah%d!\n",
|
||||
dev->def->index, emacdata->tah_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (tah_init(dev->tah_dev)) {
|
||||
printk(KERN_ERR
|
||||
"emac%d: tah%d initialization failed!\n",
|
||||
dev->def->index, emacdata->tah_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __tah_fini(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct tah_regs *p = ocp_get_drvdata(ocpdev);
|
||||
BUG_ON(!p);
|
||||
ocp_set_drvdata(ocpdev, NULL);
|
||||
iounmap((void *)p);
|
||||
}
|
||||
|
||||
void __tah_reset(struct ocp_device *ocpdev)
|
||||
{
|
||||
struct tah_regs *p = ocp_get_drvdata(ocpdev);
|
||||
int n;
|
||||
|
||||
/* Reset TAH */
|
||||
out_be32(&p->mr, TAH_MR_SR);
|
||||
n = 100;
|
||||
while ((in_be32(&p->mr) & TAH_MR_SR) && n)
|
||||
--n;
|
||||
|
||||
if (unlikely(!n))
|
||||
printk(KERN_ERR "tah%d: reset timeout\n", ocpdev->def->index);
|
||||
|
||||
/* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
|
||||
out_be32(&p->mr,
|
||||
TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
|
||||
TAH_MR_DIG);
|
||||
}
|
||||
|
||||
int __tah_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return sizeof(struct emac_ethtool_regs_subhdr) +
|
||||
sizeof(struct tah_regs);
|
||||
}
|
||||
|
||||
void *tah_dump_regs(struct ocp_device *ocpdev, void *buf)
|
||||
{
|
||||
struct tah_regs *dev = ocp_get_drvdata(ocpdev);
|
||||
struct emac_ethtool_regs_subhdr *hdr = buf;
|
||||
struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
|
||||
|
||||
hdr->version = 0;
|
||||
hdr->index = ocpdev->def->index;
|
||||
memcpy_fromio(regs, dev, sizeof(struct tah_regs));
|
||||
return regs + 1;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_tah.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
|
||||
*
|
||||
* Copyright 2004 MontaVista Software, Inc.
|
||||
* Matt Porter <mporter@kernel.crashing.org>
|
||||
*
|
||||
* Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _IBM_EMAC_TAH_H
|
||||
#define _IBM_EMAC_TAH_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
/* TAH */
|
||||
struct tah_regs {
|
||||
u32 revid;
|
||||
u32 pad[3];
|
||||
u32 mr;
|
||||
u32 ssr0;
|
||||
u32 ssr1;
|
||||
u32 ssr2;
|
||||
u32 ssr3;
|
||||
u32 ssr4;
|
||||
u32 ssr5;
|
||||
u32 tsr;
|
||||
};
|
||||
|
||||
/* TAH engine */
|
||||
#define TAH_MR_CVR 0x80000000
|
||||
#define TAH_MR_SR 0x40000000
|
||||
#define TAH_MR_ST_256 0x01000000
|
||||
#define TAH_MR_ST_512 0x02000000
|
||||
#define TAH_MR_ST_768 0x03000000
|
||||
#define TAH_MR_ST_1024 0x04000000
|
||||
#define TAH_MR_ST_1280 0x05000000
|
||||
#define TAH_MR_ST_1536 0x06000000
|
||||
#define TAH_MR_TFS_16KB 0x00000000
|
||||
#define TAH_MR_TFS_2KB 0x00200000
|
||||
#define TAH_MR_TFS_4KB 0x00400000
|
||||
#define TAH_MR_TFS_6KB 0x00600000
|
||||
#define TAH_MR_TFS_8KB 0x00800000
|
||||
#define TAH_MR_TFS_10KB 0x00a00000
|
||||
#define TAH_MR_DTFP 0x00100000
|
||||
#define TAH_MR_DIG 0x00080000
|
||||
|
||||
#ifdef CONFIG_IBM_EMAC_TAH
|
||||
int tah_attach(void *emac) __init;
|
||||
|
||||
void __tah_fini(struct ocp_device *ocpdev);
|
||||
static inline void tah_fini(struct ocp_device *ocpdev)
|
||||
{
|
||||
if (ocpdev)
|
||||
__tah_fini(ocpdev);
|
||||
}
|
||||
|
||||
void __tah_reset(struct ocp_device *ocpdev);
|
||||
static inline void tah_reset(struct ocp_device *ocpdev)
|
||||
{
|
||||
if (ocpdev)
|
||||
__tah_reset(ocpdev);
|
||||
}
|
||||
|
||||
int __tah_get_regs_len(struct ocp_device *ocpdev);
|
||||
static inline int tah_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return ocpdev ? __tah_get_regs_len(ocpdev) : 0;
|
||||
}
|
||||
|
||||
void *tah_dump_regs(struct ocp_device *ocpdev, void *buf);
|
||||
#else
|
||||
# define tah_attach(x) 0
|
||||
# define tah_fini(x) ((void)0)
|
||||
# define tah_reset(x) ((void)0)
|
||||
# define tah_get_regs_len(x) 0
|
||||
# define tah_dump_regs(x,buf) (buf)
|
||||
#endif /* !CONFIG_IBM_EMAC_TAH */
|
||||
|
||||
#endif /* _IBM_EMAC_TAH_H */
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_zmii.c
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2001 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "ibm_emac_core.h"
|
||||
#include "ibm_emac_debug.h"
|
||||
|
||||
/* ZMIIx_FER */
|
||||
#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4))
|
||||
#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \
|
||||
ZMII_FER_MDI(2) | ZMII_FER_MDI(3))
|
||||
|
||||
#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4))
|
||||
#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4))
|
||||
#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4))
|
||||
|
||||
/* ZMIIx_SSR */
|
||||
#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4))
|
||||
#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4))
|
||||
#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4))
|
||||
|
||||
/* ZMII only supports MII, RMII and SMII
|
||||
* we also support autodetection for backward compatibility
|
||||
*/
|
||||
static inline int zmii_valid_mode(int mode)
|
||||
{
|
||||
return mode == PHY_MODE_MII ||
|
||||
mode == PHY_MODE_RMII ||
|
||||
mode == PHY_MODE_SMII ||
|
||||
mode == PHY_MODE_NA;
|
||||
}
|
||||
|
||||
static inline const char *zmii_mode_name(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case PHY_MODE_MII:
|
||||
return "MII";
|
||||
case PHY_MODE_RMII:
|
||||
return "RMII";
|
||||
case PHY_MODE_SMII:
|
||||
return "SMII";
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 zmii_mode_mask(int mode, int input)
|
||||
{
|
||||
switch (mode) {
|
||||
case PHY_MODE_MII:
|
||||
return ZMII_FER_MII(input);
|
||||
case PHY_MODE_RMII:
|
||||
return ZMII_FER_RMII(input);
|
||||
case PHY_MODE_SMII:
|
||||
return ZMII_FER_SMII(input);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode)
|
||||
{
|
||||
struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
|
||||
struct zmii_regs __iomem *p;
|
||||
|
||||
ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode);
|
||||
|
||||
if (!dev) {
|
||||
dev = kzalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR
|
||||
"zmii%d: couldn't allocate device structure!\n",
|
||||
ocpdev->def->index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->mode = PHY_MODE_NA;
|
||||
|
||||
p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs));
|
||||
if (!p) {
|
||||
printk(KERN_ERR
|
||||
"zmii%d: could not ioremap device registers!\n",
|
||||
ocpdev->def->index);
|
||||
kfree(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->base = p;
|
||||
ocp_set_drvdata(ocpdev, dev);
|
||||
|
||||
/* We may need FER value for autodetection later */
|
||||
dev->fer_save = in_be32(&p->fer);
|
||||
|
||||
/* Disable all inputs by default */
|
||||
out_be32(&p->fer, 0);
|
||||
} else
|
||||
p = dev->base;
|
||||
|
||||
if (!zmii_valid_mode(*mode)) {
|
||||
/* Probably an EMAC connected to RGMII,
|
||||
* but it still may need ZMII for MDIO
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Autodetect ZMII mode if not specified.
|
||||
* This is only for backward compatibility with the old driver.
|
||||
* Please, always specify PHY mode in your board port to avoid
|
||||
* any surprises.
|
||||
*/
|
||||
if (dev->mode == PHY_MODE_NA) {
|
||||
if (*mode == PHY_MODE_NA) {
|
||||
u32 r = dev->fer_save;
|
||||
|
||||
ZMII_DBG("%d: autodetecting mode, FER = 0x%08x" NL,
|
||||
ocpdev->def->index, r);
|
||||
|
||||
if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))
|
||||
dev->mode = PHY_MODE_MII;
|
||||
else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))
|
||||
dev->mode = PHY_MODE_RMII;
|
||||
else
|
||||
dev->mode = PHY_MODE_SMII;
|
||||
} else
|
||||
dev->mode = *mode;
|
||||
|
||||
printk(KERN_NOTICE "zmii%d: bridge in %s mode\n",
|
||||
ocpdev->def->index, zmii_mode_name(dev->mode));
|
||||
} else {
|
||||
/* All inputs must use the same mode */
|
||||
if (*mode != PHY_MODE_NA && *mode != dev->mode) {
|
||||
printk(KERN_ERR
|
||||
"zmii%d: invalid mode %d specified for input %d\n",
|
||||
ocpdev->def->index, *mode, input);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report back correct PHY mode,
|
||||
* it may be used during PHY initialization.
|
||||
*/
|
||||
*mode = dev->mode;
|
||||
|
||||
/* Enable this input */
|
||||
out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));
|
||||
out:
|
||||
++dev->users;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init zmii_attach(void *emac)
|
||||
{
|
||||
struct ocp_enet_private *dev = emac;
|
||||
struct ocp_func_emac_data *emacdata = dev->def->additions;
|
||||
|
||||
if (emacdata->zmii_idx >= 0) {
|
||||
dev->zmii_input = emacdata->zmii_mux;
|
||||
dev->zmii_dev =
|
||||
ocp_find_device(OCP_VENDOR_IBM, OCP_FUNC_ZMII,
|
||||
emacdata->zmii_idx);
|
||||
if (!dev->zmii_dev) {
|
||||
printk(KERN_ERR "emac%d: unknown zmii%d!\n",
|
||||
dev->def->index, emacdata->zmii_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (zmii_init
|
||||
(dev->zmii_dev, dev->zmii_input, &emacdata->phy_mode)) {
|
||||
printk(KERN_ERR
|
||||
"emac%d: zmii%d initialization failed!\n",
|
||||
dev->def->index, emacdata->zmii_idx);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __zmii_enable_mdio(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
|
||||
u32 fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;
|
||||
|
||||
ZMII_DBG2("%d: mdio(%d)" NL, ocpdev->def->index, input);
|
||||
|
||||
out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
|
||||
}
|
||||
|
||||
void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed)
|
||||
{
|
||||
struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
|
||||
u32 ssr = in_be32(&dev->base->ssr);
|
||||
|
||||
ZMII_DBG("%d: speed(%d, %d)" NL, ocpdev->def->index, input, speed);
|
||||
|
||||
if (speed == SPEED_100)
|
||||
ssr |= ZMII_SSR_SP(input);
|
||||
else
|
||||
ssr &= ~ZMII_SSR_SP(input);
|
||||
|
||||
out_be32(&dev->base->ssr, ssr);
|
||||
}
|
||||
|
||||
void __zmii_fini(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
|
||||
BUG_ON(!dev || dev->users == 0);
|
||||
|
||||
ZMII_DBG("%d: fini(%d)" NL, ocpdev->def->index, input);
|
||||
|
||||
/* Disable this input */
|
||||
out_be32(&dev->base->fer,
|
||||
in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));
|
||||
|
||||
if (!--dev->users) {
|
||||
/* Free everything if this is the last user */
|
||||
ocp_set_drvdata(ocpdev, NULL);
|
||||
iounmap(dev->base);
|
||||
kfree(dev);
|
||||
}
|
||||
}
|
||||
|
||||
int __zmii_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return sizeof(struct emac_ethtool_regs_subhdr) +
|
||||
sizeof(struct zmii_regs);
|
||||
}
|
||||
|
||||
void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf)
|
||||
{
|
||||
struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev);
|
||||
struct emac_ethtool_regs_subhdr *hdr = buf;
|
||||
struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
|
||||
|
||||
hdr->version = 0;
|
||||
hdr->index = ocpdev->def->index;
|
||||
memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));
|
||||
return regs + 1;
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* drivers/net/ibm_emac/ibm_emac_zmii.h
|
||||
*
|
||||
* Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Zultys Technologies.
|
||||
* Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
|
||||
*
|
||||
* Based on original work by
|
||||
* Armin Kuster <akuster@mvista.com>
|
||||
* Copyright 2001 MontaVista Softare Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef _IBM_EMAC_ZMII_H_
|
||||
#define _IBM_EMAC_ZMII_H_
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/ocp.h>
|
||||
|
||||
/* ZMII bridge registers */
|
||||
struct zmii_regs {
|
||||
u32 fer; /* Function enable reg */
|
||||
u32 ssr; /* Speed select reg */
|
||||
u32 smiirs; /* SMII status reg */
|
||||
};
|
||||
|
||||
/* ZMII device */
|
||||
struct ibm_ocp_zmii {
|
||||
struct zmii_regs __iomem *base;
|
||||
int mode; /* subset of PHY_MODE_XXXX */
|
||||
int users; /* number of EMACs using this ZMII bridge */
|
||||
u32 fer_save; /* FER value left by firmware */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IBM_EMAC_ZMII
|
||||
int zmii_attach(void *emac) __init;
|
||||
|
||||
void __zmii_fini(struct ocp_device *ocpdev, int input);
|
||||
static inline void zmii_fini(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
if (ocpdev)
|
||||
__zmii_fini(ocpdev, input);
|
||||
}
|
||||
|
||||
void __zmii_enable_mdio(struct ocp_device *ocpdev, int input);
|
||||
static inline void zmii_enable_mdio(struct ocp_device *ocpdev, int input)
|
||||
{
|
||||
if (ocpdev)
|
||||
__zmii_enable_mdio(ocpdev, input);
|
||||
}
|
||||
|
||||
void __zmii_set_speed(struct ocp_device *ocpdev, int input, int speed);
|
||||
static inline void zmii_set_speed(struct ocp_device *ocpdev, int input,
|
||||
int speed)
|
||||
{
|
||||
if (ocpdev)
|
||||
__zmii_set_speed(ocpdev, input, speed);
|
||||
}
|
||||
|
||||
int __zmii_get_regs_len(struct ocp_device *ocpdev);
|
||||
static inline int zmii_get_regs_len(struct ocp_device *ocpdev)
|
||||
{
|
||||
return ocpdev ? __zmii_get_regs_len(ocpdev) : 0;
|
||||
}
|
||||
|
||||
void *zmii_dump_regs(struct ocp_device *ocpdev, void *buf);
|
||||
|
||||
#else
|
||||
# define zmii_attach(x) 0
|
||||
# define zmii_fini(x,y) ((void)0)
|
||||
# define zmii_enable_mdio(x,y) ((void)0)
|
||||
# define zmii_set_speed(x,y,z) ((void)0)
|
||||
# define zmii_get_regs_len(x) 0
|
||||
# define zmii_dump_regs(x,buf) (buf)
|
||||
#endif /* !CONFIG_IBM_EMAC_ZMII */
|
||||
|
||||
#endif /* _IBM_EMAC_ZMII_H_ */
|
Loading…
Reference in a new issue