Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
58de38a8
Commit
58de38a8
authored
May 27, 2004
by
Matt Porter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new IBM PPC4xx EMAC net driver.
parent
3d61e387
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
3884 additions
and
0 deletions
+3884
-0
drivers/net/Kconfig
drivers/net/Kconfig
+33
-0
drivers/net/Makefile
drivers/net/Makefile
+1
-0
drivers/net/ibm_emac/Makefile
drivers/net/ibm_emac/Makefile
+12
-0
drivers/net/ibm_emac/ibm_emac.h
drivers/net/ibm_emac/ibm_emac.h
+263
-0
drivers/net/ibm_emac/ibm_emac_core.c
drivers/net/ibm_emac/ibm_emac_core.c
+1968
-0
drivers/net/ibm_emac/ibm_emac_core.h
drivers/net/ibm_emac/ibm_emac_core.h
+146
-0
drivers/net/ibm_emac/ibm_emac_debug.c
drivers/net/ibm_emac/ibm_emac_debug.c
+224
-0
drivers/net/ibm_emac/ibm_emac_mal.c
drivers/net/ibm_emac/ibm_emac_mal.c
+467
-0
drivers/net/ibm_emac/ibm_emac_mal.h
drivers/net/ibm_emac/ibm_emac_mal.h
+130
-0
drivers/net/ibm_emac/ibm_emac_phy.c
drivers/net/ibm_emac/ibm_emac_phy.c
+297
-0
drivers/net/ibm_emac/ibm_emac_phy.h
drivers/net/ibm_emac/ibm_emac_phy.h
+137
-0
drivers/net/ibm_emac/ibm_emac_rgmii.h
drivers/net/ibm_emac/ibm_emac_rgmii.h
+65
-0
drivers/net/ibm_emac/ibm_emac_tah.h
drivers/net/ibm_emac/ibm_emac_tah.h
+48
-0
drivers/net/ibm_emac/ibm_emac_zmii.h
drivers/net/ibm_emac/ibm_emac_zmii.h
+93
-0
No files found.
drivers/net/Kconfig
View file @
58de38a8
...
...
@@ -1210,6 +1210,39 @@ config IBMVETH
<file:Documentation/networking/net-modules.txt>. The module will
be called ibmveth.
config IBM_EMAC
tristate "IBM PPC4xx EMAC driver support"
depends on 4xx
---help---
This driver supports the IBM PPC4xx EMAC family of on-chip
Ethernet controllers.
config IBM_EMAC_ERRMSG
bool "Verbose error messages"
depends on IBM_EMAC
config IBM_EMAC_RXB
int "Number of receive buffers"
depends on IBM_EMAC
default "128" if IBM_EMAC4
default "64"
config IBM_EMAC_TXB
int "Number of transmit buffers"
depends on IBM_EMAC
default "128" if IBM_EMAC4
default "8"
config IBM_EMAC_FGAP
int "Frame gap"
depends on IBM_EMAC
default "8"
config IBM_EMAC_SKBRES
int "Skb reserve amount"
depends on IBM_EMAC
default "0"
config NET_PCI
bool "EISA, VLB, PCI and on board controllers"
depends on NET_ETHERNET && (ISA || EISA || PCI)
...
...
drivers/net/Makefile
View file @
58de38a8
...
...
@@ -7,6 +7,7 @@ ifeq ($(CONFIG_ISDN_PPP),y)
endif
obj-$(CONFIG_E1000)
+=
e1000/
obj-$(CONFIG_IBM_EMAC)
+=
ibm_emac/
obj-$(CONFIG_IXGB)
+=
ixgb/
obj-$(CONFIG_BONDING)
+=
bonding/
...
...
drivers/net/ibm_emac/Makefile
0 → 100644
View file @
58de38a8
#
# Makefile for the IBM PPC4xx EMAC controllers
#
obj-$(CONFIG_IBM_EMAC)
+=
ibm_emac.o
ibm_emac-objs
:=
ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o
# Only need this if you want to see additional debug messages
ifeq
($(CONFIG_IBM_EMAC_ERRMSG), y)
ibm_emac-objs
+=
ibm_emac_debug.o
endif
drivers/net/ibm_emac/ibm_emac.h
0 → 100644
View file @
58de38a8
/*
* ibm_emac.h
*
*
* Armin Kuster akuster@mvista.com
* June, 2002
*
* 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_H_
#define _IBM_EMAC_H_
/* General defines needed for the driver */
/* Emac */
typedef
struct
emac_regs
{
u32
em0mr0
;
u32
em0mr1
;
u32
em0tmr0
;
u32
em0tmr1
;
u32
em0rmr
;
u32
em0isr
;
u32
em0iser
;
u32
em0iahr
;
u32
em0ialr
;
u32
em0vtpid
;
u32
em0vtci
;
u32
em0ptr
;
u32
em0iaht1
;
u32
em0iaht2
;
u32
em0iaht3
;
u32
em0iaht4
;
u32
em0gaht1
;
u32
em0gaht2
;
u32
em0gaht3
;
u32
em0gaht4
;
u32
em0lsah
;
u32
em0lsal
;
u32
em0ipgvr
;
u32
em0stacr
;
u32
em0trtr
;
u32
em0rwmr
;
}
emac_t
;
/* MODE REG 0 */
#define EMAC_M0_RXI 0x80000000
#define EMAC_M0_TXI 0x40000000
#define EMAC_M0_SRST 0x20000000
#define EMAC_M0_TXE 0x10000000
#define EMAC_M0_RXE 0x08000000
#define EMAC_M0_WKE 0x04000000
/* MODE Reg 1 */
#define EMAC_M1_FDE 0x80000000
#define EMAC_M1_ILE 0x40000000
#define EMAC_M1_VLE 0x20000000
#define EMAC_M1_EIFC 0x10000000
#define EMAC_M1_APP 0x08000000
#define EMAC_M1_AEMI 0x02000000
#define EMAC_M1_IST 0x01000000
#define EMAC_M1_MF_1000GPCS 0x00c00000
/* Internal GPCS */
#define EMAC_M1_MF_1000MBPS 0x00800000
/* External GPCS */
#define EMAC_M1_MF_100MBPS 0x00400000
#define EMAC_M1_RFS_16K 0x00280000
/* 000 for 512 byte */
#define EMAC_M1_TR 0x00008000
#ifdef CONFIG_IBM_EMAC4
#define EMAC_M1_RFS_8K 0x00200000
#define EMAC_M1_RFS_4K 0x00180000
#define EMAC_M1_RFS_2K 0x00100000
#define EMAC_M1_RFS_1K 0x00080000
#define EMAC_M1_TX_FIFO_16K 0x00050000
/* 0's for 512 byte */
#define EMAC_M1_TX_FIFO_8K 0x00040000
#define EMAC_M1_TX_FIFO_4K 0x00030000
#define EMAC_M1_TX_FIFO_2K 0x00020000
#define EMAC_M1_TX_FIFO_1K 0x00010000
#define EMAC_M1_TX_TR 0x00008000
#define EMAC_M1_TX_MWSW 0x00001000
/* 0 wait for status */
#define EMAC_M1_JUMBO_ENABLE 0x00000800
/* Upt to 9Kr status */
#define EMAC_M1_OPB_CLK_66 0x00000008
/* 66Mhz */
#define EMAC_M1_OPB_CLK_83 0x00000010
/* 83Mhz */
#define EMAC_M1_OPB_CLK_100 0x00000018
/* 100Mhz */
#define EMAC_M1_OPB_CLK_100P 0x00000020
/* 100Mhz+ */
#else
/* CONFIG_IBM_EMAC4 */
#define EMAC_M1_RFS_4K 0x00300000
/* ~4k for 512 byte */
#define EMAC_M1_RFS_2K 0x00200000
#define EMAC_M1_RFS_1K 0x00100000
#define EMAC_M1_TX_FIFO_2K 0x00080000
/* 0's for 512 byte */
#define EMAC_M1_TX_FIFO_1K 0x00040000
#define EMAC_M1_TR0_DEPEND 0x00010000
/* 0'x for single packet */
#define EMAC_M1_TR1_DEPEND 0x00004000
#define EMAC_M1_TR1_MULTI 0x00002000
#define EMAC_M1_JUMBO_ENABLE 0x00001000
#endif
/* CONFIG_IBM_EMAC4 */
#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \
EMAC_M1_APP | \
EMAC_M1_TR)
/* Transmit Mode Register 0 */
#define EMAC_TMR0_GNP0 0x80000000
#define EMAC_TMR0_GNP1 0x40000000
#define EMAC_TMR0_GNPD 0x20000000
#define EMAC_TMR0_FC 0x10000000
#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
/* Receive Mode Register */
#define EMAC_RMR_SP 0x80000000
#define EMAC_RMR_SFCS 0x40000000
#define EMAC_RMR_ARRP 0x20000000
#define EMAC_RMR_ARP 0x10000000
#define EMAC_RMR_AROP 0x08000000
#define EMAC_RMR_ARPI 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
#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_IAE | EMAC_RMR_BAE)
/* Interrupt Status & enable Regs */
#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_DBDM 0x00000200
#define EMAC_ISR_DB0 0x00000100
#define EMAC_ISR_SE0 0x00000080
#define EMAC_ISR_TE0 0x00000040
#define EMAC_ISR_DB1 0x00000020
#define EMAC_ISR_SE1 0x00000010
#define EMAC_ISR_TE1 0x00000008
#define EMAC_ISR_MOS 0x00000002
#define EMAC_ISR_MOF 0x00000001
/* STA CONTROL REG */
#define EMAC_STACR_OC 0x00008000
#define EMAC_STACR_PHYE 0x00004000
#define EMAC_STACR_WRITE 0x00002000
#define EMAC_STACR_READ 0x00001000
#define EMAC_STACR_CLK_83MHZ 0x00000800
/* 0's for 50Mhz */
#define EMAC_STACR_CLK_66MHZ 0x00000400
#define EMAC_STACR_CLK_100MHZ 0x00000C00
/* Transmit Request Threshold Register */
#define EMAC_TRTR_1600 0x18000000
/* 0's for 64 Bytes */
#define EMAC_TRTR_1024 0x0f000000
#define EMAC_TRTR_512 0x07000000
#define EMAC_TRTR_256 0x03000000
#define EMAC_TRTR_192 0x10000000
#define EMAC_TRTR_128 0x01000000
#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
/* TAH only */
#define EMAC_TX_CTRL_TAH_SEG4 0x000a
/* TAH only */
#define EMAC_TX_CTRL_TAH_SEG3 0x0008
/* TAH only */
#define EMAC_TX_CTRL_TAH_SEG2 0x0006
/* TAH only */
#define EMAC_TX_CTRL_TAH_SEG1 0x0004
/* TAH only */
#define EMAC_TX_CTRL_TAH_SEG0 0x0002
/* TAH only */
#define EMAC_TX_CTRL_TAH_DIS 0x0000
/* TAH only */
#define EMAC_TX_CTRL_DFLT ( \
MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP )
/* madmal transmit status / Control bits */
#define EMAC_TX_ST_BFCS 0x0200
#define EMAC_TX_ST_BPP 0x0100
#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
/* madmal receive status / Control bits */
#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_BAD_RX_PACKET 0x02ff
#define EMAC_CSUM_VER_ERROR 0x0003
/* identify a bad rx packet dependent on emac features */
#ifdef CONFIG_IBM_EMAC4
#define EMAC_IS_BAD_RX_PACKET(desc) \
(((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \
((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \
((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE)))
#else
#define EMAC_IS_BAD_RX_PACKET(desc) \
(desc & EMAC_BAD_RX_PACKET)
#endif
/* Revision specific EMAC register defaults */
#ifdef CONFIG_IBM_EMAC4
#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \
EMAC_M1_OPB_CLK_83 | \
EMAC_M1_TX_MWSW)
#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \
EMAC_RMR_RFAF_128_2048)
#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \
EMAC_TMR0_TFAE_128_2048)
#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024
#else
/* !CONFIG_IBM_EMAC4 */
#define EMAC_M1_DEFAULT EMAC_M1_BASE
#define EMAC_RMR_DEFAULT EMAC_RMR_BASE
#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0
#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600
#endif
/* CONFIG_IBM_EMAC4 */
/* SoC implementation specific EMAC register defaults */
#if defined(CONFIG_440GP)
#define EMAC_RWMR_DEFAULT 0x80009000
#define EMAC_TMR0_DEFAULT 0x00000000
#define EMAC_TMR1_DEFAULT 0xf8640000
#elif defined(CONFIG_440GX)
#define EMAC_RWMR_DEFAULT 0x1000a200
#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048
#define EMAC_TMR1_DEFAULT 0x88810000
#else
#define EMAC_RWMR_DEFAULT 0x0f002000
#define EMAC_TMR0_DEFAULT 0x00000000
#define EMAC_TMR1_DEFAULT 0x380f0000
#endif
/* CONFIG_440GP */
#endif
drivers/net/ibm_emac/ibm_emac_core.c
0 → 100644
View file @
58de38a8
/*
* ibm_emac_core.c
*
* Ethernet driver for the built in ethernet on the IBM 4xx PowerPC
* processors.
*
* (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
*
* Based on original work by
*
* Armin Kuster <akuster@mvista.com>
* Johnnie Peters <jpeters@mvista.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
* TODO
* - Check for races in the "remove" code path
* - Add some Power Management to the MAC and the PHY
* - Audit remaining of non-rewritten code (--BenH)
* - Cleanup message display using msglevel mecanism
* - Address all errata
* - Audit all register update paths to ensure they
* are being written post soft reset if required.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <asm/processor.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/ocp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/crc32.h>
#include "ibm_emac_core.h"
//#define MDIO_DEBUG(fmt) printk fmt
#define MDIO_DEBUG(fmt)
//#define LINK_DEBUG(fmt) printk fmt
#define LINK_DEBUG(fmt)
//#define PKT_DEBUG(fmt) printk fmt
#define PKT_DEBUG(fmt)
#define DRV_NAME "emac"
#define DRV_VERSION "2.0"
#define DRV_AUTHOR "Benjamin Herrenschmidt <benh@kernel.crashing.org>"
#define DRV_DESC "IBM EMAC Ethernet driver"
/*
* When mdio_idx >= 0, contains a list of emac ocp_devs
* that have had their initialization deferred until the
* common MDIO controller has been initialized.
*/
LIST_HEAD
(
emac_init_list
);
MODULE_AUTHOR
(
DRV_AUTHOR
);
MODULE_DESCRIPTION
(
DRV_DESC
);
MODULE_LICENSE
(
"GPL"
);
static
int
skb_res
=
SKB_RES
;
module_param
(
skb_res
,
int
,
0444
);
MODULE_PARM_DESC
(
skb_res
,
"Amount of data to reserve on skb buffs
\n
"
"The 405 handles a misaligned IP header fine but
\n
"
"this can help if you are routing to a tunnel or a
\n
"
"device that needs aligned data. 0..2"
);
#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev))
static
unsigned
int
rgmii_enable
[]
=
{
RGMII_RTBI
,
RGMII_RGMII
,
RGMII_TBI
,
RGMII_GMII
};
static
unsigned
int
rgmii_speed_mask
[]
=
{
0
,
0
,
RGMII_MII2_SPDMASK
,
RGMII_MII3_SPDMASK
};
static
unsigned
int
rgmii_speed100
[]
=
{
0
,
0
,
RGMII_MII2_100MB
,
RGMII_MII3_100MB
};
static
unsigned
int
rgmii_speed1000
[]
=
{
0
,
0
,
RGMII_MII2_1000MB
,
RGMII_MII3_1000MB
};
#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev))
static
unsigned
int
zmii_enable
[][
4
]
=
{
{
ZMII_SMII0
,
ZMII_RMII0
,
ZMII_MII0
,
~
(
ZMII_MDI1
|
ZMII_MDI2
|
ZMII_MDI3
)},
{
ZMII_SMII1
,
ZMII_RMII1
,
ZMII_MII1
,
~
(
ZMII_MDI0
|
ZMII_MDI2
|
ZMII_MDI3
)},
{
ZMII_SMII2
,
ZMII_RMII2
,
ZMII_MII2
,
~
(
ZMII_MDI0
|
ZMII_MDI1
|
ZMII_MDI3
)},
{
ZMII_SMII3
,
ZMII_RMII3
,
ZMII_MII3
,
~
(
ZMII_MDI0
|
ZMII_MDI1
|
ZMII_MDI2
)}
};
static
unsigned
int
mdi_enable
[]
=
{
ZMII_MDI0
,
ZMII_MDI1
,
ZMII_MDI2
,
ZMII_MDI3
};
static
unsigned
int
zmii_speed
=
0x0
;
static
unsigned
int
zmii_speed100
[]
=
{
ZMII_MII0_100MB
,
ZMII_MII1_100MB
};
/* Since multiple EMACs share MDIO lines in various ways, we need
* to avoid re-using the same PHY ID in cases where the arch didn't
* setup precise phy_map entries
*/
static
u32
busy_phy_map
=
0
;
/* If EMACs share a common MDIO device, this points to it */
static
struct
net_device
*
mdio_ndev
=
NULL
;
struct
emac_def_dev
{
struct
list_head
link
;
struct
ocp_device
*
ocpdev
;
struct
ibm_ocp_mal
*
mal
;
};
static
struct
net_device_stats
*
emac_stats
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
return
&
fep
->
stats
;
};
static
int
emac_init_rgmii
(
struct
ocp_device
*
rgmii_dev
,
int
input
,
int
phy_mode
)
{
struct
ibm_ocp_rgmii
*
rgmii
=
RGMII_PRIV
(
rgmii_dev
);
const
char
*
mode_name
[]
=
{
"RTBI"
,
"RGMII"
,
"TBI"
,
"GMII"
};
int
mode
=
-
1
;
if
(
!
rgmii
)
{
rgmii
=
kmalloc
(
sizeof
(
struct
ibm_ocp_rgmii
),
GFP_KERNEL
);
if
(
rgmii
==
NULL
)
{
printk
(
KERN_ERR
"rgmii%d: Out of memory allocating RGMII structure!
\n
"
,
rgmii_dev
->
def
->
index
);
return
-
ENOMEM
;
}
memset
(
rgmii
,
0
,
sizeof
(
*
rgmii
));
rgmii
->
base
=
(
struct
rgmii_regs
*
)
ioremap
(
rgmii_dev
->
def
->
paddr
,
sizeof
(
*
rgmii
->
base
));
if
(
rgmii
->
base
==
NULL
)
{
printk
(
KERN_ERR
"rgmii%d: Cannot ioremap bridge registers!
\n
"
,
rgmii_dev
->
def
->
index
);
kfree
(
rgmii
);
return
-
ENOMEM
;
}
ocp_set_drvdata
(
rgmii_dev
,
rgmii
);
}
if
(
phy_mode
)
{
switch
(
phy_mode
)
{
case
PHY_MODE_GMII
:
mode
=
GMII
;
break
;
case
PHY_MODE_TBI
:
mode
=
TBI
;
break
;
case
PHY_MODE_RTBI
:
mode
=
RTBI
;
break
;
case
PHY_MODE_RGMII
:
default:
mode
=
RGMII
;
}
rgmii
->
base
->
fer
&=
~
RGMII_FER_MASK
(
input
);
rgmii
->
base
->
fer
|=
rgmii_enable
[
mode
]
<<
(
4
*
input
);
}
else
{
switch
((
rgmii
->
base
->
fer
&
RGMII_FER_MASK
(
input
))
>>
(
4
*
input
))
{
case
RGMII_RTBI
:
mode
=
RTBI
;
break
;
case
RGMII_RGMII
:
mode
=
RGMII
;
break
;
case
RGMII_TBI
:
mode
=
TBI
;
break
;
case
RGMII_GMII
:
mode
=
GMII
;
}
}
/* Set mode to RGMII if nothing valid is detected */
if
(
mode
<
0
)
mode
=
RGMII
;
printk
(
KERN_NOTICE
"rgmii%d: input %d in %s mode
\n
"
,
rgmii_dev
->
def
->
index
,
input
,
mode_name
[
mode
]);
rgmii
->
mode
[
input
]
=
mode
;
rgmii
->
users
++
;
return
0
;
}
static
void
emac_rgmii_port_speed
(
struct
ocp_device
*
ocpdev
,
int
input
,
int
speed
)
{
struct
ibm_ocp_rgmii
*
rgmii
=
RGMII_PRIV
(
ocpdev
);
unsigned
int
rgmii_speed
;
rgmii_speed
=
in_be32
(
&
rgmii
->
base
->
ssr
);
rgmii_speed
&=
~
rgmii_speed_mask
[
input
];
if
(
speed
==
1000
)
rgmii_speed
|=
rgmii_speed1000
[
input
];
else
if
(
speed
==
100
)
rgmii_speed
|=
rgmii_speed100
[
input
];
out_be32
(
&
rgmii
->
base
->
ssr
,
rgmii_speed
);
}
static
void
emac_close_rgmii
(
struct
ocp_device
*
ocpdev
)
{
struct
ibm_ocp_rgmii
*
rgmii
=
RGMII_PRIV
(
ocpdev
);
BUG_ON
(
!
rgmii
||
rgmii
->
users
==
0
);
if
(
!--
rgmii
->
users
)
{
ocp_set_drvdata
(
ocpdev
,
NULL
);
iounmap
((
void
*
)
rgmii
->
base
);
kfree
(
rgmii
);
}
}
static
int
emac_init_zmii
(
struct
ocp_device
*
zmii_dev
,
int
input
,
int
phy_mode
)
{
struct
ibm_ocp_zmii
*
zmii
=
ZMII_PRIV
(
zmii_dev
);
const
char
*
mode_name
[]
=
{
"SMII"
,
"RMII"
,
"MII"
};
int
mode
=
-
1
;
if
(
!
zmii
)
{
zmii
=
kmalloc
(
sizeof
(
struct
ibm_ocp_zmii
),
GFP_KERNEL
);
if
(
zmii
==
NULL
)
{
printk
(
KERN_ERR
"zmii%d: Out of memory allocating ZMII structure!
\n
"
,
zmii_dev
->
def
->
index
);
return
-
ENOMEM
;
}
memset
(
zmii
,
0
,
sizeof
(
*
zmii
));
zmii
->
base
=
(
struct
zmii_regs
*
)
ioremap
(
zmii_dev
->
def
->
paddr
,
sizeof
(
*
zmii
->
base
));
if
(
zmii
->
base
==
NULL
)
{
printk
(
KERN_ERR
"zmii%d: Cannot ioremap bridge registers!
\n
"
,
zmii_dev
->
def
->
index
);
kfree
(
zmii
);
return
-
ENOMEM
;
}
ocp_set_drvdata
(
zmii_dev
,
zmii
);
}
if
(
phy_mode
)
{
switch
(
phy_mode
)
{
case
PHY_MODE_MII
:
mode
=
MII
;
break
;
case
PHY_MODE_RMII
:
mode
=
RMII
;
break
;
case
PHY_MODE_SMII
:
default:
mode
=
SMII
;
}
zmii
->
base
->
fer
&=
~
ZMII_FER_MASK
(
input
);
zmii
->
base
->
fer
|=
zmii_enable
[
input
][
mode
];
}
else
{
switch
((
zmii
->
base
->
fer
&
ZMII_FER_MASK
(
input
))
<<
(
4
*
input
))
{
case
ZMII_MII0
:
mode
=
MII
;
break
;
case
ZMII_RMII0
:
mode
=
RMII
;
break
;
case
ZMII_SMII0
:
mode
=
SMII
;
}
}
/* Set mode to SMII if nothing valid is detected */
if
(
mode
<
0
)
mode
=
SMII
;
printk
(
KERN_NOTICE
"zmii%d: input %d in %s mode
\n
"
,
zmii_dev
->
def
->
index
,
input
,
mode_name
[
mode
]);
zmii
->
mode
[
input
]
=
mode
;
zmii
->
users
++
;
return
0
;
}
static
void
emac_enable_zmii_port
(
struct
ocp_device
*
ocpdev
,
int
input
)
{
u32
mask
;
struct
ibm_ocp_zmii
*
zmii
=
ZMII_PRIV
(
ocpdev
);
mask
=
in_be32
(
&
zmii
->
base
->
fer
);
mask
&=
zmii_enable
[
input
][
MDI
];
/* turn all non enabled MDI's off */
mask
|=
zmii_enable
[
input
][
zmii
->
mode
[
input
]]
|
mdi_enable
[
input
];
out_be32
(
&
zmii
->
base
->
fer
,
mask
);
}
static
void
emac_zmii_port_speed
(
struct
ocp_device
*
ocpdev
,
int
input
,
int
speed
)
{
struct
ibm_ocp_zmii
*
zmii
=
ZMII_PRIV
(
ocpdev
);
if
(
speed
==
100
)
zmii_speed
|=
zmii_speed100
[
input
];
else
zmii_speed
&=
~
zmii_speed100
[
input
];
out_be32
(
&
zmii
->
base
->
ssr
,
zmii_speed
);
}
static
void
emac_close_zmii
(
struct
ocp_device
*
ocpdev
)
{
struct
ibm_ocp_zmii
*
zmii
=
ZMII_PRIV
(
ocpdev
);
BUG_ON
(
!
zmii
||
zmii
->
users
==
0
);
if
(
!--
zmii
->
users
)
{
ocp_set_drvdata
(
ocpdev
,
NULL
);
iounmap
((
void
*
)
zmii
->
base
);
kfree
(
zmii
);
}
}
int
emac_phy_read
(
struct
net_device
*
dev
,
int
mii_id
,
int
reg
)
{
uint32_t
stacr
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
MDIO_DEBUG
((
"%s: phy_read, id: 0x%x, reg: 0x%x
\n
"
,
dev
->
name
,
mii_id
,
reg
));
/* Enable proper ZMII port */
if
(
fep
->
zmii_dev
)
emac_enable_zmii_port
(
fep
->
zmii_dev
,
fep
->
zmii_input
);
/* Use the EMAC that has the MDIO port */
if
(
fep
->
mdio_dev
)
{
dev
=
fep
->
mdio_dev
;
fep
=
dev
->
priv
;
emacp
=
fep
->
emacp
;
}
udelay
(
MDIO_DELAY
);
if
((
in_be32
(
&
emacp
->
em0stacr
)
&
EMAC_STACR_OC
)
==
0
)
{
printk
(
KERN_WARNING
"%s: PHY read timeout #1!
\n
"
,
dev
->
name
);
return
-
1
;
}
/* Clear the speed bits and make a read request to the PHY */
stacr
=
((
EMAC_STACR_READ
|
(
reg
&
0x1f
))
&
~
EMAC_STACR_CLK_100MHZ
);
stacr
|=
((
mii_id
&
0x1F
)
<<
5
);
out_be32
(
&
emacp
->
em0stacr
,
stacr
);
udelay
(
MDIO_DELAY
);
stacr
=
in_be32
(
&
emacp
->
em0stacr
);
if
((
stacr
&
EMAC_STACR_OC
)
==
0
)
{
printk
(
KERN_WARNING
"%s: PHY read timeout #2!
\n
"
,
dev
->
name
);
return
-
1
;
}
/* Check for a read error */
if
(
stacr
&
EMAC_STACR_PHYE
)
{
MDIO_DEBUG
((
"EMAC MDIO PHY error !
\n
"
));
return
-
1
;
}
MDIO_DEBUG
((
" -> 0x%x
\n
"
,
stacr
>>
16
));
return
(
stacr
>>
16
);
}
void
emac_phy_write
(
struct
net_device
*
dev
,
int
mii_id
,
int
reg
,
int
data
)
{
uint32_t
stacr
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
MDIO_DEBUG
((
"%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x
\n
"
,
dev
->
name
,
mii_id
,
reg
,
data
));
/* Enable proper ZMII port */
if
(
fep
->
zmii_dev
)
emac_enable_zmii_port
(
fep
->
zmii_dev
,
fep
->
zmii_input
);
/* Use the EMAC that has the MDIO port */
if
(
fep
->
mdio_dev
)
{
dev
=
fep
->
mdio_dev
;
fep
=
dev
->
priv
;
emacp
=
fep
->
emacp
;
}
udelay
(
MDIO_DELAY
);
if
((
in_be32
(
&
emacp
->
em0stacr
)
&
EMAC_STACR_OC
)
==
0
)
{
printk
(
KERN_WARNING
"%s: PHY write timeout #2!
\n
"
,
dev
->
name
);
return
;
}
/* Clear the speed bits and make a read request to the PHY */
stacr
=
((
EMAC_STACR_WRITE
|
(
reg
&
0x1f
))
&
~
EMAC_STACR_CLK_100MHZ
);
stacr
|=
((
mii_id
&
0x1f
)
<<
5
)
|
((
data
&
0xffff
)
<<
16
);
out_be32
(
&
emacp
->
em0stacr
,
stacr
);
udelay
(
MDIO_DELAY
);
if
((
in_be32
(
&
emacp
->
em0stacr
)
&
EMAC_STACR_OC
)
==
0
)
printk
(
KERN_WARNING
"%s: PHY write timeout #2!
\n
"
,
dev
->
name
);
/* Check for a write error */
if
((
stacr
&
EMAC_STACR_PHYE
)
!=
0
)
{
MDIO_DEBUG
((
"EMAC MDIO PHY error !
\n
"
));
}
}
static
void
emac_txeob_dev
(
void
*
param
,
u32
chanmask
)
{
struct
net_device
*
dev
=
param
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
fep
->
lock
,
flags
);
PKT_DEBUG
((
"emac_txeob_dev() entry, tx_cnt: %d
\n
"
,
fep
->
tx_cnt
));
while
(
fep
->
tx_cnt
&&
!
(
fep
->
tx_desc
[
fep
->
ack_slot
].
ctrl
&
MAL_TX_CTRL_READY
))
{
if
(
fep
->
tx_desc
[
fep
->
ack_slot
].
ctrl
&
MAL_TX_CTRL_LAST
)
{
/* Tell the system the transmit completed. */
dma_unmap_single
(
&
fep
->
ocpdev
->
dev
,
fep
->
tx_desc
[
fep
->
ack_slot
].
data_ptr
,
fep
->
tx_desc
[
fep
->
ack_slot
].
data_len
,
DMA_TO_DEVICE
);
dev_kfree_skb_irq
(
fep
->
tx_skb
[
fep
->
ack_slot
]);
if
(
fep
->
tx_desc
[
fep
->
ack_slot
].
ctrl
&
(
EMAC_TX_ST_EC
|
EMAC_TX_ST_MC
|
EMAC_TX_ST_SC
))
fep
->
stats
.
collisions
++
;
}
fep
->
tx_skb
[
fep
->
ack_slot
]
=
(
struct
sk_buff
*
)
NULL
;
if
(
++
fep
->
ack_slot
==
NUM_TX_BUFF
)
fep
->
ack_slot
=
0
;
fep
->
tx_cnt
--
;
}
if
(
fep
->
tx_cnt
<
NUM_TX_BUFF
)
netif_wake_queue
(
dev
);
PKT_DEBUG
((
"emac_txeob_dev() exit, tx_cnt: %d
\n
"
,
fep
->
tx_cnt
));
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
}
/*
Fill/Re-fill the rx chain with valid ctrl/ptrs.
This function will fill from rx_slot up to the parm end.
So to completely fill the chain pre-set rx_slot to 0 and
pass in an end of 0.
*/
static
void
emac_rx_fill
(
struct
net_device
*
dev
,
int
end
)
{
int
i
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
i
=
fep
->
rx_slot
;
do
{
/* We don't want the 16 bytes skb_reserve done by dev_alloc_skb,
* it breaks our cache line alignement. However, we still allocate
* +16 so that we end up allocating the exact same size as
* dev_alloc_skb() would do.
* Also, because of the skb_res, the max DMA size we give to EMAC
* is slighly wrong, causing it to potentially DMA 2 more bytes
* from a broken/oversized packet. These 16 bytes will take care
* that we don't walk on somebody else toes with that.
*/
fep
->
rx_skb
[
i
]
=
alloc_skb
(
fep
->
rx_buffer_size
+
16
,
GFP_ATOMIC
);
if
(
fep
->
rx_skb
[
i
]
==
NULL
)
{
/* Keep rx_slot here, the next time clean/fill is called
* we will try again before the MAL wraps back here
* If the MAL tries to use this descriptor with
* the EMPTY bit off it will cause the
* rxde interrupt. That is where we will
* try again to allocate an sk_buff.
*/
break
;
}
if
(
skb_res
)
skb_reserve
(
fep
->
rx_skb
[
i
],
skb_res
);
/* We must NOT dma_map_single the cache line right after the
* buffer, so we must crop our sync size to account for the
* reserved space
*/
fep
->
rx_desc
[
i
].
data_ptr
=
(
unsigned
char
*
)
dma_map_single
(
&
fep
->
ocpdev
->
dev
,
(
void
*
)
fep
->
rx_skb
[
i
]
->
data
,
fep
->
rx_buffer_size
-
skb_res
,
DMA_FROM_DEVICE
);
/*
* Some 4xx implementations use the previously
* reserved bits in data_len to encode the MS
* 4-bits of a 36-bit physical address (ERPN)
* This must be initialized.
*/
fep
->
rx_desc
[
i
].
data_len
=
0
;
fep
->
rx_desc
[
i
].
ctrl
=
MAL_RX_CTRL_EMPTY
|
MAL_RX_CTRL_INTR
|
(
i
==
(
NUM_RX_BUFF
-
1
)
?
MAL_RX_CTRL_WRAP
:
0
);
}
while
((
i
=
(
i
+
1
)
%
NUM_RX_BUFF
)
!=
end
);
fep
->
rx_slot
=
i
;
}
static
void
emac_rx_csum
(
struct
net_device
*
dev
,
unsigned
short
ctrl
,
struct
sk_buff
*
skb
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
/* Exit if interface has no TAH engine */
if
(
!
fep
->
tah_dev
)
{
skb
->
ip_summed
=
CHECKSUM_NONE
;
return
;
}
/* Check for TCP/UDP/IP csum error */
if
(
ctrl
&
EMAC_CSUM_VER_ERROR
)
{
/* Let the stack verify checksum errors */
skb
->
ip_summed
=
CHECKSUM_NONE
;
/* adapter->hw_csum_err++; */
}
else
{
/* Csum is good */
skb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
/* adapter->hw_csum_good++; */
}
}
static
int
emac_rx_clean
(
struct
net_device
*
dev
)
{
int
i
,
b
,
bnum
,
buf
[
6
];
int
error
,
frame_length
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
unsigned
short
ctrl
;
i
=
fep
->
rx_slot
;
PKT_DEBUG
((
"emac_rx_clean() entry, rx_slot: %d
\n
"
,
fep
->
rx_slot
));
do
{
if
(
fep
->
rx_skb
[
i
]
==
NULL
)
continue
;
/*we have already handled the packet but haved failed to alloc */
/*
since rx_desc is in uncached mem we don't keep reading it directly
we pull out a local copy of ctrl and do the checks on the copy.
*/
ctrl
=
fep
->
rx_desc
[
i
].
ctrl
;
if
(
ctrl
&
MAL_RX_CTRL_EMPTY
)
break
;
/*we don't have any more ready packets */
if
(
EMAC_IS_BAD_RX_PACKET
(
ctrl
))
{
fep
->
stats
.
rx_errors
++
;
fep
->
stats
.
rx_dropped
++
;
if
(
ctrl
&
EMAC_RX_ST_OE
)
fep
->
stats
.
rx_fifo_errors
++
;
if
(
ctrl
&
EMAC_RX_ST_AE
)
fep
->
stats
.
rx_frame_errors
++
;
if
(
ctrl
&
EMAC_RX_ST_BFCS
)
fep
->
stats
.
rx_crc_errors
++
;
if
(
ctrl
&
(
EMAC_RX_ST_RP
|
EMAC_RX_ST_PTL
|
EMAC_RX_ST_ORE
|
EMAC_RX_ST_IRE
))
fep
->
stats
.
rx_length_errors
++
;
}
else
{
if
((
ctrl
&
(
MAL_RX_CTRL_FIRST
|
MAL_RX_CTRL_LAST
))
==
(
MAL_RX_CTRL_FIRST
|
MAL_RX_CTRL_LAST
))
{
/* Single descriptor packet */
emac_rx_csum
(
dev
,
ctrl
,
fep
->
rx_skb
[
i
]);
/* Send the skb up the chain. */
frame_length
=
fep
->
rx_desc
[
i
].
data_len
-
4
;
skb_put
(
fep
->
rx_skb
[
i
],
frame_length
);
fep
->
rx_skb
[
i
]
->
dev
=
dev
;
fep
->
rx_skb
[
i
]
->
protocol
=
eth_type_trans
(
fep
->
rx_skb
[
i
],
dev
);
error
=
netif_rx
(
fep
->
rx_skb
[
i
]);
if
((
error
==
NET_RX_DROP
)
||
(
error
==
NET_RX_BAD
))
{
fep
->
stats
.
rx_dropped
++
;
}
else
{
fep
->
stats
.
rx_packets
++
;
fep
->
stats
.
rx_bytes
+=
frame_length
;
}
fep
->
rx_skb
[
i
]
=
NULL
;
}
else
{
/* Multiple descriptor packet */
if
(
ctrl
&
MAL_RX_CTRL_FIRST
)
{
if
(
fep
->
rx_desc
[(
i
+
1
)
%
NUM_RX_BUFF
].
ctrl
&
MAL_RX_CTRL_EMPTY
)
break
;
bnum
=
0
;
buf
[
bnum
]
=
i
;
++
bnum
;
continue
;
}
if
(((
ctrl
&
MAL_RX_CTRL_FIRST
)
!=
MAL_RX_CTRL_FIRST
)
&&
((
ctrl
&
MAL_RX_CTRL_LAST
)
!=
MAL_RX_CTRL_LAST
))
{
if
(
fep
->
rx_desc
[(
i
+
1
)
%
NUM_RX_BUFF
].
ctrl
&
MAL_RX_CTRL_EMPTY
)
{
i
=
buf
[
0
];
break
;
}
buf
[
bnum
]
=
i
;
++
bnum
;
continue
;
}
if
(
ctrl
&
MAL_RX_CTRL_LAST
)
{
buf
[
bnum
]
=
i
;
++
bnum
;
skb_put
(
fep
->
rx_skb
[
buf
[
0
]],
fep
->
rx_desc
[
buf
[
0
]].
data_len
);
for
(
b
=
1
;
b
<
bnum
;
b
++
)
{
/*
* MAL is braindead, we need
* to copy the remainder
* of the packet from the
* latter descriptor buffers
* to the first skb. Then
* dispose of the source
* skbs.
*
* Once the stack is fixed
* to handle frags on most
* protocols we can generate
* a fragmented skb with
* no copies.
*/
memcpy
(
fep
->
rx_skb
[
buf
[
0
]]
->
data
+
fep
->
rx_skb
[
buf
[
0
]]
->
len
,
fep
->
rx_skb
[
buf
[
b
]]
->
data
,
fep
->
rx_desc
[
buf
[
b
]].
data_len
);
skb_put
(
fep
->
rx_skb
[
buf
[
0
]],
fep
->
rx_desc
[
buf
[
b
]].
data_len
);
dma_unmap_single
(
&
fep
->
ocpdev
->
dev
,
fep
->
rx_desc
[
buf
[
b
]].
data_ptr
,
fep
->
rx_desc
[
buf
[
b
]].
data_len
,
DMA_FROM_DEVICE
);
dev_kfree_skb
(
fep
->
rx_skb
[
buf
[
b
]]);
}
emac_rx_csum
(
dev
,
ctrl
,
fep
->
rx_skb
[
buf
[
0
]]);
fep
->
rx_skb
[
buf
[
0
]]
->
dev
=
dev
;
fep
->
rx_skb
[
buf
[
0
]]
->
protocol
=
eth_type_trans
(
fep
->
rx_skb
[
buf
[
0
]],
dev
);
error
=
netif_rx
(
fep
->
rx_skb
[
buf
[
0
]]);
if
((
error
==
NET_RX_DROP
)
||
(
error
==
NET_RX_BAD
))
{
fep
->
stats
.
rx_dropped
++
;
}
else
{
fep
->
stats
.
rx_packets
++
;
fep
->
stats
.
rx_bytes
+=
fep
->
rx_skb
[
buf
[
0
]]
->
len
;
}
for
(
b
=
0
;
b
<
bnum
;
b
++
)
fep
->
rx_skb
[
buf
[
b
]]
=
NULL
;
}
}
}
}
while
((
i
=
(
i
+
1
)
%
NUM_RX_BUFF
)
!=
fep
->
rx_slot
);
PKT_DEBUG
((
"emac_rx_clean() exit, rx_slot: %d
\n
"
,
fep
->
rx_slot
));
return
i
;
}
static
void
emac_rxeob_dev
(
void
*
param
,
u32
chanmask
)
{
struct
net_device
*
dev
=
param
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
unsigned
long
flags
;
int
n
;
spin_lock_irqsave
(
&
fep
->
lock
,
flags
);
if
((
n
=
emac_rx_clean
(
dev
))
!=
fep
->
rx_slot
)
emac_rx_fill
(
dev
,
n
);
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
}
/*
* This interrupt should never occurr, we don't program
* the MAL for contiunous mode.
*/
static
void
emac_txde_dev
(
void
*
param
,
u32
chanmask
)
{
struct
net_device
*
dev
=
param
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
printk
(
KERN_WARNING
"%s: transmit descriptor error
\n
"
,
dev
->
name
);
emac_mac_dump
(
dev
);
emac_mal_dump
(
dev
);
/* Reenable the transmit channel */
mal_enable_tx_channels
(
fep
->
mal
,
fep
->
commac
.
tx_chan_mask
);
}
/*
* This interrupt should be very rare at best. This occurs when
* the hardware has a problem with the receive descriptors. The manual
* states that it occurs when the hardware cannot the receive descriptor
* empty bit is not set. The recovery mechanism will be to
* traverse through the descriptors, handle any that are marked to be
* handled and reinitialize each along the way. At that point the driver
* will be restarted.
*/
static
void
emac_rxde_dev
(
void
*
param
,
u32
chanmask
)
{
struct
net_device
*
dev
=
param
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
unsigned
long
flags
;
if
(
net_ratelimit
())
{
printk
(
KERN_WARNING
"%s: receive descriptor error
\n
"
,
fep
->
ndev
->
name
);
emac_mac_dump
(
dev
);
emac_mal_dump
(
dev
);
emac_desc_dump
(
dev
);
}
/* Disable RX channel */
spin_lock_irqsave
(
&
fep
->
lock
,
flags
);
mal_disable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
/* For now, charge the error against all emacs */
fep
->
stats
.
rx_errors
++
;
/* so do we have any good packets still? */
emac_rx_clean
(
dev
);
/* When the interface is restarted it resets processing to the
* first descriptor in the table.
*/
fep
->
rx_slot
=
0
;
emac_rx_fill
(
dev
,
0
);
set_mal_dcrn
(
fep
->
mal
,
DCRN_MALRXEOBISR
,
fep
->
commac
.
rx_chan_mask
);
set_mal_dcrn
(
fep
->
mal
,
DCRN_MALRXDEIR
,
fep
->
commac
.
rx_chan_mask
);
/* Reenable the receive channels */
mal_enable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
}
static
irqreturn_t
emac_mac_irq
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
dev_instance
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
unsigned
long
tmp_em0isr
;
/* EMAC interrupt */
tmp_em0isr
=
in_be32
(
&
emacp
->
em0isr
);
if
(
tmp_em0isr
&
(
EMAC_ISR_TE0
|
EMAC_ISR_TE1
))
{
/* This error is a hard transmit error - could retransmit */
fep
->
stats
.
tx_errors
++
;
/* Reenable the transmit channel */
mal_enable_tx_channels
(
fep
->
mal
,
fep
->
commac
.
tx_chan_mask
);
}
else
{
fep
->
stats
.
rx_errors
++
;
}
if
(
tmp_em0isr
&
EMAC_ISR_RP
)
fep
->
stats
.
rx_length_errors
++
;
if
(
tmp_em0isr
&
EMAC_ISR_ALE
)
fep
->
stats
.
rx_frame_errors
++
;
if
(
tmp_em0isr
&
EMAC_ISR_BFCS
)
fep
->
stats
.
rx_crc_errors
++
;
if
(
tmp_em0isr
&
EMAC_ISR_PTLE
)
fep
->
stats
.
rx_length_errors
++
;
if
(
tmp_em0isr
&
EMAC_ISR_ORE
)
fep
->
stats
.
rx_length_errors
++
;
if
(
tmp_em0isr
&
EMAC_ISR_TE0
)
fep
->
stats
.
tx_aborted_errors
++
;
emac_err_dump
(
dev
,
tmp_em0isr
);
out_be32
(
&
emacp
->
em0isr
,
tmp_em0isr
);
return
IRQ_HANDLED
;
}
static
int
emac_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
unsigned
short
ctrl
;
unsigned
long
flags
;
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
int
len
=
skb
->
len
;
unsigned
int
offset
=
0
,
size
,
f
,
tx_slot_first
;
unsigned
int
nr_frags
=
skb_shinfo
(
skb
)
->
nr_frags
;
spin_lock_irqsave
(
&
fep
->
lock
,
flags
);
len
-=
skb
->
data_len
;
if
((
fep
->
tx_cnt
+
nr_frags
+
len
/
DESC_BUF_SIZE
+
1
)
>
NUM_TX_BUFF
)
{
PKT_DEBUG
((
"emac_start_xmit() stopping queue
\n
"
));
netif_stop_queue
(
dev
);
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
restore_flags
(
flags
);
return
-
EBUSY
;
}
tx_slot_first
=
fep
->
tx_slot
;
while
(
len
)
{
size
=
min
(
len
,
DESC_BUF_SIZE
);
fep
->
tx_desc
[
fep
->
tx_slot
].
data_len
=
(
short
)
size
;
fep
->
tx_desc
[
fep
->
tx_slot
].
data_ptr
=
(
unsigned
char
*
)
dma_map_single
(
&
fep
->
ocpdev
->
dev
,
(
void
*
)((
unsigned
int
)
skb
->
data
+
offset
),
size
,
DMA_TO_DEVICE
);
ctrl
=
EMAC_TX_CTRL_DFLT
;
if
(
fep
->
tx_slot
!=
tx_slot_first
)
ctrl
|=
MAL_TX_CTRL_READY
;
if
((
NUM_TX_BUFF
-
1
)
==
fep
->
tx_slot
)
ctrl
|=
MAL_TX_CTRL_WRAP
;
if
(
!
nr_frags
&&
(
len
==
size
))
{
ctrl
|=
MAL_TX_CTRL_LAST
;
fep
->
tx_skb
[
fep
->
tx_slot
]
=
skb
;
}
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
ctrl
|=
EMAC_TX_CTRL_TAH_CSUM
;
fep
->
tx_desc
[
fep
->
tx_slot
].
ctrl
=
ctrl
;
len
-=
size
;
offset
+=
size
;
/* Bump tx count */
if
(
++
fep
->
tx_cnt
==
NUM_TX_BUFF
)
netif_stop_queue
(
dev
);
/* Next descriptor */
if
(
++
fep
->
tx_slot
==
NUM_TX_BUFF
)
fep
->
tx_slot
=
0
;
}
for
(
f
=
0
;
f
<
nr_frags
;
f
++
)
{
struct
skb_frag_struct
*
frag
;
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
f
];
len
=
frag
->
size
;
offset
=
0
;
while
(
len
)
{
size
=
min
(
len
,
DESC_BUF_SIZE
);
dma_map_page
(
&
fep
->
ocpdev
->
dev
,
frag
->
page
,
frag
->
page_offset
+
offset
,
size
,
DMA_TO_DEVICE
);
ctrl
=
EMAC_TX_CTRL_DFLT
|
MAL_TX_CTRL_READY
;
if
((
NUM_TX_BUFF
-
1
)
==
fep
->
tx_slot
)
ctrl
|=
MAL_TX_CTRL_WRAP
;
if
((
f
==
(
nr_frags
-
1
))
&&
(
len
==
size
))
{
ctrl
|=
MAL_TX_CTRL_LAST
;
fep
->
tx_skb
[
fep
->
tx_slot
]
=
skb
;
}
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
ctrl
|=
EMAC_TX_CTRL_TAH_CSUM
;
fep
->
tx_desc
[
fep
->
tx_slot
].
data_len
=
(
short
)
size
;
fep
->
tx_desc
[
fep
->
tx_slot
].
data_ptr
=
(
char
*
)((
page_to_pfn
(
frag
->
page
)
<<
PAGE_SHIFT
)
+
frag
->
page_offset
+
offset
);
fep
->
tx_desc
[
fep
->
tx_slot
].
ctrl
=
ctrl
;
len
-=
size
;
offset
+=
size
;
/* Bump tx count */
if
(
++
fep
->
tx_cnt
==
NUM_TX_BUFF
)
netif_stop_queue
(
dev
);
/* Next descriptor */
if
(
++
fep
->
tx_slot
==
NUM_TX_BUFF
)
fep
->
tx_slot
=
0
;
}
}
/*
* Deferred set READY on first descriptor of packet to
* avoid TX MAL race.
*/
fep
->
tx_desc
[
tx_slot_first
].
ctrl
|=
MAL_TX_CTRL_READY
;
/* Send the packet out. */
out_be32
(
&
emacp
->
em0tmr0
,
EMAC_TMR0_XMIT
);
fep
->
stats
.
tx_packets
++
;
fep
->
stats
.
tx_bytes
+=
skb
->
len
;
PKT_DEBUG
((
"emac_start_xmit() exitn"
));
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
return
0
;
}
static
int
emac_adjust_to_link
(
struct
ocp_enet_private
*
fep
)
{
emac_t
*
emacp
=
fep
->
emacp
;
struct
ibm_ocp_rgmii
*
rgmii
;
unsigned
long
mode_reg
;
int
full_duplex
,
speed
;
full_duplex
=
0
;
speed
=
SPEED_10
;
/* set mode register 1 defaults */
mode_reg
=
EMAC_M1_DEFAULT
;
/* Read link mode on PHY */
if
(
fep
->
phy_mii
.
def
->
ops
->
read_link
(
&
fep
->
phy_mii
)
==
0
)
{
/* If an error occurred, we don't deal with it yet */
full_duplex
=
(
fep
->
phy_mii
.
duplex
==
DUPLEX_FULL
);
speed
=
fep
->
phy_mii
.
speed
;
}
if
(
fep
->
rgmii_dev
)
rgmii
=
RGMII_PRIV
(
fep
->
rgmii_dev
);
/* set speed (default is 10Mb) */
switch
(
speed
)
{
case
SPEED_1000
:
mode_reg
|=
EMAC_M1_JUMBO_ENABLE
|
EMAC_M1_RFS_16K
;
if
((
rgmii
->
mode
[
fep
->
rgmii_input
]
==
RTBI
)
||
(
rgmii
->
mode
[
fep
->
rgmii_input
]
==
TBI
))
mode_reg
|=
EMAC_M1_MF_1000GPCS
;
else
mode_reg
|=
EMAC_M1_MF_1000MBPS
;
if
(
fep
->
rgmii_dev
)
emac_rgmii_port_speed
(
fep
->
rgmii_dev
,
fep
->
rgmii_input
,
1000
);
break
;
case
SPEED_100
:
mode_reg
|=
EMAC_M1_MF_100MBPS
|
EMAC_M1_RFS_4K
;
if
(
fep
->
rgmii_dev
)
emac_rgmii_port_speed
(
fep
->
rgmii_dev
,
fep
->
rgmii_input
,
100
);
if
(
fep
->
zmii_dev
)
emac_zmii_port_speed
(
fep
->
zmii_dev
,
fep
->
zmii_input
,
100
);
break
;
case
SPEED_10
:
default:
mode_reg
=
(
mode_reg
&
~
EMAC_M1_MF_100MBPS
)
|
EMAC_M1_RFS_4K
;
if
(
fep
->
rgmii_dev
)
emac_rgmii_port_speed
(
fep
->
rgmii_dev
,
fep
->
rgmii_input
,
10
);
if
(
fep
->
zmii_dev
)
emac_zmii_port_speed
(
fep
->
zmii_dev
,
fep
->
zmii_input
,
10
);
}
if
(
full_duplex
)
mode_reg
|=
EMAC_M1_FDE
|
EMAC_M1_EIFC
|
EMAC_M1_IST
;
else
mode_reg
&=
~
(
EMAC_M1_FDE
|
EMAC_M1_EIFC
|
EMAC_M1_ILE
);
LINK_DEBUG
((
"%s: adjust to link, speed: %d, duplex: %d, opened: %d
\n
"
,
fep
->
ndev
->
name
,
speed
,
full_duplex
,
fep
->
opened
));
printk
(
KERN_INFO
"%s: Speed: %d, %s duplex.
\n
"
,
fep
->
ndev
->
name
,
speed
,
full_duplex
?
"Full"
:
"Half"
);
if
(
fep
->
opened
)
out_be32
(
&
emacp
->
em0mr1
,
mode_reg
);
return
0
;
}
static
int
emac_set_mac_address
(
struct
net_device
*
ndev
,
void
*
p
)
{
struct
ocp_enet_private
*
fep
=
ndev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
struct
sockaddr
*
addr
=
p
;
if
(
!
is_valid_ether_addr
(
addr
->
sa_data
))
return
-
EADDRNOTAVAIL
;
memcpy
(
ndev
->
dev_addr
,
addr
->
sa_data
,
ndev
->
addr_len
);
/* set the high address */
out_be32
(
&
emacp
->
em0iahr
,
(
fep
->
ndev
->
dev_addr
[
0
]
<<
8
)
|
fep
->
ndev
->
dev_addr
[
1
]);
/* set the low address */
out_be32
(
&
emacp
->
em0ialr
,
(
fep
->
ndev
->
dev_addr
[
2
]
<<
24
)
|
(
fep
->
ndev
->
dev_addr
[
3
]
<<
16
)
|
(
fep
->
ndev
->
dev_addr
[
4
]
<<
8
)
|
fep
->
ndev
->
dev_addr
[
5
]);
return
0
;
}
static
int
emac_change_mtu
(
struct
net_device
*
dev
,
int
new_mtu
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
int
old_mtu
=
dev
->
mtu
;
emac_t
*
emacp
=
fep
->
emacp
;
u32
em0mr0
;
int
i
,
full
;
unsigned
long
flags
;
if
((
new_mtu
<
EMAC_MIN_MTU
)
||
(
new_mtu
>
EMAC_MAX_MTU
))
{
printk
(
KERN_ERR
"emac: Invalid MTU setting, MTU must be between %d and %d
\n
"
,
EMAC_MIN_MTU
,
EMAC_MAX_MTU
);
return
-
EINVAL
;
}
if
(
old_mtu
!=
new_mtu
&&
netif_running
(
dev
))
{
/* Stop rx engine */
em0mr0
=
in_be32
(
&
emacp
->
em0mr0
);
out_be32
(
&
emacp
->
em0mr0
,
em0mr0
&
~
EMAC_M0_RXE
);
/* Wait for descriptors to be empty */
do
{
full
=
0
;
for
(
i
=
0
;
i
<
NUM_RX_BUFF
;
i
++
)
if
(
!
(
fep
->
rx_desc
[
i
].
ctrl
&
MAL_RX_CTRL_EMPTY
))
{
printk
(
KERN_NOTICE
"emac: RX ring is still full
\n
"
);
full
=
1
;
}
}
while
(
full
);
spin_lock_irqsave
(
&
fep
->
lock
,
flags
);
mal_disable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
/* Destroy all old rx skbs */
for
(
i
=
0
;
i
<
NUM_RX_BUFF
;
i
++
)
{
dma_unmap_single
(
&
fep
->
ocpdev
->
dev
,
fep
->
rx_desc
[
i
].
data_ptr
,
fep
->
rx_desc
[
i
].
data_len
,
DMA_FROM_DEVICE
);
dev_kfree_skb
(
fep
->
rx_skb
[
i
]);
fep
->
rx_skb
[
i
]
=
NULL
;
}
/* Set new rx_buffer_size and advertise new mtu */
fep
->
rx_buffer_size
=
new_mtu
+
ENET_HEADER_SIZE
+
ENET_FCS_SIZE
;
dev
->
mtu
=
new_mtu
;
/* Re-init rx skbs */
fep
->
rx_slot
=
0
;
emac_rx_fill
(
dev
,
0
);
/* Restart the rx engine */
mal_enable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
out_be32
(
&
emacp
->
em0mr0
,
em0mr0
|
EMAC_M0_RXE
);
spin_unlock_irqrestore
(
&
fep
->
lock
,
flags
);
}
return
0
;
}
static
void
__emac_set_multicast_list
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
u32
rmr
=
in_be32
(
&
emacp
->
em0rmr
);
/* First clear all special bits, they can be set later */
rmr
&=
~
(
EMAC_RMR_PME
|
EMAC_RMR_PMME
|
EMAC_RMR_MAE
);
if
(
dev
->
flags
&
IFF_PROMISC
)
{
rmr
|=
EMAC_RMR_PME
;
}
else
if
(
dev
->
flags
&
IFF_ALLMULTI
||
32
<
dev
->
mc_count
)
{
/*
* Must be setting up to use multicast
* Now check for promiscuous multicast
*/
rmr
|=
EMAC_RMR_PMME
;
}
else
if
(
dev
->
flags
&
IFF_MULTICAST
&&
0
<
dev
->
mc_count
)
{
unsigned
short
em0gaht
[
4
]
=
{
0
,
0
,
0
,
0
};
struct
dev_mc_list
*
dmi
;
/* Need to hash on the multicast address. */
for
(
dmi
=
dev
->
mc_list
;
dmi
;
dmi
=
dmi
->
next
)
{
unsigned
long
mc_crc
;
unsigned
int
bit_number
;
mc_crc
=
ether_crc
(
6
,
(
char
*
)
dmi
->
dmi_addr
);
bit_number
=
63
-
(
mc_crc
>>
26
);
/* MSB: 0 LSB: 63 */
em0gaht
[
bit_number
>>
4
]
|=
0x8000
>>
(
bit_number
&
0x0f
);
}
emacp
->
em0gaht1
=
em0gaht
[
0
];
emacp
->
em0gaht2
=
em0gaht
[
1
];
emacp
->
em0gaht3
=
em0gaht
[
2
];
emacp
->
em0gaht4
=
em0gaht
[
3
];
/* Turn on multicast addressing */
rmr
|=
EMAC_RMR_MAE
;
}
out_be32
(
&
emacp
->
em0rmr
,
rmr
);
}
static
int
emac_init_tah
(
struct
ocp_enet_private
*
fep
)
{
tah_t
*
tahp
;
/* Initialize TAH and enable checksum verification */
tahp
=
(
tah_t
*
)
ioremap
(
fep
->
tah_dev
->
def
->
paddr
,
sizeof
(
*
tahp
));
if
(
tahp
==
NULL
)
{
printk
(
KERN_ERR
"tah%d: Cannot ioremap TAH registers!
\n
"
,
fep
->
tah_dev
->
def
->
index
);
return
-
ENOMEM
;
}
out_be32
(
&
tahp
->
tah_mr
,
TAH_MR_SR
);
/* wait for reset to complete */
while
(
in_be32
(
&
tahp
->
tah_mr
)
&
TAH_MR_SR
)
;
/* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
out_be32
(
&
tahp
->
tah_mr
,
TAH_MR_CVR
|
TAH_MR_ST_768
|
TAH_MR_TFS_10KB
|
TAH_MR_DTFP
|
TAH_MR_DIG
);
iounmap
(
&
tahp
);
return
0
;
}
static
void
emac_init_rings
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
ep
=
dev
->
priv
;
int
loop
;
ep
->
tx_desc
=
(
struct
mal_descriptor
*
)((
char
*
)
ep
->
mal
->
tx_virt_addr
+
(
ep
->
mal_tx_chan
*
MAL_DT_ALIGN
));
ep
->
rx_desc
=
(
struct
mal_descriptor
*
)((
char
*
)
ep
->
mal
->
rx_virt_addr
+
(
ep
->
mal_rx_chan
*
MAL_DT_ALIGN
));
/* Fill in the transmit descriptor ring. */
for
(
loop
=
0
;
loop
<
NUM_TX_BUFF
;
loop
++
)
{
if
(
ep
->
tx_skb
[
loop
])
{
dma_unmap_single
(
&
ep
->
ocpdev
->
dev
,
ep
->
tx_desc
[
loop
].
data_ptr
,
ep
->
tx_desc
[
loop
].
data_len
,
DMA_TO_DEVICE
);
dev_kfree_skb_irq
(
ep
->
tx_skb
[
loop
]);
}
ep
->
tx_skb
[
loop
]
=
NULL
;
ep
->
tx_desc
[
loop
].
ctrl
=
0
;
ep
->
tx_desc
[
loop
].
data_len
=
0
;
ep
->
tx_desc
[
loop
].
data_ptr
=
NULL
;
}
ep
->
tx_desc
[
loop
-
1
].
ctrl
|=
MAL_TX_CTRL_WRAP
;
/* Format the receive descriptor ring. */
ep
->
rx_slot
=
0
;
/* Default is MTU=1500 + Ethernet overhead */
ep
->
rx_buffer_size
=
ENET_DEF_BUF_SIZE
;
emac_rx_fill
(
dev
,
0
);
if
(
ep
->
rx_slot
!=
0
)
{
printk
(
KERN_ERR
"%s: Not enough mem for RxChain durning Open?
\n
"
,
dev
->
name
);
/*We couldn't fill the ring at startup?
*We could clean up and fail to open but right now we will try to
*carry on. It may be a sign of a bad NUM_RX_BUFF value
*/
}
ep
->
tx_cnt
=
0
;
ep
->
tx_slot
=
0
;
ep
->
ack_slot
=
0
;
}
static
void
emac_reset_configure
(
struct
ocp_enet_private
*
fep
)
{
emac_t
*
emacp
=
fep
->
emacp
;
int
i
;
mal_disable_tx_channels
(
fep
->
mal
,
fep
->
commac
.
tx_chan_mask
);
mal_disable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
/*
* Check for a link, some PHYs don't provide a clock if
* no link is present. Some EMACs will not come out of
* soft reset without a PHY clock present.
*/
if
(
fep
->
phy_mii
.
def
->
ops
->
poll_link
(
&
fep
->
phy_mii
))
{
/* Reset the EMAC */
out_be32
(
&
emacp
->
em0mr0
,
EMAC_M0_SRST
);
udelay
(
20
);
for
(
i
=
0
;
i
<
100
;
i
++
)
{
if
((
in_be32
(
&
emacp
->
em0mr0
)
&
EMAC_M0_SRST
)
==
0
)
break
;
udelay
(
10
);
}
if
(
i
>=
100
)
{
printk
(
KERN_ERR
"%s: Cannot reset EMAC
\n
"
,
fep
->
ndev
->
name
);
return
;
}
}
/* Switch IRQs off for now */
out_be32
(
&
emacp
->
em0iser
,
0
);
/* Configure MAL rx channel */
mal_set_rcbs
(
fep
->
mal
,
fep
->
mal_rx_chan
,
DESC_BUF_SIZE_REG
);
/* set the high address */
out_be32
(
&
emacp
->
em0iahr
,
(
fep
->
ndev
->
dev_addr
[
0
]
<<
8
)
|
fep
->
ndev
->
dev_addr
[
1
]);
/* set the low address */
out_be32
(
&
emacp
->
em0ialr
,
(
fep
->
ndev
->
dev_addr
[
2
]
<<
24
)
|
(
fep
->
ndev
->
dev_addr
[
3
]
<<
16
)
|
(
fep
->
ndev
->
dev_addr
[
4
]
<<
8
)
|
fep
->
ndev
->
dev_addr
[
5
]);
/* Adjust to link */
if
(
netif_carrier_ok
(
fep
->
ndev
))
emac_adjust_to_link
(
fep
);
/* enable broadcast/individual address and RX FIFO defaults */
out_be32
(
&
emacp
->
em0rmr
,
EMAC_RMR_DEFAULT
);
/* set transmit request threshold register */
out_be32
(
&
emacp
->
em0trtr
,
EMAC_TRTR_DEFAULT
);
/* Reconfigure multicast */
__emac_set_multicast_list
(
fep
->
ndev
);
/* Set receiver/transmitter defaults */
out_be32
(
&
emacp
->
em0rwmr
,
EMAC_RWMR_DEFAULT
);
out_be32
(
&
emacp
->
em0tmr0
,
EMAC_TMR0_DEFAULT
);
out_be32
(
&
emacp
->
em0tmr1
,
EMAC_TMR1_DEFAULT
);
/* set frame gap */
out_be32
(
&
emacp
->
em0ipgvr
,
CONFIG_IBM_EMAC_FGAP
);
/* Init ring buffers */
emac_init_rings
(
fep
->
ndev
);
}
static
void
emac_kick
(
struct
ocp_enet_private
*
fep
)
{
emac_t
*
emacp
=
fep
->
emacp
;
unsigned
long
emac_ier
;
emac_ier
=
EMAC_ISR_PP
|
EMAC_ISR_BP
|
EMAC_ISR_RP
|
EMAC_ISR_SE
|
EMAC_ISR_PTLE
|
EMAC_ISR_ALE
|
EMAC_ISR_BFCS
|
EMAC_ISR_ORE
|
EMAC_ISR_IRE
;
out_be32
(
&
emacp
->
em0iser
,
emac_ier
);
/* enable all MAL transmit and receive channels */
mal_enable_tx_channels
(
fep
->
mal
,
fep
->
commac
.
tx_chan_mask
);
mal_enable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
/* set transmit and receive enable */
out_be32
(
&
emacp
->
em0mr0
,
EMAC_M0_TXE
|
EMAC_M0_RXE
);
}
static
void
emac_start_link
(
struct
ocp_enet_private
*
fep
,
struct
ethtool_cmd
*
ep
)
{
u32
advertise
;
int
autoneg
;
int
forced_speed
;
int
forced_duplex
;
/* Default advertise */
advertise
=
ADVERTISED_10baseT_Half
|
ADVERTISED_10baseT_Full
|
ADVERTISED_100baseT_Half
|
ADVERTISED_100baseT_Full
|
ADVERTISED_1000baseT_Half
|
ADVERTISED_1000baseT_Full
;
autoneg
=
fep
->
want_autoneg
;
forced_speed
=
fep
->
phy_mii
.
speed
;
forced_duplex
=
fep
->
phy_mii
.
duplex
;
/* Setup link parameters */
if
(
ep
)
{
if
(
ep
->
autoneg
==
AUTONEG_ENABLE
)
{
advertise
=
ep
->
advertising
;
autoneg
=
1
;
}
else
{
autoneg
=
0
;
forced_speed
=
ep
->
speed
;
forced_duplex
=
ep
->
duplex
;
}
}
/* Configure PHY & start aneg */
fep
->
want_autoneg
=
autoneg
;
if
(
autoneg
)
{
LINK_DEBUG
((
"%s: start link aneg, advertise: 0x%x
\n
"
,
fep
->
ndev
->
name
,
advertise
));
fep
->
phy_mii
.
def
->
ops
->
setup_aneg
(
&
fep
->
phy_mii
,
advertise
);
}
else
{
LINK_DEBUG
((
"%s: start link forced, speed: %d, duplex: %d
\n
"
,
fep
->
ndev
->
name
,
forced_speed
,
forced_duplex
));
fep
->
phy_mii
.
def
->
ops
->
setup_forced
(
&
fep
->
phy_mii
,
forced_speed
,
forced_duplex
);
}
fep
->
timer_ticks
=
0
;
mod_timer
(
&
fep
->
link_timer
,
jiffies
+
HZ
);
}
static
void
emac_link_timer
(
unsigned
long
data
)
{
struct
ocp_enet_private
*
fep
=
(
struct
ocp_enet_private
*
)
data
;
int
link
;
if
(
fep
->
going_away
)
return
;
spin_lock_irq
(
&
fep
->
lock
);
link
=
fep
->
phy_mii
.
def
->
ops
->
poll_link
(
&
fep
->
phy_mii
);
LINK_DEBUG
((
"%s: poll_link: %d
\n
"
,
fep
->
ndev
->
name
,
link
));
if
(
link
==
netif_carrier_ok
(
fep
->
ndev
))
{
if
(
!
link
&&
fep
->
want_autoneg
&&
(
++
fep
->
timer_ticks
)
>
10
)
emac_start_link
(
fep
,
NULL
);
goto
out
;
}
printk
(
KERN_INFO
"%s: Link is %s
\n
"
,
fep
->
ndev
->
name
,
link
?
"Up"
:
"Down"
);
if
(
link
)
{
netif_carrier_on
(
fep
->
ndev
);
/* Chip needs a full reset on config change. That sucks, so I
* should ultimately move that to some tasklet to limit
* latency peaks caused by this code
*/
emac_reset_configure
(
fep
);
if
(
fep
->
opened
)
emac_kick
(
fep
);
}
else
{
fep
->
timer_ticks
=
0
;
netif_carrier_off
(
fep
->
ndev
);
}
out:
mod_timer
(
&
fep
->
link_timer
,
jiffies
+
HZ
);
spin_unlock_irq
(
&
fep
->
lock
);
}
static
void
emac_set_multicast_list
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
spin_lock_irq
(
&
fep
->
lock
);
__emac_set_multicast_list
(
dev
);
spin_unlock_irq
(
&
fep
->
lock
);
}
static
int
emac_get_settings
(
struct
net_device
*
ndev
,
struct
ethtool_cmd
*
cmd
)
{
struct
ocp_enet_private
*
fep
=
ndev
->
priv
;
cmd
->
supported
=
fep
->
phy_mii
.
def
->
features
;
cmd
->
port
=
PORT_MII
;
cmd
->
transceiver
=
XCVR_EXTERNAL
;
cmd
->
phy_address
=
fep
->
mii_phy_addr
;
spin_lock_irq
(
&
fep
->
lock
);
cmd
->
autoneg
=
fep
->
want_autoneg
;
cmd
->
speed
=
fep
->
phy_mii
.
speed
;
cmd
->
duplex
=
fep
->
phy_mii
.
duplex
;
spin_unlock_irq
(
&
fep
->
lock
);
return
0
;
}
static
int
emac_set_settings
(
struct
net_device
*
ndev
,
struct
ethtool_cmd
*
cmd
)
{
struct
ocp_enet_private
*
fep
=
ndev
->
priv
;
unsigned
long
features
=
fep
->
phy_mii
.
def
->
features
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
cmd
->
autoneg
!=
AUTONEG_ENABLE
&&
cmd
->
autoneg
!=
AUTONEG_DISABLE
)
return
-
EINVAL
;
if
(
cmd
->
autoneg
==
AUTONEG_ENABLE
&&
cmd
->
advertising
==
0
)
return
-
EINVAL
;
if
(
cmd
->
duplex
!=
DUPLEX_HALF
&&
cmd
->
duplex
!=
DUPLEX_FULL
)
return
-
EINVAL
;
if
(
cmd
->
autoneg
==
AUTONEG_DISABLE
)
switch
(
cmd
->
speed
)
{
case
SPEED_10
:
if
(
cmd
->
duplex
==
DUPLEX_HALF
&&
(
features
&
SUPPORTED_10baseT_Half
)
==
0
)
return
-
EINVAL
;
if
(
cmd
->
duplex
==
DUPLEX_FULL
&&
(
features
&
SUPPORTED_10baseT_Full
)
==
0
)
return
-
EINVAL
;
break
;
case
SPEED_100
:
if
(
cmd
->
duplex
==
DUPLEX_HALF
&&
(
features
&
SUPPORTED_100baseT_Half
)
==
0
)
return
-
EINVAL
;
if
(
cmd
->
duplex
==
DUPLEX_FULL
&&
(
features
&
SUPPORTED_100baseT_Full
)
==
0
)
return
-
EINVAL
;
break
;
case
SPEED_1000
:
if
(
cmd
->
duplex
==
DUPLEX_HALF
&&
(
features
&
SUPPORTED_1000baseT_Half
)
==
0
)
return
-
EINVAL
;
if
(
cmd
->
duplex
==
DUPLEX_FULL
&&
(
features
&
SUPPORTED_1000baseT_Full
)
==
0
)
return
-
EINVAL
;
break
;
default:
return
-
EINVAL
;
}
else
if
((
features
&
SUPPORTED_Autoneg
)
==
0
)
return
-
EINVAL
;
spin_lock_irq
(
&
fep
->
lock
);
emac_start_link
(
fep
,
cmd
);
spin_unlock_irq
(
&
fep
->
lock
);
return
0
;
}
static
void
emac_get_drvinfo
(
struct
net_device
*
ndev
,
struct
ethtool_drvinfo
*
info
)
{
struct
ocp_enet_private
*
fep
=
ndev
->
priv
;
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
version
,
DRV_VERSION
);
info
->
fw_version
[
0
]
=
'\0'
;
sprintf
(
info
->
bus_info
,
"IBM EMAC %d"
,
fep
->
ocpdev
->
def
->
index
);
info
->
regdump_len
=
0
;
}
static
int
emac_nway_reset
(
struct
net_device
*
ndev
)
{
struct
ocp_enet_private
*
fep
=
ndev
->
priv
;
if
(
!
fep
->
want_autoneg
)
return
-
EINVAL
;
spin_lock_irq
(
&
fep
->
lock
);
emac_start_link
(
fep
,
NULL
);
spin_unlock_irq
(
&
fep
->
lock
);
return
0
;
}
static
u32
emac_get_link
(
struct
net_device
*
ndev
)
{
return
netif_carrier_ok
(
ndev
);
}
static
struct
ethtool_ops
emac_ethtool_ops
=
{
.
get_settings
=
emac_get_settings
,
.
set_settings
=
emac_set_settings
,
.
get_drvinfo
=
emac_get_drvinfo
,
.
nway_reset
=
emac_nway_reset
,
.
get_link
=
emac_get_link
};
static
int
emac_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
uint
*
data
=
(
uint
*
)
&
rq
->
ifr_data
;
switch
(
cmd
)
{
case
SIOCGMIIPHY
:
data
[
0
]
=
fep
->
mii_phy_addr
;
/* Fall through */
case
SIOCGMIIREG
:
data
[
3
]
=
emac_phy_read
(
dev
,
fep
->
mii_phy_addr
,
data
[
1
]);
return
0
;
case
SIOCSMIIREG
:
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
emac_phy_write
(
dev
,
fep
->
mii_phy_addr
,
data
[
1
],
data
[
2
]);
return
0
;
default:
return
-
EOPNOTSUPP
;
}
}
static
int
emac_open
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
int
rc
;
spin_lock_irq
(
&
fep
->
lock
);
fep
->
opened
=
1
;
netif_carrier_off
(
dev
);
/* Reset & configure the chip */
emac_reset_configure
(
fep
);
spin_unlock_irq
(
&
fep
->
lock
);
/* Request our interrupt lines */
rc
=
request_irq
(
dev
->
irq
,
emac_mac_irq
,
0
,
"IBM EMAC MAC"
,
dev
);
if
(
rc
!=
0
)
{
printk
(
"dev->irq %d failed
\n
"
,
dev
->
irq
);
goto
bail
;
}
/* Kick the chip rx & tx channels into life */
spin_lock_irq
(
&
fep
->
lock
);
emac_kick
(
fep
);
spin_unlock_irq
(
&
fep
->
lock
);
netif_start_queue
(
dev
);
bail:
return
rc
;
}
static
int
emac_close
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
emac_t
*
emacp
=
fep
->
emacp
;
/* XXX Stop IRQ emitting here */
spin_lock_irq
(
&
fep
->
lock
);
fep
->
opened
=
0
;
mal_disable_tx_channels
(
fep
->
mal
,
fep
->
commac
.
tx_chan_mask
);
mal_disable_rx_channels
(
fep
->
mal
,
fep
->
commac
.
rx_chan_mask
);
netif_carrier_off
(
dev
);
netif_stop_queue
(
dev
);
/*
* Check for a link, some PHYs don't provide a clock if
* no link is present. Some EMACs will not come out of
* soft reset without a PHY clock present.
*/
if
(
fep
->
phy_mii
.
def
->
ops
->
poll_link
(
&
fep
->
phy_mii
))
{
out_be32
(
&
emacp
->
em0mr0
,
EMAC_M0_SRST
);
udelay
(
10
);
if
(
emacp
->
em0mr0
&
EMAC_M0_SRST
)
{
/*not sure what to do here hopefully it clears before another open */
printk
(
KERN_ERR
"%s: Phy SoftReset didn't clear, no link?
\n
"
,
dev
->
name
);
}
}
/* Free the irq's */
free_irq
(
dev
->
irq
,
dev
);
spin_unlock_irq
(
&
fep
->
lock
);
return
0
;
}
static
void
emac_remove
(
struct
ocp_device
*
ocpdev
)
{
struct
net_device
*
dev
=
ocp_get_drvdata
(
ocpdev
);
struct
ocp_enet_private
*
ep
=
dev
->
priv
;
/* FIXME: locking, races, ... */
ep
->
going_away
=
1
;
ocp_set_drvdata
(
ocpdev
,
NULL
);
if
(
ep
->
rgmii_dev
)
emac_close_rgmii
(
ep
->
rgmii_dev
);
if
(
ep
->
zmii_dev
)
emac_close_zmii
(
ep
->
zmii_dev
);
unregister_netdev
(
dev
);
del_timer_sync
(
&
ep
->
link_timer
);
mal_unregister_commac
(
ep
->
mal
,
&
ep
->
commac
);
iounmap
((
void
*
)
ep
->
emacp
);
kfree
(
dev
);
}
struct
mal_commac_ops
emac_commac_ops
=
{
.
txeob
=
&
emac_txeob_dev
,
.
txde
=
&
emac_txde_dev
,
.
rxeob
=
&
emac_rxeob_dev
,
.
rxde
=
&
emac_rxde_dev
,
};
static
int
emac_init_device
(
struct
ocp_device
*
ocpdev
,
struct
ibm_ocp_mal
*
mal
)
{
int
deferred_init
=
0
;
int
rc
=
0
,
i
;
struct
net_device
*
ndev
;
struct
ocp_enet_private
*
ep
;
struct
ocp_func_emac_data
*
emacdata
;
int
commac_reg
=
0
;
u32
phy_map
;
emacdata
=
(
struct
ocp_func_emac_data
*
)
ocpdev
->
def
->
additions
;
if
(
!
emacdata
)
{
printk
(
KERN_ERR
"emac%d: Missing additional data!
\n
"
,
ocpdev
->
def
->
index
);
return
-
ENODEV
;
}
/* Allocate our net_device structure */
ndev
=
alloc_etherdev
(
sizeof
(
struct
ocp_enet_private
));
if
(
ndev
==
NULL
)
{
printk
(
KERN_ERR
"emac%d: Could not allocate ethernet device.
\n
"
,
ocpdev
->
def
->
index
);
return
-
ENOMEM
;
}
ep
=
ndev
->
priv
;
ep
->
ndev
=
ndev
;
ep
->
ocpdev
=
ocpdev
;
ndev
->
irq
=
ocpdev
->
def
->
irq
;
ep
->
wol_irq
=
emacdata
->
wol_irq
;
if
(
emacdata
->
mdio_idx
>=
0
)
{
if
(
emacdata
->
mdio_idx
==
ocpdev
->
def
->
index
)
{
/* Set the common MDIO net_device */
mdio_ndev
=
ndev
;
deferred_init
=
1
;
}
ep
->
mdio_dev
=
mdio_ndev
;
}
else
{
ep
->
mdio_dev
=
ndev
;
}
ocp_set_drvdata
(
ocpdev
,
ndev
);
spin_lock_init
(
&
ep
->
lock
);
/* Fill out MAL informations and register commac */
ep
->
mal
=
mal
;
ep
->
mal_tx_chan
=
emacdata
->
mal_tx_chan
;
ep
->
mal_rx_chan
=
emacdata
->
mal_rx_chan
;
ep
->
commac
.
ops
=
&
emac_commac_ops
;
ep
->
commac
.
dev
=
ndev
;
ep
->
commac
.
tx_chan_mask
=
MAL_CHAN_MASK
(
ep
->
mal_tx_chan
);
ep
->
commac
.
rx_chan_mask
=
MAL_CHAN_MASK
(
ep
->
mal_rx_chan
);
rc
=
mal_register_commac
(
ep
->
mal
,
&
ep
->
commac
);
if
(
rc
!=
0
)
goto
bail
;
commac_reg
=
1
;
/* Map our MMIOs */
ep
->
emacp
=
(
emac_t
*
)
ioremap
(
ocpdev
->
def
->
paddr
,
sizeof
(
emac_t
));
/* Check if we need to attach to a ZMII */
if
(
emacdata
->
zmii_idx
>=
0
)
{
ep
->
zmii_input
=
emacdata
->
zmii_mux
;
ep
->
zmii_dev
=
ocp_find_device
(
OCP_ANY_ID
,
OCP_FUNC_ZMII
,
emacdata
->
zmii_idx
);
if
(
ep
->
zmii_dev
==
NULL
)
printk
(
KERN_WARNING
"emac%d: ZMII %d requested but not found !
\n
"
,
ocpdev
->
def
->
index
,
emacdata
->
zmii_idx
);
else
if
((
rc
=
emac_init_zmii
(
ep
->
zmii_dev
,
ep
->
zmii_input
,
emacdata
->
phy_mode
))
!=
0
)
goto
bail
;
}
/* Check if we need to attach to a RGMII */
if
(
emacdata
->
rgmii_idx
>=
0
)
{
ep
->
rgmii_input
=
emacdata
->
rgmii_mux
;
ep
->
rgmii_dev
=
ocp_find_device
(
OCP_ANY_ID
,
OCP_FUNC_RGMII
,
emacdata
->
rgmii_idx
);
if
(
ep
->
rgmii_dev
==
NULL
)
printk
(
KERN_WARNING
"emac%d: RGMII %d requested but not found !
\n
"
,
ocpdev
->
def
->
index
,
emacdata
->
rgmii_idx
);
else
if
((
rc
=
emac_init_rgmii
(
ep
->
rgmii_dev
,
ep
->
rgmii_input
,
emacdata
->
phy_mode
))
!=
0
)
goto
bail
;
}
/* Check if we need to attach to a TAH */
if
(
emacdata
->
tah_idx
>=
0
)
{
ep
->
tah_dev
=
ocp_find_device
(
OCP_ANY_ID
,
OCP_FUNC_TAH
,
emacdata
->
tah_idx
);
if
(
ep
->
tah_dev
==
NULL
)
printk
(
KERN_WARNING
"emac%d: TAH %d requested but not found !
\n
"
,
ocpdev
->
def
->
index
,
emacdata
->
tah_idx
);
else
if
((
rc
=
emac_init_tah
(
ep
))
!=
0
)
goto
bail
;
}
if
(
deferred_init
)
{
if
(
!
list_empty
(
&
emac_init_list
))
{
struct
list_head
*
entry
;
struct
emac_def_dev
*
ddev
;
list_for_each
(
entry
,
&
emac_init_list
)
{
ddev
=
list_entry
(
entry
,
struct
emac_def_dev
,
link
);
emac_init_device
(
ddev
->
ocpdev
,
ddev
->
mal
);
}
}
}
/* Init link monitoring timer */
init_timer
(
&
ep
->
link_timer
);
ep
->
link_timer
.
function
=
emac_link_timer
;
ep
->
link_timer
.
data
=
(
unsigned
long
)
ep
;
ep
->
timer_ticks
=
0
;
/* Fill up the mii_phy structure */
ep
->
phy_mii
.
dev
=
ndev
;
ep
->
phy_mii
.
mdio_read
=
emac_phy_read
;
ep
->
phy_mii
.
mdio_write
=
emac_phy_write
;
ep
->
phy_mii
.
mode
=
emacdata
->
phy_mode
;
/* Find PHY */
phy_map
=
emacdata
->
phy_map
|
busy_phy_map
;
for
(
i
=
0
;
i
<=
0x1f
;
i
++
,
phy_map
>>=
1
)
{
if
((
phy_map
&
0x1
)
==
0
)
{
int
val
=
emac_phy_read
(
ndev
,
i
,
MII_BMCR
);
if
(
val
!=
0xffff
&&
val
!=
-
1
)
break
;
}
}
if
(
i
==
0x20
)
{
printk
(
KERN_WARNING
"emac%d: Can't find PHY.
\n
"
,
ocpdev
->
def
->
index
);
rc
=
-
ENODEV
;
goto
bail
;
}
busy_phy_map
|=
1
<<
i
;
ep
->
mii_phy_addr
=
i
;
rc
=
mii_phy_probe
(
&
ep
->
phy_mii
,
i
);
if
(
rc
)
{
printk
(
KERN_WARNING
"emac%d: Failed to probe PHY type.
\n
"
,
ocpdev
->
def
->
index
);
rc
=
-
ENODEV
;
goto
bail
;
}
/* Setup initial PHY config & startup aneg */
if
(
ep
->
phy_mii
.
def
->
ops
->
init
)
ep
->
phy_mii
.
def
->
ops
->
init
(
&
ep
->
phy_mii
);
netif_carrier_off
(
ndev
);
if
(
ep
->
phy_mii
.
def
->
features
&
SUPPORTED_Autoneg
)
ep
->
want_autoneg
=
1
;
emac_start_link
(
ep
,
NULL
);
/* read the MAC Address */
for
(
i
=
0
;
i
<
6
;
i
++
)
ndev
->
dev_addr
[
i
]
=
emacdata
->
mac_addr
[
i
];
/* Fill in the driver function table */
ndev
->
open
=
&
emac_open
;
ndev
->
hard_start_xmit
=
&
emac_start_xmit
;
ndev
->
stop
=
&
emac_close
;
ndev
->
get_stats
=
&
emac_stats
;
if
(
emacdata
->
jumbo
)
ndev
->
change_mtu
=
&
emac_change_mtu
;
ndev
->
set_mac_address
=
&
emac_set_mac_address
;
ndev
->
set_multicast_list
=
&
emac_set_multicast_list
;
ndev
->
do_ioctl
=
&
emac_ioctl
;
SET_ETHTOOL_OPS
(
ndev
,
&
emac_ethtool_ops
);
if
(
emacdata
->
tah_idx
>=
0
)
ndev
->
features
=
NETIF_F_IP_CSUM
|
NETIF_F_SG
;
SET_MODULE_OWNER
(
ndev
);
rc
=
register_netdev
(
ndev
);
if
(
rc
!=
0
)
goto
bail
;
printk
(
"%s: IBM emac, MAC %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
ndev
->
name
,
ndev
->
dev_addr
[
0
],
ndev
->
dev_addr
[
1
],
ndev
->
dev_addr
[
2
],
ndev
->
dev_addr
[
3
],
ndev
->
dev_addr
[
4
],
ndev
->
dev_addr
[
5
]);
printk
(
KERN_INFO
"%s: Found %s PHY (0x%02x)
\n
"
,
ndev
->
name
,
ep
->
phy_mii
.
def
->
name
,
ep
->
mii_phy_addr
);
bail:
if
(
rc
&&
commac_reg
)
mal_unregister_commac
(
ep
->
mal
,
&
ep
->
commac
);
if
(
rc
&&
ndev
)
kfree
(
ndev
);
return
rc
;
}
static
int
emac_probe
(
struct
ocp_device
*
ocpdev
)
{
struct
ocp_device
*
maldev
;
struct
ibm_ocp_mal
*
mal
;
struct
ocp_func_emac_data
*
emacdata
;
emacdata
=
(
struct
ocp_func_emac_data
*
)
ocpdev
->
def
->
additions
;
if
(
emacdata
==
NULL
)
{
printk
(
KERN_ERR
"emac%d: Missing additional datas !
\n
"
,
ocpdev
->
def
->
index
);
return
-
ENODEV
;
}
/* Get the MAL device */
maldev
=
ocp_find_device
(
OCP_ANY_ID
,
OCP_FUNC_MAL
,
emacdata
->
mal_idx
);
if
(
maldev
==
NULL
)
{
printk
(
"No maldev
\n
"
);
return
-
ENODEV
;
}
/*
* Get MAL driver data, it must be here due to link order.
* When the driver is modularized, symbol dependencies will
* ensure the MAL driver is already present if built as a
* module.
*/
mal
=
(
struct
ibm_ocp_mal
*
)
ocp_get_drvdata
(
maldev
);
if
(
mal
==
NULL
)
{
printk
(
"No maldrv
\n
"
);
return
-
ENODEV
;
}
/* If we depend on another EMAC for MDIO, wait for it to show up */
if
(
emacdata
->
mdio_idx
>=
0
&&
(
emacdata
->
mdio_idx
!=
ocpdev
->
def
->
index
)
&&
!
mdio_ndev
)
{
struct
emac_def_dev
*
ddev
;
/* Add this index to the deferred init table */
ddev
=
kmalloc
(
sizeof
(
struct
emac_def_dev
),
GFP_KERNEL
);
ddev
->
ocpdev
=
ocpdev
;
ddev
->
mal
=
mal
;
list_add_tail
(
&
ddev
->
link
,
&
emac_init_list
);
}
else
{
emac_init_device
(
ocpdev
,
mal
);
}
return
0
;
}
/* Structure for a device driver */
static
struct
ocp_device_id
emac_ids
[]
=
{
{.
vendor
=
OCP_ANY_ID
,.
function
=
OCP_FUNC_EMAC
},
{.
vendor
=
OCP_VENDOR_INVALID
}
};
static
struct
ocp_driver
emac_driver
=
{
.
name
=
"emac"
,
.
id_table
=
emac_ids
,
.
probe
=
emac_probe
,
.
remove
=
emac_remove
,
};
static
int
__init
emac_init
(
void
)
{
int
rc
;
printk
(
KERN_INFO
DRV_NAME
": "
DRV_DESC
", version "
DRV_VERSION
"
\n
"
);
printk
(
KERN_INFO
"Maintained by "
DRV_AUTHOR
"
\n
"
);
if
(
skb_res
>
2
)
{
printk
(
KERN_WARNING
"Invalid skb_res: %d, cropping to 2
\n
"
,
skb_res
);
skb_res
=
2
;
}
rc
=
ocp_register_driver
(
&
emac_driver
);
if
(
rc
<
0
)
{
ocp_unregister_driver
(
&
emac_driver
);
return
-
ENODEV
;
}
return
0
;
}
static
void
__exit
emac_exit
(
void
)
{
ocp_unregister_driver
(
&
emac_driver
);
}
module_init
(
emac_init
);
module_exit
(
emac_exit
);
drivers/net/ibm_emac/ibm_emac_core.h
0 → 100644
View file @
58de38a8
/*
* ibm_emac_core.h
*
* Ethernet driver for the built in ethernet on the IBM 405 PowerPC
* processor.
*
* Armin Kuster akuster@mvista.com
* Sept, 2001
*
* Orignial driver
* Johnnie Peters
* jpeters@mvista.com
*
* Copyright 2000 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 <asm/ocp.h>
#include <asm/mmu.h>
/* For phys_addr_t */
#include "ibm_emac.h"
#include "ibm_emac_phy.h"
#include "ibm_emac_rgmii.h"
#include "ibm_emac_zmii.h"
#include "ibm_emac_mal.h"
#include "ibm_emac_tah.h"
#ifndef CONFIG_IBM_EMAC_TXB
#define NUM_TX_BUFF 64
#define NUM_RX_BUFF 64
#else
#define NUM_TX_BUFF CONFIG_IBM_EMAC_TXB
#define NUM_RX_BUFF CONFIG_IBM_EMAC_RXB
#endif
/* This does 16 byte alignment, exactly what we need.
* The packet length includes FCS, but we don't want to
* include that when passing upstream as it messes up
* bridging applications.
*/
#ifndef CONFIG_IBM_EMAC_SKBRES
#define SKB_RES 2
#else
#define SKB_RES CONFIG_IBM_EMAC_SKBRES
#endif
/* Note about alignement. alloc_skb() returns a cache line
* aligned buffer. However, dev_alloc_skb() will add 16 more
* bytes and "reserve" them, so our buffer will actually end
* on a half cache line. What we do is to use directly
* alloc_skb, allocate 16 more bytes to match the total amount
* allocated by dev_alloc_skb(), but we don't reserve.
*/
#define MAX_NUM_BUF_DESC 255
#define DESC_BUF_SIZE 4080
/* max 4096-16 */
#define DESC_BUF_SIZE_REG (DESC_BUF_SIZE / 16)
/* Transmitter timeout. */
#define TX_TIMEOUT (2*HZ)
/* MDIO latency delay */
#define MDIO_DELAY 50
/* Power managment shift registers */
#define IBM_CPM_EMMII 0
/* Shift value for MII */
#define IBM_CPM_EMRX 1
/* Shift value for recv */
#define IBM_CPM_EMTX 2
/* Shift value for MAC */
#define IBM_CPM_EMAC(x) (((x)>>IBM_CPM_EMMII) | ((x)>>IBM_CPM_EMRX) | ((x)>>IBM_CPM_EMTX))
#define ENET_HEADER_SIZE 14
#define ENET_FCS_SIZE 4
#define ENET_DEF_MTU_SIZE 1500
#define ENET_DEF_BUF_SIZE (ENET_DEF_MTU_SIZE + ENET_HEADER_SIZE + ENET_FCS_SIZE)
#define EMAC_MIN_FRAME 64
#define EMAC_MAX_FRAME 9018
#define EMAC_MIN_MTU (EMAC_MIN_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE)
#define EMAC_MAX_MTU (EMAC_MAX_FRAME - ENET_HEADER_SIZE - ENET_FCS_SIZE)
#ifdef CONFIG_IBM_EMAC_ERRMSG
void
emac_serr_dump_0
(
struct
net_device
*
dev
);
void
emac_serr_dump_1
(
struct
net_device
*
dev
);
void
emac_err_dump
(
struct
net_device
*
dev
,
int
em0isr
);
void
emac_phy_dump
(
struct
net_device
*
);
void
emac_desc_dump
(
struct
net_device
*
);
void
emac_mac_dump
(
struct
net_device
*
);
void
emac_mal_dump
(
struct
net_device
*
);
#else
#define emac_serr_dump_0(dev) do { } while (0)
#define emac_serr_dump_1(dev) do { } while (0)
#define emac_err_dump(dev,x) do { } while (0)
#define emac_phy_dump(dev) do { } while (0)
#define emac_desc_dump(dev) do { } while (0)
#define emac_mac_dump(dev) do { } while (0)
#define emac_mal_dump(dev) do { } while (0)
#endif
struct
ocp_enet_private
{
struct
sk_buff
*
tx_skb
[
NUM_TX_BUFF
];
struct
sk_buff
*
rx_skb
[
NUM_RX_BUFF
];
struct
mal_descriptor
*
tx_desc
;
struct
mal_descriptor
*
rx_desc
;
struct
mal_descriptor
*
rx_dirty
;
struct
net_device_stats
stats
;
int
tx_cnt
;
int
rx_slot
;
int
dirty_rx
;
int
tx_slot
;
int
ack_slot
;
int
rx_buffer_size
;
struct
mii_phy
phy_mii
;
int
mii_phy_addr
;
int
want_autoneg
;
int
timer_ticks
;
struct
timer_list
link_timer
;
struct
net_device
*
mdio_dev
;
struct
ocp_device
*
rgmii_dev
;
int
rgmii_input
;
struct
ocp_device
*
zmii_dev
;
int
zmii_input
;
struct
ibm_ocp_mal
*
mal
;
int
mal_tx_chan
,
mal_rx_chan
;
struct
mal_commac
commac
;
struct
ocp_device
*
tah_dev
;
int
opened
;
int
going_away
;
int
wol_irq
;
emac_t
*
emacp
;
struct
ocp_device
*
ocpdev
;
struct
net_device
*
ndev
;
spinlock_t
lock
;
};
#endif
/* _IBM_EMAC_CORE_H_ */
drivers/net/ibm_emac/ibm_emac_debug.c
0 → 100644
View file @
58de38a8
/*
* ibm_ocp_debug.c
*
* This has all the debug routines that where in *_enet.c
*
* Armin Kuster akuster@mvista.com
* April , 2002
*
* 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/config.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <asm/io.h>
#include "ibm_ocp_mal.h"
#include "ibm_ocp_zmii.h"
#include "ibm_ocp_enet.h"
extern
int
emac_phy_read
(
struct
net_device
*
dev
,
int
mii_id
,
int
reg
);
void
emac_phy_dump
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
unsigned
long
i
;
uint
data
;
printk
(
KERN_DEBUG
" Prepare for Phy dump....
\n
"
);
for
(
i
=
0
;
i
<
0x1A
;
i
++
)
{
data
=
emac_phy_read
(
dev
,
fep
->
mii_phy_addr
,
i
);
printk
(
KERN_DEBUG
"Phy reg 0x%lx ==> %4x
\n
"
,
i
,
data
);
if
(
i
==
0x07
)
i
=
0x0f
;
}
}
void
emac_desc_dump
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
int
curr_slot
;
printk
(
KERN_DEBUG
"dumping the receive descriptors: current slot is %d
\n
"
,
fep
->
rx_slot
);
for
(
curr_slot
=
0
;
curr_slot
<
NUM_RX_BUFF
;
curr_slot
++
)
{
printk
(
KERN_DEBUG
"Desc %02d: status 0x%04x, length %3d, addr 0x%x
\n
"
,
curr_slot
,
fep
->
rx_desc
[
curr_slot
].
ctrl
,
fep
->
rx_desc
[
curr_slot
].
data_len
,
(
unsigned
int
)
fep
->
rx_desc
[
curr_slot
].
data_ptr
);
}
}
void
emac_mac_dump
(
struct
net_device
*
dev
)
{
struct
ocp_enet_private
*
fep
=
dev
->
priv
;
volatile
emac_t
*
emacp
=
fep
->
emacp
;
printk
(
KERN_DEBUG
"EMAC DEBUG **********
\n
"
);
printk
(
KERN_DEBUG
"EMAC_M0 ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0mr0
));
printk
(
KERN_DEBUG
"EMAC_M1 ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0mr1
));
printk
(
KERN_DEBUG
"EMAC_TXM0==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0tmr0
));
printk
(
KERN_DEBUG
"EMAC_TXM1==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0tmr1
));
printk
(
KERN_DEBUG
"EMAC_RXM ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0rmr
));
printk
(
KERN_DEBUG
"EMAC_ISR ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0isr
));
printk
(
KERN_DEBUG
"EMAC_IER ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0iser
));
printk
(
KERN_DEBUG
"EMAC_IAH ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0iahr
));
printk
(
KERN_DEBUG
"EMAC_IAL ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0ialr
));
printk
(
KERN_DEBUG
"EMAC_VLAN_TPID_REG ==> 0x%x
\n
"
,
in_be32
(
&
emacp
->
em0vtpid
));
}
void
emac_mal_dump
(
struct
net_device
*
dev
)
{
struct
ibm_ocp_mal
*
mal
=
((
struct
ocp_enet_private
*
)
dev
->
priv
)
->
mal
;
printk
(
KERN_DEBUG
" MAL DEBUG **********
\n
"
);
printk
(
KERN_DEBUG
" MCR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALCR
));
printk
(
KERN_DEBUG
" ESR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALESR
));
printk
(
KERN_DEBUG
" IER ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALIER
));
#ifdef CONFIG_40x
printk
(
KERN_DEBUG
" DBR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALDBR
));
#endif
/* CONFIG_40x */
printk
(
KERN_DEBUG
" TXCASR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCASR
));
printk
(
KERN_DEBUG
" TXCARR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCARR
));
printk
(
KERN_DEBUG
" TXEOBISR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXEOBISR
));
printk
(
KERN_DEBUG
" TXDEIR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXDEIR
));
printk
(
KERN_DEBUG
" RXCASR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXCASR
));
printk
(
KERN_DEBUG
" RXCARR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXCARR
));
printk
(
KERN_DEBUG
" RXEOBISR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXEOBISR
));
printk
(
KERN_DEBUG
" RXDEIR ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXDEIR
));
printk
(
KERN_DEBUG
" TXCTP0R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCTP0R
));
printk
(
KERN_DEBUG
" TXCTP1R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCTP1R
));
printk
(
KERN_DEBUG
" TXCTP2R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCTP2R
));
printk
(
KERN_DEBUG
" TXCTP3R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALTXCTP3R
));
printk
(
KERN_DEBUG
" RXCTP0R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXCTP0R
));
printk
(
KERN_DEBUG
" RXCTP1R ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRXCTP1R
));
printk
(
KERN_DEBUG
" RCBS0 ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRCBS0
));
printk
(
KERN_DEBUG
" RCBS1 ==> 0x%x
\n
"
,
(
unsigned
int
)
get_mal_dcrn
(
mal
,
DCRN_MALRCBS1
));
}
void
emac_serr_dump_0
(
struct
net_device
*
dev
)
{
struct
ibm_ocp_mal
*
mal
=
((
struct
ocp_enet_private
*
)
dev
->
priv
)
->
mal
;
unsigned
long
int
mal_error
,
plb_error
,
plb_addr
;
mal_error
=
get_mal_dcrn
(
mal
,
DCRN_MALESR
);
printk
(
KERN_DEBUG
"ppc405_eth_serr: %s channel %ld
\n
"
,
(
mal_error
&
0x40000000
)
?
"Receive"
:
"Transmit"
,
(
mal_error
&
0x3e000000
)
>>
25
);
printk
(
KERN_DEBUG
" ----- latched error -----
\n
"
);
if
(
mal_error
&
MALESR_DE
)
printk
(
KERN_DEBUG
" DE: descriptor error
\n
"
);
if
(
mal_error
&
MALESR_OEN
)
printk
(
KERN_DEBUG
" ONE: OPB non-fullword error
\n
"
);
if
(
mal_error
&
MALESR_OTE
)
printk
(
KERN_DEBUG
" OTE: OPB timeout error
\n
"
);
if
(
mal_error
&
MALESR_OSE
)
printk
(
KERN_DEBUG
" OSE: OPB slave error
\n
"
);
if
(
mal_error
&
MALESR_PEIN
)
{
plb_error
=
mfdcr
(
DCRN_PLB0_BESR
);
printk
(
KERN_DEBUG
" PEIN: PLB error, PLB0_BESR is 0x%x
\n
"
,
(
unsigned
int
)
plb_error
);
plb_addr
=
mfdcr
(
DCRN_PLB0_BEAR
);
printk
(
KERN_DEBUG
" PEIN: PLB error, PLB0_BEAR is 0x%x
\n
"
,
(
unsigned
int
)
plb_addr
);
}
}
void
emac_serr_dump_1
(
struct
net_device
*
dev
)
{
struct
ibm_ocp_mal
*
mal
=
((
struct
ocp_enet_private
*
)
dev
->
priv
)
->
mal
;
int
mal_error
=
get_mal_dcrn
(
mal
,
DCRN_MALESR
);
printk
(
KERN_DEBUG
" ----- cumulative errors -----
\n
"
);
if
(
mal_error
&
MALESR_DEI
)
printk
(
KERN_DEBUG
" DEI: descriptor error interrupt
\n
"
);
if
(
mal_error
&
MALESR_ONEI
)
printk
(
KERN_DEBUG
" OPB non-fullword error interrupt
\n
"
);
if
(
mal_error
&
MALESR_OTEI
)
printk
(
KERN_DEBUG
" OTEI: timeout error interrupt
\n
"
);
if
(
mal_error
&
MALESR_OSEI
)
printk
(
KERN_DEBUG
" OSEI: slave error interrupt
\n
"
);
if
(
mal_error
&
MALESR_PBEI
)
printk
(
KERN_DEBUG
" PBEI: PLB bus error interrupt
\n
"
);
}
void
emac_err_dump
(
struct
net_device
*
dev
,
int
em0isr
)
{
printk
(
KERN_DEBUG
"%s: on-chip ethernet error:
\n
"
,
dev
->
name
);
if
(
em0isr
&
EMAC_ISR_OVR
)
printk
(
KERN_DEBUG
" OVR: overrun
\n
"
);
if
(
em0isr
&
EMAC_ISR_PP
)
printk
(
KERN_DEBUG
" PP: control pause packet
\n
"
);
if
(
em0isr
&
EMAC_ISR_BP
)
printk
(
KERN_DEBUG
" BP: packet error
\n
"
);
if
(
em0isr
&
EMAC_ISR_RP
)
printk
(
KERN_DEBUG
" RP: runt packet
\n
"
);
if
(
em0isr
&
EMAC_ISR_SE
)
printk
(
KERN_DEBUG
" SE: short event
\n
"
);
if
(
em0isr
&
EMAC_ISR_ALE
)
printk
(
KERN_DEBUG
" ALE: odd number of nibbles in packet
\n
"
);
if
(
em0isr
&
EMAC_ISR_BFCS
)
printk
(
KERN_DEBUG
" BFCS: bad FCS
\n
"
);
if
(
em0isr
&
EMAC_ISR_PTLE
)
printk
(
KERN_DEBUG
" PTLE: oversized packet
\n
"
);
if
(
em0isr
&
EMAC_ISR_ORE
)
printk
(
KERN_DEBUG
" ORE: packet length field > max allowed LLC
\n
"
);
if
(
em0isr
&
EMAC_ISR_IRE
)
printk
(
KERN_DEBUG
" IRE: In Range error
\n
"
);
if
(
em0isr
&
EMAC_ISR_DBDM
)
printk
(
KERN_DEBUG
" DBDM: xmit error or SQE
\n
"
);
if
(
em0isr
&
EMAC_ISR_DB0
)
printk
(
KERN_DEBUG
" DB0: xmit error or SQE on TX channel 0
\n
"
);
if
(
em0isr
&
EMAC_ISR_SE0
)
printk
(
KERN_DEBUG
" SE0: Signal Quality Error test failure from TX channel 0
\n
"
);
if
(
em0isr
&
EMAC_ISR_TE0
)
printk
(
KERN_DEBUG
" TE0: xmit channel 0 aborted
\n
"
);
if
(
em0isr
&
EMAC_ISR_DB1
)
printk
(
KERN_DEBUG
" DB1: xmit error or SQE on TX channel
\n
"
);
if
(
em0isr
&
EMAC_ISR_SE1
)
printk
(
KERN_DEBUG
" SE1: Signal Quality Error test failure from TX channel 1
\n
"
);
if
(
em0isr
&
EMAC_ISR_TE1
)
printk
(
KERN_DEBUG
" TE1: xmit channel 1 aborted
\n
"
);
if
(
em0isr
&
EMAC_ISR_MOS
)
printk
(
KERN_DEBUG
" MOS
\n
"
);
if
(
em0isr
&
EMAC_ISR_MOF
)
printk
(
KERN_DEBUG
" MOF
\n
"
);
emac_mac_dump
(
dev
);
emac_mal_dump
(
dev
);
}
drivers/net/ibm_emac/ibm_emac_mal.c
0 → 100644
View file @
58de38a8
/*
* ibm_ocp_mal.c
*
* Armin Kuster akuster@mvista.com
* Juen, 2002
*
* 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/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ocp.h>
#include "ibm_emac_mal.h"
// Locking: Should we share a lock with the client ? The client could provide
// a lock pointer (optionally) in the commac structure... I don't think this is
// really necessary though
/* This lock protects the commac list. On today UP implementations, it's
* really only used as IRQ protection in mal_{register,unregister}_commac()
*/
static
rwlock_t
mal_list_lock
=
RW_LOCK_UNLOCKED
;
int
mal_register_commac
(
struct
ibm_ocp_mal
*
mal
,
struct
mal_commac
*
commac
)
{
unsigned
long
flags
;
write_lock_irqsave
(
&
mal_list_lock
,
flags
);
/* Don't let multiple commacs claim the same channel */
if
((
mal
->
tx_chan_mask
&
commac
->
tx_chan_mask
)
||
(
mal
->
rx_chan_mask
&
commac
->
rx_chan_mask
))
{
write_unlock_irqrestore
(
&
mal_list_lock
,
flags
);
return
-
EBUSY
;
}
mal
->
tx_chan_mask
|=
commac
->
tx_chan_mask
;
mal
->
rx_chan_mask
|=
commac
->
rx_chan_mask
;
list_add
(
&
commac
->
list
,
&
mal
->
commac
);
write_unlock_irqrestore
(
&
mal_list_lock
,
flags
);
MOD_INC_USE_COUNT
;
return
0
;
}
int
mal_unregister_commac
(
struct
ibm_ocp_mal
*
mal
,
struct
mal_commac
*
commac
)
{
unsigned
long
flags
;
write_lock_irqsave
(
&
mal_list_lock
,
flags
);
mal
->
tx_chan_mask
&=
~
commac
->
tx_chan_mask
;
mal
->
rx_chan_mask
&=
~
commac
->
rx_chan_mask
;
list_del_init
(
&
commac
->
list
);
write_unlock_irqrestore
(
&
mal_list_lock
,
flags
);
MOD_DEC_USE_COUNT
;
return
0
;
}
int
mal_set_rcbs
(
struct
ibm_ocp_mal
*
mal
,
int
channel
,
unsigned
long
size
)
{
switch
(
channel
)
{
case
0
:
set_mal_dcrn
(
mal
,
DCRN_MALRCBS0
,
size
);
break
;
#ifdef DCRN_MALRCBS1
case
1
:
set_mal_dcrn
(
mal
,
DCRN_MALRCBS1
,
size
);
break
;
#endif
#ifdef DCRN_MALRCBS2
case
2
:
set_mal_dcrn
(
mal
,
DCRN_MALRCBS2
,
size
);
break
;
#endif
#ifdef DCRN_MALRCBS3
case
3
:
set_mal_dcrn
(
mal
,
DCRN_MALRCBS3
,
size
);
break
;
#endif
default:
return
-
EINVAL
;
}
return
0
;
}
static
irqreturn_t
mal_serr
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ibm_ocp_mal
*
mal
=
dev_instance
;
unsigned
long
mal_error
;
/*
* This SERR applies to one of the devices on the MAL, here we charge
* it against the first EMAC registered for the MAL.
*/
mal_error
=
get_mal_dcrn
(
mal
,
DCRN_MALESR
);
printk
(
KERN_ERR
"%s: System Error (MALESR=%lx)
\n
"
,
"MAL"
/* FIXME: get the name right */
,
mal_error
);
/* FIXME: decipher error */
/* DIXME: distribute to commacs, if possible */
/* Clear the error status register */
set_mal_dcrn
(
mal
,
DCRN_MALESR
,
mal_error
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
mal_txeob
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ibm_ocp_mal
*
mal
=
dev_instance
;
struct
list_head
*
l
;
unsigned
long
isr
;
isr
=
get_mal_dcrn
(
mal
,
DCRN_MALTXEOBISR
);
set_mal_dcrn
(
mal
,
DCRN_MALTXEOBISR
,
isr
);
read_lock
(
&
mal_list_lock
);
list_for_each
(
l
,
&
mal
->
commac
)
{
struct
mal_commac
*
mc
=
list_entry
(
l
,
struct
mal_commac
,
list
);
if
(
isr
&
mc
->
tx_chan_mask
)
{
mc
->
ops
->
txeob
(
mc
->
dev
,
isr
&
mc
->
tx_chan_mask
);
}
}
read_unlock
(
&
mal_list_lock
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
mal_rxeob
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ibm_ocp_mal
*
mal
=
dev_instance
;
struct
list_head
*
l
;
unsigned
long
isr
;
isr
=
get_mal_dcrn
(
mal
,
DCRN_MALRXEOBISR
);
set_mal_dcrn
(
mal
,
DCRN_MALRXEOBISR
,
isr
);
read_lock
(
&
mal_list_lock
);
list_for_each
(
l
,
&
mal
->
commac
)
{
struct
mal_commac
*
mc
=
list_entry
(
l
,
struct
mal_commac
,
list
);
if
(
isr
&
mc
->
rx_chan_mask
)
{
mc
->
ops
->
rxeob
(
mc
->
dev
,
isr
&
mc
->
rx_chan_mask
);
}
}
read_unlock
(
&
mal_list_lock
);
return
IRQ_HANDLED
;
}
static
irqreturn_t
mal_txde
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ibm_ocp_mal
*
mal
=
dev_instance
;
struct
list_head
*
l
;
unsigned
long
deir
;
deir
=
get_mal_dcrn
(
mal
,
DCRN_MALTXDEIR
);
/* FIXME: print which MAL correctly */
printk
(
KERN_WARNING
"%s: Tx descriptor error (MALTXDEIR=%lx)
\n
"
,
"MAL"
,
deir
);
read_lock
(
&
mal_list_lock
);
list_for_each
(
l
,
&
mal
->
commac
)
{
struct
mal_commac
*
mc
=
list_entry
(
l
,
struct
mal_commac
,
list
);
if
(
deir
&
mc
->
tx_chan_mask
)
{
mc
->
ops
->
txde
(
mc
->
dev
,
deir
&
mc
->
tx_chan_mask
);
}
}
read_unlock
(
&
mal_list_lock
);
return
IRQ_HANDLED
;
}
/*
* This interrupt should be very rare at best. This occurs when
* the hardware has a problem with the receive descriptors. The manual
* states that it occurs when the hardware cannot the receive descriptor
* empty bit is not set. The recovery mechanism will be to
* traverse through the descriptors, handle any that are marked to be
* handled and reinitialize each along the way. At that point the driver
* will be restarted.
*/
static
irqreturn_t
mal_rxde
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ibm_ocp_mal
*
mal
=
dev_instance
;
struct
list_head
*
l
;
unsigned
long
deir
;
deir
=
get_mal_dcrn
(
mal
,
DCRN_MALRXDEIR
);
/*
* This really is needed. This case encountered in stress testing.
*/
if
(
deir
==
0
)
return
IRQ_HANDLED
;
/* FIXME: print which MAL correctly */
printk
(
KERN_WARNING
"%s: Rx descriptor error (MALRXDEIR=%lx)
\n
"
,
"MAL"
,
deir
);
read_lock
(
&
mal_list_lock
);
list_for_each
(
l
,
&
mal
->
commac
)
{
struct
mal_commac
*
mc
=
list_entry
(
l
,
struct
mal_commac
,
list
);
if
(
deir
&
mc
->
rx_chan_mask
)
{
mc
->
ops
->
rxde
(
mc
->
dev
,
deir
&
mc
->
rx_chan_mask
);
}
}
read_unlock
(
&
mal_list_lock
);
return
IRQ_HANDLED
;
}
static
int
__init
mal_probe
(
struct
ocp_device
*
ocpdev
)
{
struct
ibm_ocp_mal
*
mal
=
NULL
;
struct
ocp_func_mal_data
*
maldata
;
int
err
=
0
;
maldata
=
(
struct
ocp_func_mal_data
*
)
ocpdev
->
def
->
additions
;
if
(
maldata
==
NULL
)
{
printk
(
KERN_ERR
"mal%d: Missing additional datas !
\n
"
,
ocpdev
->
def
->
index
);
return
-
ENODEV
;
}
mal
=
kmalloc
(
sizeof
(
struct
ibm_ocp_mal
),
GFP_KERNEL
);
if
(
mal
==
NULL
)
{
printk
(
KERN_ERR
"mal%d: Out of memory allocating MAL structure !
\n
"
,
ocpdev
->
def
->
index
);
return
-
ENOMEM
;
}
memset
(
mal
,
0
,
sizeof
(
*
mal
));
switch
(
ocpdev
->
def
->
index
)
{
case
0
:
mal
->
dcrbase
=
DCRN_MAL_BASE
;
break
;
#ifdef DCRN_MAL1_BASE
case
1
:
mal
->
dcrbase
=
DCRN_MAL1_BASE
;
break
;
#endif
default:
BUG
();
}
/**************************/
INIT_LIST_HEAD
(
&
mal
->
commac
);
set_mal_dcrn
(
mal
,
DCRN_MALRXCARR
,
0xFFFFFFFF
);
set_mal_dcrn
(
mal
,
DCRN_MALTXCARR
,
0xFFFFFFFF
);
set_mal_dcrn
(
mal
,
DCRN_MALCR
,
MALCR_MMSR
);
/* 384 */
/* FIXME: Add delay */
/* Set the MAL configuration register */
set_mal_dcrn
(
mal
,
DCRN_MALCR
,
MALCR_PLBB
|
MALCR_OPBBL
|
MALCR_LEA
|
MALCR_PLBLT_DEFAULT
);
/* It would be nice to allocate buffers separately for each
* channel, but we can't because the channels share the upper
* 13 bits of address lines. Each channels buffer must also
* be 4k aligned, so we allocate 4k for each channel. This is
* inefficient FIXME: do better, if possible */
mal
->
tx_virt_addr
=
dma_alloc_coherent
(
&
ocpdev
->
dev
,
MAL_DT_ALIGN
*
maldata
->
num_tx_chans
,
&
mal
->
tx_phys_addr
,
GFP_KERNEL
);
if
(
mal
->
tx_virt_addr
==
NULL
)
{
printk
(
KERN_ERR
"mal%d: Out of memory allocating MAL descriptors !
\n
"
,
ocpdev
->
def
->
index
);
err
=
-
ENOMEM
;
goto
fail
;
}
/* God, oh, god, I hate DCRs */
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP0R
,
mal
->
tx_phys_addr
);
#ifdef DCRN_MALTXCTP1R
if
(
maldata
->
num_tx_chans
>
1
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP1R
,
mal
->
tx_phys_addr
+
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP1R */
#ifdef DCRN_MALTXCTP2R
if
(
maldata
->
num_tx_chans
>
2
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP2R
,
mal
->
tx_phys_addr
+
2
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP2R */
#ifdef DCRN_MALTXCTP3R
if
(
maldata
->
num_tx_chans
>
3
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP3R
,
mal
->
tx_phys_addr
+
3
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP3R */
#ifdef DCRN_MALTXCTP4R
if
(
maldata
->
num_tx_chans
>
4
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP4R
,
mal
->
tx_phys_addr
+
4
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP4R */
#ifdef DCRN_MALTXCTP5R
if
(
maldata
->
num_tx_chans
>
5
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP5R
,
mal
->
tx_phys_addr
+
5
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP5R */
#ifdef DCRN_MALTXCTP6R
if
(
maldata
->
num_tx_chans
>
6
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP6R
,
mal
->
tx_phys_addr
+
6
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP6R */
#ifdef DCRN_MALTXCTP7R
if
(
maldata
->
num_tx_chans
>
7
)
set_mal_dcrn
(
mal
,
DCRN_MALTXCTP7R
,
mal
->
tx_phys_addr
+
7
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALTXCTP7R */
mal
->
rx_virt_addr
=
dma_alloc_coherent
(
&
ocpdev
->
dev
,
MAL_DT_ALIGN
*
maldata
->
num_rx_chans
,
&
mal
->
rx_phys_addr
,
GFP_KERNEL
);
set_mal_dcrn
(
mal
,
DCRN_MALRXCTP0R
,
mal
->
rx_phys_addr
);
#ifdef DCRN_MALRXCTP1R
if
(
maldata
->
num_rx_chans
>
1
)
set_mal_dcrn
(
mal
,
DCRN_MALRXCTP1R
,
mal
->
rx_phys_addr
+
MAL_DT_ALIGN
);
#endif
/* DCRN_MALRXCTP1R */
#ifdef DCRN_MALRXCTP2R
if
(
maldata
->
num_rx_chans
>
2
)
set_mal_dcrn
(
mal
,
DCRN_MALRXCTP2R
,
mal
->
rx_phys_addr
+
2
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALRXCTP2R */
#ifdef DCRN_MALRXCTP3R
if
(
maldata
->
num_rx_chans
>
3
)
set_mal_dcrn
(
mal
,
DCRN_MALRXCTP3R
,
mal
->
rx_phys_addr
+
3
*
MAL_DT_ALIGN
);
#endif
/* DCRN_MALRXCTP3R */
err
=
request_irq
(
maldata
->
serr_irq
,
mal_serr
,
0
,
"MAL SERR"
,
mal
);
if
(
err
)
goto
fail
;
err
=
request_irq
(
maldata
->
txde_irq
,
mal_txde
,
0
,
"MAL TX DE "
,
mal
);
if
(
err
)
goto
fail
;
err
=
request_irq
(
maldata
->
txeob_irq
,
mal_txeob
,
0
,
"MAL TX EOB"
,
mal
);
if
(
err
)
goto
fail
;
err
=
request_irq
(
maldata
->
rxde_irq
,
mal_rxde
,
0
,
"MAL RX DE"
,
mal
);
if
(
err
)
goto
fail
;
err
=
request_irq
(
maldata
->
rxeob_irq
,
mal_rxeob
,
0
,
"MAL RX EOB"
,
mal
);
if
(
err
)
goto
fail
;
set_mal_dcrn
(
mal
,
DCRN_MALIER
,
MALIER_DE
|
MALIER_NE
|
MALIER_TE
|
MALIER_OPBE
|
MALIER_PLBE
);
/* Advertise me to the rest of the world */
ocp_set_drvdata
(
ocpdev
,
mal
);
printk
(
KERN_INFO
"mal%d: Initialized, %d tx channels, %d rx channels
\n
"
,
ocpdev
->
def
->
index
,
maldata
->
num_tx_chans
,
maldata
->
num_rx_chans
);
return
0
;
fail:
/* FIXME: dispose requested IRQs ! */
if
(
err
&&
mal
)
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
=
ocpdev
->
def
->
additions
;
BUG_ON
(
!
maldata
);
ocp_set_drvdata
(
ocpdev
,
NULL
);
/* FIXME: shut down the MAL, deal with dependency with emac */
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
);
if
(
mal
->
tx_virt_addr
)
dma_free_coherent
(
&
ocpdev
->
dev
,
MAL_DT_ALIGN
*
maldata
->
num_tx_chans
,
mal
->
tx_virt_addr
,
mal
->
tx_phys_addr
);
if
(
mal
->
rx_virt_addr
)
dma_free_coherent
(
&
ocpdev
->
dev
,
MAL_DT_ALIGN
*
maldata
->
num_rx_chans
,
mal
->
rx_virt_addr
,
mal
->
rx_phys_addr
);
kfree
(
mal
);
}
/* Structure for a device driver */
static
struct
ocp_device_id
mal_ids
[]
=
{
{.
vendor
=
OCP_ANY_ID
,.
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
,
};
static
int
__init
init_mals
(
void
)
{
int
rc
;
rc
=
ocp_register_driver
(
&
mal_driver
);
if
(
rc
<
0
)
{
ocp_unregister_driver
(
&
mal_driver
);
return
-
ENODEV
;
}
return
0
;
}
static
void
__exit
exit_mals
(
void
)
{
ocp_unregister_driver
(
&
mal_driver
);
}
module_init
(
init_mals
);
module_exit
(
exit_mals
);
drivers/net/ibm_emac/ibm_emac_mal.h
0 → 100644
View file @
58de38a8
#ifndef _IBM_EMAC_MAL_H
#define _IBM_EMAC_MAL_H
#include <linux/list.h>
#define MAL_DT_ALIGN (4096)
/* Alignment for each channel's descriptor table */
#define MAL_CHAN_MASK(chan) (0x80000000 >> (chan))
/* MAL Buffer Descriptor structure */
struct
mal_descriptor
{
unsigned
short
ctrl
;
/* MAL / Commac status control bits */
short
data_len
;
/* Max length is 4K-1 (12 bits) */
unsigned
char
*
data_ptr
;
/* pointer to actual data buffer */
}
__attribute__
((
packed
));
/* 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_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
(
*
txeob
)
(
void
*
dev
,
u32
chanmask
);
void
(
*
txde
)
(
void
*
dev
,
u32
chanmask
);
void
(
*
rxeob
)
(
void
*
dev
,
u32
chanmask
);
void
(
*
rxde
)
(
void
*
dev
,
u32
chanmask
);
};
struct
mal_commac
{
struct
mal_commac_ops
*
ops
;
void
*
dev
;
u32
tx_chan_mask
,
rx_chan_mask
;
struct
list_head
list
;
};
struct
ibm_ocp_mal
{
int
dcrbase
;
struct
list_head
commac
;
u32
tx_chan_mask
,
rx_chan_mask
;
dma_addr_t
tx_phys_addr
;
struct
mal_descriptor
*
tx_virt_addr
;
dma_addr_t
rx_phys_addr
;
struct
mal_descriptor
*
rx_virt_addr
;
};
#define GET_MAL_STANZA(base,dcrn) \
case base: \
x = mfdcr(dcrn(base)); \
break;
#define SET_MAL_STANZA(base,dcrn, val) \
case base: \
mtdcr(dcrn(base), (val)); \
break;
#define GET_MAL0_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL_BASE,dcrn)
#define SET_MAL0_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL_BASE,dcrn,val)
#ifdef DCRN_MAL1_BASE
#define GET_MAL1_STANZA(dcrn) GET_MAL_STANZA(DCRN_MAL1_BASE,dcrn)
#define SET_MAL1_STANZA(dcrn,val) SET_MAL_STANZA(DCRN_MAL1_BASE,dcrn,val)
#else
/* ! DCRN_MAL1_BASE */
#define GET_MAL1_STANZA(dcrn)
#define SET_MAL1_STANZA(dcrn,val)
#endif
#define get_mal_dcrn(mal, dcrn) ({ \
u32 x; \
switch ((mal)->dcrbase) { \
GET_MAL0_STANZA(dcrn) \
GET_MAL1_STANZA(dcrn) \
default: \
BUG(); \
} \
x; })
#define set_mal_dcrn(mal, dcrn, val) do { \
switch ((mal)->dcrbase) { \
SET_MAL0_STANZA(dcrn,val) \
SET_MAL1_STANZA(dcrn,val) \
default: \
BUG(); \
} } while (0)
static
inline
void
mal_enable_tx_channels
(
struct
ibm_ocp_mal
*
mal
,
u32
chanmask
)
{
set_mal_dcrn
(
mal
,
DCRN_MALTXCASR
,
get_mal_dcrn
(
mal
,
DCRN_MALTXCASR
)
|
chanmask
);
}
static
inline
void
mal_disable_tx_channels
(
struct
ibm_ocp_mal
*
mal
,
u32
chanmask
)
{
set_mal_dcrn
(
mal
,
DCRN_MALTXCARR
,
chanmask
);
}
static
inline
void
mal_enable_rx_channels
(
struct
ibm_ocp_mal
*
mal
,
u32
chanmask
)
{
set_mal_dcrn
(
mal
,
DCRN_MALRXCASR
,
get_mal_dcrn
(
mal
,
DCRN_MALRXCASR
)
|
chanmask
);
}
static
inline
void
mal_disable_rx_channels
(
struct
ibm_ocp_mal
*
mal
,
u32
chanmask
)
{
set_mal_dcrn
(
mal
,
DCRN_MALRXCARR
,
chanmask
);
}
extern
int
mal_register_commac
(
struct
ibm_ocp_mal
*
mal
,
struct
mal_commac
*
commac
);
extern
int
mal_unregister_commac
(
struct
ibm_ocp_mal
*
mal
,
struct
mal_commac
*
commac
);
extern
int
mal_set_rcbs
(
struct
ibm_ocp_mal
*
mal
,
int
channel
,
unsigned
long
size
);
#endif
/* _IBM_EMAC_MAL_H */
drivers/net/ibm_emac/ibm_emac_phy.c
0 → 100644
View file @
58de38a8
/*
* ibm_ocp_phy.c
*
* PHY drivers for the ibm ocp ethernet driver. 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)
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include "ibm_emac_phy.h"
static
int
reset_one_mii_phy
(
struct
mii_phy
*
phy
,
int
phy_id
)
{
u16
val
;
int
limit
=
10000
;
val
=
__phy_read
(
phy
,
phy_id
,
MII_BMCR
);
val
&=
~
BMCR_ISOLATE
;
val
|=
BMCR_RESET
;
__phy_write
(
phy
,
phy_id
,
MII_BMCR
,
val
);
udelay
(
100
);
while
(
limit
--
)
{
val
=
__phy_read
(
phy
,
phy_id
,
MII_BMCR
);
if
((
val
&
BMCR_RESET
)
==
0
)
break
;
udelay
(
10
);
}
if
((
val
&
BMCR_ISOLATE
)
&&
limit
>
0
)
__phy_write
(
phy
,
phy_id
,
MII_BMCR
,
val
&
~
BMCR_ISOLATE
);
return
(
limit
<=
0
);
}
static
int
cis8201_init
(
struct
mii_phy
*
phy
)
{
u16
epcr
;
epcr
=
phy_read
(
phy
,
MII_CIS8201_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
);
return
0
;
}
static
int
genmii_setup_aneg
(
struct
mii_phy
*
phy
,
u32
advertise
)
{
u16
ctl
,
adv
;
phy
->
autoneg
=
1
;
phy
->
speed
=
SPEED_10
;
phy
->
duplex
=
DUPLEX_HALF
;
phy
->
pause
=
0
;
phy
->
advertising
=
advertise
;
/* Setup standard advertise */
adv
=
phy_read
(
phy
,
MII_ADVERTISE
);
adv
&=
~
(
ADVERTISE_ALL
|
ADVERTISE_100BASE4
);
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
;
phy_write
(
phy
,
MII_ADVERTISE
,
adv
);
/* Start/Restart aneg */
ctl
=
phy_read
(
phy
,
MII_BMCR
);
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
)
{
u16
ctl
;
phy
->
autoneg
=
0
;
phy
->
speed
=
speed
;
phy
->
duplex
=
fd
;
phy
->
pause
=
0
;
ctl
=
phy_read
(
phy
,
MII_BMCR
);
ctl
&=
~
(
BMCR_FULLDPLX
|
BMCR_SPEED100
|
BMCR_ANENABLE
);
/* First reset the PHY */
phy_write
(
phy
,
MII_BMCR
,
ctl
|
BMCR_RESET
);
/* Select speed & duplex */
switch
(
speed
)
{
case
SPEED_10
:
break
;
case
SPEED_100
:
ctl
|=
BMCR_SPEED100
;
break
;
case
SPEED_1000
:
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
)
{
u16
status
;
(
void
)
phy_read
(
phy
,
MII_BMSR
);
status
=
phy_read
(
phy
,
MII_BMSR
);
if
((
status
&
BMSR_LSTATUS
)
==
0
)
return
0
;
if
(
phy
->
autoneg
&&
!
(
status
&
BMSR_ANEGCOMPLETE
))
return
0
;
return
1
;
}
#define MII_CIS8201_ACSR 0x1c
#define ACSR_DUPLEX_STATUS 0x0020
#define ACSR_SPEED_1000BASET 0x0010
#define ACSR_SPEED_100BASET 0x0008
static
int
cis8201_read_link
(
struct
mii_phy
*
phy
)
{
u16
acsr
;
if
(
phy
->
autoneg
)
{
acsr
=
phy_read
(
phy
,
MII_CIS8201_ACSR
);
if
(
acsr
&
ACSR_DUPLEX_STATUS
)
phy
->
duplex
=
DUPLEX_FULL
;
else
phy
->
duplex
=
DUPLEX_HALF
;
if
(
acsr
&
ACSR_SPEED_1000BASET
)
{
phy
->
speed
=
SPEED_1000
;
}
else
if
(
acsr
&
ACSR_SPEED_100BASET
)
phy
->
speed
=
SPEED_100
;
else
phy
->
speed
=
SPEED_10
;
phy
->
pause
=
0
;
}
/* On non-aneg, we assume what we put in BMCR is the speed,
* though magic-aneg shouldn't prevent this case from occurring
*/
return
0
;
}
static
int
genmii_read_link
(
struct
mii_phy
*
phy
)
{
u16
lpa
;
if
(
phy
->
autoneg
)
{
lpa
=
phy_read
(
phy
,
MII_LPA
);
if
(
lpa
&
(
LPA_10FULL
|
LPA_100FULL
))
phy
->
duplex
=
DUPLEX_FULL
;
else
phy
->
duplex
=
DUPLEX_HALF
;
if
(
lpa
&
(
LPA_100FULL
|
LPA_100HALF
))
phy
->
speed
=
SPEED_100
;
else
phy
->
speed
=
SPEED_10
;
phy
->
pause
=
0
;
}
/* On non-aneg, we assume what we put in BMCR is the speed,
* though magic-aneg shouldn't prevent this case from occurring
*/
return
0
;
}
#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
/* CIS8201 phy ops */
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:
cis8201_read_link
};
/* Generic implementation for most 10/100 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
cis8201_phy_def
=
{
phy_id:
0x000fc410
,
phy_id_mask:
0x000ffff0
,
name:
"CIS8201 Gigabit Ethernet"
,
features:
MII_GBIT_FEATURES
,
magic_aneg:
0
,
ops:
&
cis8201_phy_ops
};
static
struct
mii_phy_def
genmii_phy_def
=
{
phy_id:
0x00000000
,
phy_id_mask:
0x00000000
,
name:
"Generic MII"
,
features:
MII_BASIC_FEATURES
,
magic_aneg:
0
,
ops:
&
generic_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
mii_id
)
{
int
rc
;
u32
id
;
struct
mii_phy_def
*
def
;
int
i
;
phy
->
autoneg
=
0
;
phy
->
advertising
=
0
;
phy
->
mii_id
=
mii_id
;
phy
->
speed
=
0
;
phy
->
duplex
=
0
;
phy
->
pause
=
0
;
/* Take PHY out of isloate mode and reset it. */
rc
=
reset_one_mii_phy
(
phy
,
mii_id
);
if
(
rc
)
return
-
ENODEV
;
/* Read ID and find matching entry */
id
=
(
phy_read
(
phy
,
MII_PHYSID1
)
<<
16
|
phy_read
(
phy
,
MII_PHYSID2
))
&
0xfffffff0
;
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
==
NULL
)
return
-
ENODEV
;
phy
->
def
=
def
;
/* Setup default advertising */
phy
->
advertising
=
def
->
features
;
return
0
;
}
MODULE_LICENSE
(
"GPL"
);
drivers/net/ibm_emac/ibm_emac_phy.h
0 → 100644
View file @
58de38a8
/*
* ibm_emac_phy.h
*
*
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
* February 2003
*
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* 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_EMAC_PHY_H_
#define _IBM_EMAC_PHY_H_
/*
* PHY mode settings
* Used for multi-mode capable PHYs
*/
#define PHY_MODE_NA 0
#define PHY_MODE_MII 1
#define PHY_MODE_RMII 2
#define PHY_MODE_SMII 3
#define PHY_MODE_RGMII 4
#define PHY_MODE_TBI 5
#define PHY_MODE_GMII 6
#define PHY_MODE_RTBI 7
#define PHY_MODE_SGMII 8
/*
* PHY specific registers/values
*/
/* CIS8201 */
#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
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 */
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
;
int
advertising
;
int
mii_id
;
/* 1: autoneg enabled, 0: disabled */
int
autoneg
;
/* forced speed & duplex (no autoneg)
* partner speed & duplex & pause (autoneg)
*/
int
speed
;
int
duplex
;
int
pause
;
/* PHY mode - if needed */
int
mode
;
/* Provided by host chip */
struct
net_device
*
dev
;
int
(
*
mdio_read
)
(
struct
net_device
*
dev
,
int
mii_id
,
int
reg
);
void
(
*
mdio_write
)
(
struct
net_device
*
dev
,
int
mii_id
,
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
*/
extern
int
mii_phy_probe
(
struct
mii_phy
*
phy
,
int
mii_id
);
static
inline
int
__phy_read
(
struct
mii_phy
*
phy
,
int
id
,
int
reg
)
{
return
phy
->
mdio_read
(
phy
->
dev
,
id
,
reg
);
}
static
inline
void
__phy_write
(
struct
mii_phy
*
phy
,
int
id
,
int
reg
,
int
val
)
{
phy
->
mdio_write
(
phy
->
dev
,
id
,
reg
,
val
);
}
static
inline
int
phy_read
(
struct
mii_phy
*
phy
,
int
reg
)
{
return
phy
->
mdio_read
(
phy
->
dev
,
phy
->
mii_id
,
reg
);
}
static
inline
void
phy_write
(
struct
mii_phy
*
phy
,
int
reg
,
int
val
)
{
phy
->
mdio_write
(
phy
->
dev
,
phy
->
mii_id
,
reg
,
val
);
}
#endif
/* _IBM_EMAC_PHY_H_ */
drivers/net/ibm_emac/ibm_emac_rgmii.h
0 → 100644
View file @
58de38a8
/*
* Defines for the IBM RGMII bridge
*
* 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>
*
* 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_
#include <linux/config.h>
/* RGMII bridge */
typedef
struct
rgmii_regs
{
u32
fer
;
/* Function enable register */
u32
ssr
;
/* Speed select register */
}
rgmii_t
;
#define RGMII_INPUTS 4
/* RGMII device */
struct
ibm_ocp_rgmii
{
struct
rgmii_regs
*
base
;
int
mode
[
RGMII_INPUTS
];
int
users
;
/* number of EMACs using this RGMII bridge */
};
/* Fuctional Enable Reg */
#define RGMII_FER_MASK(x) (0x00000007 << (4*x))
#define RGMII_RTBI 0x00000004
#define RGMII_RGMII 0x00000005
#define RGMII_TBI 0x00000006
#define RGMII_GMII 0x00000007
/* Speed Selection reg */
#define RGMII_SP2_100 0x00000002
#define RGMII_SP2_1000 0x00000004
#define RGMII_SP3_100 0x00000200
#define RGMII_SP3_1000 0x00000400
#define RGMII_MII2_SPDMASK 0x00000007
#define RGMII_MII3_SPDMASK 0x00000700
#define RGMII_MII2_100MB RGMII_SP2_100 & ~RGMII_SP2_1000
#define RGMII_MII2_1000MB RGMII_SP2_1000 & ~RGMII_SP2_100
#define RGMII_MII2_10MB ~(RGMII_SP2_100 | RGMII_SP2_1000)
#define RGMII_MII3_100MB RGMII_SP3_100 & ~RGMII_SP3_1000
#define RGMII_MII3_1000MB RGMII_SP3_1000 & ~RGMII_SP3_100
#define RGMII_MII3_10MB ~(RGMII_SP3_100 | RGMII_SP3_1000)
#define RTBI 0
#define RGMII 1
#define TBI 2
#define GMII 3
#endif
/* _IBM_EMAC_RGMII_H_ */
drivers/net/ibm_emac/ibm_emac_tah.h
0 → 100644
View file @
58de38a8
/*
* Defines for the IBM TAH
*
* Copyright 2004 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef _IBM_EMAC_TAH_H
#define _IBM_EMAC_TAH_H
/* TAH */
typedef
struct
tah_regs
{
u32
tah_revid
;
u32
pad
[
3
];
u32
tah_mr
;
u32
tah_ssr0
;
u32
tah_ssr1
;
u32
tah_ssr2
;
u32
tah_ssr3
;
u32
tah_ssr4
;
u32
tah_ssr5
;
u32
tah_tsr
;
}
tah_t
;
/* 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
#endif
/* _IBM_EMAC_TAH_H */
drivers/net/ibm_emac/ibm_emac_zmii.h
0 → 100644
View file @
58de38a8
/*
* ocp_zmii.h
*
* Defines for the IBM ZMII bridge
*
* Armin Kuster akuster@mvista.com
* Dec, 2001
*
* 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/config.h>
/* ZMII bridge registers */
struct
zmii_regs
{
u32
fer
;
/* Function enable reg */
u32
ssr
;
/* Speed select reg */
u32
smiirs
;
/* SMII status reg */
};
#define ZMII_INPUTS 4
/* ZMII device */
struct
ibm_ocp_zmii
{
struct
zmii_regs
*
base
;
int
mode
[
ZMII_INPUTS
];
int
users
;
/* number of EMACs using this ZMII bridge */
};
/* Fuctional Enable Reg */
#define ZMII_FER_MASK(x) (0xf0000000 >> (4*x))
#define ZMII_MDI0 0x80000000
#define ZMII_SMII0 0x40000000
#define ZMII_RMII0 0x20000000
#define ZMII_MII0 0x10000000
#define ZMII_MDI1 0x08000000
#define ZMII_SMII1 0x04000000
#define ZMII_RMII1 0x02000000
#define ZMII_MII1 0x01000000
#define ZMII_MDI2 0x00800000
#define ZMII_SMII2 0x00400000
#define ZMII_RMII2 0x00200000
#define ZMII_MII2 0x00100000
#define ZMII_MDI3 0x00080000
#define ZMII_SMII3 0x00040000
#define ZMII_RMII3 0x00020000
#define ZMII_MII3 0x00010000
/* Speed Selection reg */
#define ZMII_SCI0 0x40000000
#define ZMII_FSS0 0x20000000
#define ZMII_SP0 0x10000000
#define ZMII_SCI1 0x04000000
#define ZMII_FSS1 0x02000000
#define ZMII_SP1 0x01000000
#define ZMII_SCI2 0x00400000
#define ZMII_FSS2 0x00200000
#define ZMII_SP2 0x00100000
#define ZMII_SCI3 0x00040000
#define ZMII_FSS3 0x00020000
#define ZMII_SP3 0x00010000
#define ZMII_MII0_100MB ZMII_SP0
#define ZMII_MII0_10MB ~ZMII_SP0
#define ZMII_MII1_100MB ZMII_SP1
#define ZMII_MII1_10MB ~ZMII_SP1
#define ZMII_MII2_100MB ZMII_SP2
#define ZMII_MII2_10MB ~ZMII_SP2
#define ZMII_MII3_100MB ZMII_SP3
#define ZMII_MII3_10MB ~ZMII_SP3
/* SMII Status reg */
#define ZMII_STS0 0xFF000000
/* EMAC0 smii status mask */
#define ZMII_STS1 0x00FF0000
/* EMAC1 smii status mask */
#define SMII 0
#define RMII 1
#define MII 2
#define MDI 3
#endif
/* _IBM_EMAC_ZMII_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment