Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
ae19161e
Commit
ae19161e
authored
Sep 24, 2008
by
Jeff Garzik
Committed by
Jeff Garzik
Sep 24, 2008
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-2.6.28' of
git://git.marvell.com/mv643xx_eth
into upstream-next
parents
152cbcf9
042af53c
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
820 additions
and
777 deletions
+820
-777
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
+1
-1
arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
+1
-1
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
+1
-1
arch/arm/mach-loki/lb88rc8480-setup.c
arch/arm/mach-loki/lb88rc8480-setup.c
+1
-1
arch/arm/mach-mv78xx0/common.c
arch/arm/mach-mv78xx0/common.c
+3
-3
arch/arm/mach-mv78xx0/db78x00-bp-setup.c
arch/arm/mach-mv78xx0/db78x00-bp-setup.c
+4
-4
arch/arm/mach-orion5x/db88f5281-setup.c
arch/arm/mach-orion5x/db88f5281-setup.c
+1
-1
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/dns323-setup.c
+1
-1
arch/arm/mach-orion5x/kurobox_pro-setup.c
arch/arm/mach-orion5x/kurobox_pro-setup.c
+1
-1
arch/arm/mach-orion5x/mss2-setup.c
arch/arm/mach-orion5x/mss2-setup.c
+1
-1
arch/arm/mach-orion5x/mv2120-setup.c
arch/arm/mach-orion5x/mv2120-setup.c
+1
-1
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+1
-1
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+1
-1
arch/arm/mach-orion5x/rd88f5182-setup.c
arch/arm/mach-orion5x/rd88f5182-setup.c
+1
-1
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-orion5x/ts78xx-setup.c
+1
-2
arch/arm/mach-orion5x/tsx09-common.c
arch/arm/mach-orion5x/tsx09-common.c
+1
-1
arch/arm/mach-orion5x/wnr854t-setup.c
arch/arm/mach-orion5x/wnr854t-setup.c
+1
-1
arch/arm/mach-orion5x/wrt350n-v2-setup.c
arch/arm/mach-orion5x/wrt350n-v2-setup.c
+1
-1
arch/powerpc/sysdev/mv64x60_dev.c
arch/powerpc/sysdev/mv64x60_dev.c
+2
-4
drivers/net/Kconfig
drivers/net/Kconfig
+1
-1
drivers/net/mv643xx_eth.c
drivers/net/mv643xx_eth.c
+736
-702
drivers/net/phy/mdio_bus.c
drivers/net/phy/mdio_bus.c
+48
-41
include/linux/mv643xx_eth.h
include/linux/mv643xx_eth.h
+8
-5
include/linux/phy.h
include/linux/phy.h
+2
-0
No files found.
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
View file @
ae19161e
...
...
@@ -25,7 +25,7 @@
#include "common.h"
static
struct
mv643xx_eth_platform_data
db88f6281_ge00_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
static
struct
mv_sata_platform_data
db88f6281_sata_data
=
{
...
...
arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
View file @
ae19161e
...
...
@@ -30,7 +30,7 @@
#define RD88F6192_GPIO_USB_VBUS 10
static
struct
mv643xx_eth_platform_data
rd88f6192_ge00_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
static
struct
mv_sata_platform_data
rd88f6192_sata_data
=
{
...
...
arch/arm/mach-kirkwood/rd88f6281-setup.c
View file @
ae19161e
...
...
@@ -69,7 +69,7 @@ static struct platform_device rd88f6281_nand_flash = {
};
static
struct
mv643xx_eth_platform_data
rd88f6281_ge00_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
.
speed
=
SPEED_1000
,
.
duplex
=
DUPLEX_FULL
,
};
...
...
arch/arm/mach-loki/lb88rc8480-setup.c
View file @
ae19161e
...
...
@@ -67,7 +67,7 @@ static struct platform_device lb88rc8480_boot_flash = {
};
static
struct
mv643xx_eth_platform_data
lb88rc8480_ge0_data
=
{
.
phy_addr
=
1
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
1
)
,
.
mac_addr
=
{
0x00
,
0x50
,
0x43
,
0x11
,
0x22
,
0x33
},
};
...
...
arch/arm/mach-mv78xx0/common.c
View file @
ae19161e
...
...
@@ -330,6 +330,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
struct
mv643xx_eth_shared_platform_data
mv78xx0_ge01_shared_data
=
{
.
t_clk
=
0
,
.
dram
=
&
mv78xx0_mbus_dram_info
,
.
shared_smi
=
&
mv78xx0_ge00_shared
,
};
static
struct
resource
mv78xx0_ge01_shared_resources
[]
=
{
...
...
@@ -370,7 +371,6 @@ static struct platform_device mv78xx0_ge01 = {
void
__init
mv78xx0_ge01_init
(
struct
mv643xx_eth_platform_data
*
eth_data
)
{
eth_data
->
shared
=
&
mv78xx0_ge01_shared
;
eth_data
->
shared_smi
=
&
mv78xx0_ge00_shared
;
mv78xx0_ge01
.
dev
.
platform_data
=
eth_data
;
platform_device_register
(
&
mv78xx0_ge01_shared
);
...
...
@@ -384,6 +384,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
struct
mv643xx_eth_shared_platform_data
mv78xx0_ge10_shared_data
=
{
.
t_clk
=
0
,
.
dram
=
&
mv78xx0_mbus_dram_info
,
.
shared_smi
=
&
mv78xx0_ge00_shared
,
};
static
struct
resource
mv78xx0_ge10_shared_resources
[]
=
{
...
...
@@ -424,7 +425,6 @@ static struct platform_device mv78xx0_ge10 = {
void
__init
mv78xx0_ge10_init
(
struct
mv643xx_eth_platform_data
*
eth_data
)
{
eth_data
->
shared
=
&
mv78xx0_ge10_shared
;
eth_data
->
shared_smi
=
&
mv78xx0_ge00_shared
;
mv78xx0_ge10
.
dev
.
platform_data
=
eth_data
;
platform_device_register
(
&
mv78xx0_ge10_shared
);
...
...
@@ -438,6 +438,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
struct
mv643xx_eth_shared_platform_data
mv78xx0_ge11_shared_data
=
{
.
t_clk
=
0
,
.
dram
=
&
mv78xx0_mbus_dram_info
,
.
shared_smi
=
&
mv78xx0_ge00_shared
,
};
static
struct
resource
mv78xx0_ge11_shared_resources
[]
=
{
...
...
@@ -478,7 +479,6 @@ static struct platform_device mv78xx0_ge11 = {
void
__init
mv78xx0_ge11_init
(
struct
mv643xx_eth_platform_data
*
eth_data
)
{
eth_data
->
shared
=
&
mv78xx0_ge11_shared
;
eth_data
->
shared_smi
=
&
mv78xx0_ge00_shared
;
mv78xx0_ge11
.
dev
.
platform_data
=
eth_data
;
platform_device_register
(
&
mv78xx0_ge11_shared
);
...
...
arch/arm/mach-mv78xx0/db78x00-bp-setup.c
View file @
ae19161e
...
...
@@ -19,19 +19,19 @@
#include "common.h"
static
struct
mv643xx_eth_platform_data
db78x00_ge00_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
static
struct
mv643xx_eth_platform_data
db78x00_ge01_data
=
{
.
phy_addr
=
9
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
9
)
,
};
static
struct
mv643xx_eth_platform_data
db78x00_ge10_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
};
static
struct
mv643xx_eth_platform_data
db78x00_ge11_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
};
static
struct
mv_sata_platform_data
db78x00_sata_data
=
{
...
...
arch/arm/mach-orion5x/db88f5281-setup.c
View file @
ae19161e
...
...
@@ -285,7 +285,7 @@ subsys_initcall(db88f5281_pci_init);
* Ethernet
****************************************************************************/
static
struct
mv643xx_eth_platform_data
db88f5281_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
/*****************************************************************************
...
...
arch/arm/mach-orion5x/dns323-setup.c
View file @
ae19161e
...
...
@@ -79,7 +79,7 @@ subsys_initcall(dns323_pci_init);
*/
static
struct
mv643xx_eth_platform_data
dns323_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
/****************************************************************************
...
...
arch/arm/mach-orion5x/kurobox_pro-setup.c
View file @
ae19161e
...
...
@@ -161,7 +161,7 @@ subsys_initcall(kurobox_pro_pci_init);
****************************************************************************/
static
struct
mv643xx_eth_platform_data
kurobox_pro_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
/*****************************************************************************
...
...
arch/arm/mach-orion5x/mss2-setup.c
View file @
ae19161e
...
...
@@ -109,7 +109,7 @@ subsys_initcall(mss2_pci_init);
****************************************************************************/
static
struct
mv643xx_eth_platform_data
mss2_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
/*****************************************************************************
...
...
arch/arm/mach-orion5x/mv2120-setup.c
View file @
ae19161e
...
...
@@ -39,7 +39,7 @@
* Ethernet
****************************************************************************/
static
struct
mv643xx_eth_platform_data
mv2120_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
static
struct
mv_sata_platform_data
mv2120_sata_data
=
{
...
...
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
View file @
ae19161e
...
...
@@ -88,7 +88,7 @@ static struct orion5x_mpp_mode rd88f5181l_fxo_mpp_modes[] __initdata = {
};
static
struct
mv643xx_eth_platform_data
rd88f5181l_fxo_eth_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
.
speed
=
SPEED_1000
,
.
duplex
=
DUPLEX_FULL
,
};
...
...
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
View file @
ae19161e
...
...
@@ -89,7 +89,7 @@ static struct orion5x_mpp_mode rd88f5181l_ge_mpp_modes[] __initdata = {
};
static
struct
mv643xx_eth_platform_data
rd88f5181l_ge_eth_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
.
speed
=
SPEED_1000
,
.
duplex
=
DUPLEX_FULL
,
};
...
...
arch/arm/mach-orion5x/rd88f5182-setup.c
View file @
ae19161e
...
...
@@ -221,7 +221,7 @@ subsys_initcall(rd88f5182_pci_init);
****************************************************************************/
static
struct
mv643xx_eth_platform_data
rd88f5182_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
/*****************************************************************************
...
...
arch/arm/mach-orion5x/ts78xx-setup.c
View file @
ae19161e
...
...
@@ -103,8 +103,7 @@ static struct platform_device ts78xx_nor_boot_flash = {
* Ethernet
****************************************************************************/
static
struct
mv643xx_eth_platform_data
ts78xx_eth_data
=
{
.
phy_addr
=
0
,
.
force_phy_addr
=
1
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
0
),
};
/*****************************************************************************
...
...
arch/arm/mach-orion5x/tsx09-common.c
View file @
ae19161e
...
...
@@ -48,7 +48,7 @@ void qnap_tsx09_power_off(void)
****************************************************************************/
struct
mv643xx_eth_platform_data
qnap_tsx09_eth_data
=
{
.
phy_addr
=
8
,
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
8
)
,
};
static
int
__init
qnap_tsx09_parse_hex_nibble
(
char
n
)
...
...
arch/arm/mach-orion5x/wnr854t-setup.c
View file @
ae19161e
...
...
@@ -92,7 +92,7 @@ static struct platform_device wnr854t_nor_flash = {
};
static
struct
mv643xx_eth_platform_data
wnr854t_eth_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
.
speed
=
SPEED_1000
,
.
duplex
=
DUPLEX_FULL
,
};
...
...
arch/arm/mach-orion5x/wrt350n-v2-setup.c
View file @
ae19161e
...
...
@@ -100,7 +100,7 @@ static struct platform_device wrt350n_v2_nor_flash = {
};
static
struct
mv643xx_eth_platform_data
wrt350n_v2_eth_data
=
{
.
phy_addr
=
-
1
,
.
phy_addr
=
MV643XX_ETH_PHY_NONE
,
.
speed
=
SPEED_1000
,
.
duplex
=
DUPLEX_FULL
,
};
...
...
arch/powerpc/sysdev/mv64x60_dev.c
View file @
ae19161e
...
...
@@ -293,10 +293,8 @@ static int __init mv64x60_eth_device_setup(struct device_node *np, int id,
return
-
ENODEV
;
prop
=
of_get_property
(
phy
,
"reg"
,
NULL
);
if
(
prop
)
{
pdata
.
force_phy_addr
=
1
;
pdata
.
phy_addr
=
*
prop
;
}
if
(
prop
)
pdata
.
phy_addr
=
MV643XX_ETH_PHY_ADDR
(
*
prop
);
of_node_put
(
phy
);
...
...
drivers/net/Kconfig
View file @
ae19161e
...
...
@@ -2274,7 +2274,7 @@ config UGETH_TX_ON_DEMAND
config MV643XX_ETH
tristate "Marvell Discovery (643XX) and Orion ethernet support"
depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
select
MII
select
PHYLIB
help
This driver supports the gigabit ethernet MACs in the
Marvell Discovery PPC/MIPS chipset family (MV643XX) and
...
...
drivers/net/mv643xx_eth.c
View file @
ae19161e
...
...
@@ -48,30 +48,28 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/
mii
.h>
#include <linux/
phy
.h>
#include <linux/mv643xx_eth.h>
#include <asm/io.h>
#include <asm/types.h>
#include <asm/system.h>
static
char
mv643xx_eth_driver_name
[]
=
"mv643xx_eth"
;
static
char
mv643xx_eth_driver_version
[]
=
"1.
3
"
;
static
char
mv643xx_eth_driver_version
[]
=
"1.
4
"
;
#define MV643XX_ETH_CHECKSUM_OFFLOAD_TX
#define MV643XX_ETH_NAPI
#define MV643XX_ETH_TX_FAST_REFILL
#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1)
#else
#define MAX_DESCS_PER_SKB 1
#endif
/*
* Registers shared between all ports.
*/
#define PHY_ADDR 0x0000
#define SMI_REG 0x0004
#define SMI_BUSY 0x10000000
#define SMI_READ_VALID 0x08000000
#define SMI_OPCODE_READ 0x04000000
#define SMI_OPCODE_WRITE 0x00000000
#define ERR_INT_CAUSE 0x0080
#define ERR_INT_SMI_DONE 0x00000010
#define ERR_INT_MASK 0x0084
#define WINDOW_BASE(w) (0x0200 + ((w) << 3))
#define WINDOW_SIZE(w) (0x0204 + ((w) << 3))
#define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2))
...
...
@@ -104,16 +102,12 @@ static char mv643xx_eth_driver_version[] = "1.3";
#define TX_BW_MTU(p) (0x0458 + ((p) << 10))
#define TX_BW_BURST(p) (0x045c + ((p) << 10))
#define INT_CAUSE(p) (0x0460 + ((p) << 10))
#define INT_TX_END_0 0x00080000
#define INT_TX_END 0x07f80000
#define INT_RX 0x000
7fb
fc
#define INT_RX 0x000
003
fc
#define INT_EXT 0x00000002
#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10))
#define INT_EXT_LINK 0x00100000
#define INT_EXT_PHY 0x00010000
#define INT_EXT_TX_ERROR_0 0x00000100
#define INT_EXT_TX_0 0x00000001
#define INT_EXT_TX 0x0000ffff
#define INT_EXT_LINK_PHY 0x00110000
#define INT_EXT_TX 0x000000ff
#define INT_MASK(p) (0x0468 + ((p) << 10))
#define INT_MASK_EXT(p) (0x046c + ((p) << 10))
#define TX_FIFO_URGENT_THRESHOLD(p) (0x0474 + ((p) << 10))
...
...
@@ -171,8 +165,8 @@ static char mv643xx_eth_driver_version[] = "1.3";
#define FORCE_LINK_PASS (1 << 1)
#define SERIAL_PORT_ENABLE (1 << 0)
#define DEFAULT_RX_QUEUE_SIZE
400
#define DEFAULT_TX_QUEUE_SIZE
800
#define DEFAULT_RX_QUEUE_SIZE
128
#define DEFAULT_TX_QUEUE_SIZE
256
/*
...
...
@@ -249,9 +243,23 @@ struct mv643xx_eth_shared_private {
void
__iomem
*
base
;
/*
* Protects access to SMI_REG, which is shared between ports.
* Points at the right SMI instance to use.
*/
struct
mv643xx_eth_shared_private
*
smi
;
/*
* Provides access to local SMI interface.
*/
spinlock_t
phy_lock
;
struct
mii_bus
smi_bus
;
/*
* If we have access to the error interrupt pin (which is
* somewhat misnamed as it not only reflects internal errors
* but also reflects SMI completion), use that to wait for
* SMI access completion instead of polling the SMI busy bit.
*/
int
err_interrupt
;
wait_queue_head_t
smi_busy_wait
;
/*
* Per-port MBUS window access register value.
...
...
@@ -263,9 +271,13 @@ struct mv643xx_eth_shared_private {
*/
unsigned
int
t_clk
;
int
extended_rx_coal_limit
;
int
tx_bw_control
_moved
;
int
tx_bw_control
;
};
#define TX_BW_CONTROL_ABSENT 0
#define TX_BW_CONTROL_OLD_LAYOUT 1
#define TX_BW_CONTROL_NEW_LAYOUT 2
/* per-port *****************************************************************/
struct
mib_counters
{
...
...
@@ -314,8 +326,6 @@ struct rx_queue {
dma_addr_t
rx_desc_dma
;
int
rx_desc_area_size
;
struct
sk_buff
**
rx_skb
;
struct
timer_list
rx_oom
;
};
struct
tx_queue
{
...
...
@@ -330,7 +340,12 @@ struct tx_queue {
struct
tx_desc
*
tx_desc_area
;
dma_addr_t
tx_desc_dma
;
int
tx_desc_area_size
;
struct
sk_buff
**
tx_skb
;
struct
sk_buff_head
tx_skb
;
unsigned
long
tx_packets
;
unsigned
long
tx_bytes
;
unsigned
long
tx_dropped
;
};
struct
mv643xx_eth_private
{
...
...
@@ -339,14 +354,21 @@ struct mv643xx_eth_private {
struct
net_device
*
dev
;
struct
mv643xx_eth_shared_private
*
shared_smi
;
int
phy_addr
;
spinlock_t
lock
;
struct
phy_device
*
phy
;
struct
timer_list
mib_counters_timer
;
spinlock_t
mib_counters_lock
;
struct
mib_counters
mib_counters
;
struct
work_struct
tx_timeout_task
;
struct
mii_if_info
mii
;
struct
napi_struct
napi
;
u8
work_link
;
u8
work_tx
;
u8
work_tx_end
;
u8
work_rx
;
u8
work_rx_refill
;
u8
work_rx_oom
;
/*
* RX state.
...
...
@@ -354,9 +376,8 @@ struct mv643xx_eth_private {
int
default_rx_ring_size
;
unsigned
long
rx_desc_sram_addr
;
int
rx_desc_sram_size
;
u8
rxq_mask
;
int
rxq_primary
;
struct
napi_struct
napi
;
int
rxq_count
;
struct
timer_list
rx_oom
;
struct
rx_queue
rxq
[
8
];
/*
...
...
@@ -365,12 +386,8 @@ struct mv643xx_eth_private {
int
default_tx_ring_size
;
unsigned
long
tx_desc_sram_addr
;
int
tx_desc_sram_size
;
u8
txq_mask
;
int
txq_primary
;
int
txq_count
;
struct
tx_queue
txq
[
8
];
#ifdef MV643XX_ETH_TX_FAST_REFILL
int
tx_clean_threshold
;
#endif
};
...
...
@@ -440,94 +457,21 @@ static void txq_disable(struct tx_queue *txq)
udelay
(
10
);
}
static
void
__
txq_maybe_wake
(
struct
tx_queue
*
txq
)
static
void
txq_maybe_wake
(
struct
tx_queue
*
txq
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
struct
netdev_queue
*
nq
=
netdev_get_tx_queue
(
mp
->
dev
,
txq
->
index
);
/*
* netif_{stop,wake}_queue() flow control only applies to
* the primary queue.
*/
BUG_ON
(
txq
->
index
!=
mp
->
txq_primary
);
if
(
txq
->
tx_ring_size
-
txq
->
tx_desc_count
>=
MAX_DESCS_PER_SKB
)
netif_wake_queue
(
mp
->
dev
);
}
/* rx ***********************************************************************/
static
void
txq_reclaim
(
struct
tx_queue
*
txq
,
int
force
);
static
void
rxq_refill
(
struct
rx_queue
*
rxq
)
{
struct
mv643xx_eth_private
*
mp
=
rxq_to_mp
(
rxq
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
mp
->
lock
,
flags
);
while
(
rxq
->
rx_desc_count
<
rxq
->
rx_ring_size
)
{
int
skb_size
;
struct
sk_buff
*
skb
;
int
unaligned
;
int
rx
;
/*
* Reserve 2+14 bytes for an ethernet header (the
* hardware automatically prepends 2 bytes of dummy
* data to each received packet), 16 bytes for up to
* four VLAN tags, and 4 bytes for the trailing FCS
* -- 36 bytes total.
*/
skb_size
=
mp
->
dev
->
mtu
+
36
;
/*
* Make sure that the skb size is a multiple of 8
* bytes, as the lower three bits of the receive
* descriptor's buffer size field are ignored by
* the hardware.
*/
skb_size
=
(
skb_size
+
7
)
&
~
7
;
skb
=
dev_alloc_skb
(
skb_size
+
dma_get_cache_alignment
()
-
1
);
if
(
skb
==
NULL
)
break
;
unaligned
=
(
u32
)
skb
->
data
&
(
dma_get_cache_alignment
()
-
1
);
if
(
unaligned
)
skb_reserve
(
skb
,
dma_get_cache_alignment
()
-
unaligned
);
rxq
->
rx_desc_count
++
;
rx
=
rxq
->
rx_used_desc
;
rxq
->
rx_used_desc
=
(
rx
+
1
)
%
rxq
->
rx_ring_size
;
rxq
->
rx_desc_area
[
rx
].
buf_ptr
=
dma_map_single
(
NULL
,
skb
->
data
,
skb_size
,
DMA_FROM_DEVICE
);
rxq
->
rx_desc_area
[
rx
].
buf_size
=
skb_size
;
rxq
->
rx_skb
[
rx
]
=
skb
;
wmb
();
rxq
->
rx_desc_area
[
rx
].
cmd_sts
=
BUFFER_OWNED_BY_DMA
|
RX_ENABLE_INTERRUPT
;
wmb
();
/*
* The hardware automatically prepends 2 bytes of
* dummy data to each received packet, so that the
* IP header ends up 16-byte aligned.
*/
skb_reserve
(
skb
,
2
);
if
(
netif_tx_queue_stopped
(
nq
))
{
__netif_tx_lock
(
nq
,
smp_processor_id
());
if
(
txq
->
tx_ring_size
-
txq
->
tx_desc_count
>=
MAX_SKB_FRAGS
+
1
)
netif_tx_wake_queue
(
nq
);
__netif_tx_unlock
(
nq
);
}
if
(
rxq
->
rx_desc_count
!=
rxq
->
rx_ring_size
)
mod_timer
(
&
rxq
->
rx_oom
,
jiffies
+
(
HZ
/
10
));
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
}
static
inline
void
rxq_refill_timer_wrapper
(
unsigned
long
data
)
{
rxq_refill
((
struct
rx_queue
*
)
data
);
}
/* rx napi ******************************************************************/
static
int
rxq_process
(
struct
rx_queue
*
rxq
,
int
budget
)
{
struct
mv643xx_eth_private
*
mp
=
rxq_to_mp
(
rxq
);
...
...
@@ -539,31 +483,31 @@ static int rxq_process(struct rx_queue *rxq, int budget)
struct
rx_desc
*
rx_desc
;
unsigned
int
cmd_sts
;
struct
sk_buff
*
skb
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
mp
->
lock
,
flags
);
u16
byte_cnt
;
rx_desc
=
&
rxq
->
rx_desc_area
[
rxq
->
rx_curr_desc
];
cmd_sts
=
rx_desc
->
cmd_sts
;
if
(
cmd_sts
&
BUFFER_OWNED_BY_DMA
)
{
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
if
(
cmd_sts
&
BUFFER_OWNED_BY_DMA
)
break
;
}
rmb
();
skb
=
rxq
->
rx_skb
[
rxq
->
rx_curr_desc
];
rxq
->
rx_skb
[
rxq
->
rx_curr_desc
]
=
NULL
;
rxq
->
rx_curr_desc
=
(
rxq
->
rx_curr_desc
+
1
)
%
rxq
->
rx_ring_size
;
rxq
->
rx_curr_desc
++
;
if
(
rxq
->
rx_curr_desc
==
rxq
->
rx_ring_size
)
rxq
->
rx_curr_desc
=
0
;
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
dma_unmap_single
(
NULL
,
rx_desc
->
buf_ptr
+
2
,
dma_unmap_single
(
NULL
,
rx_desc
->
buf_ptr
,
rx_desc
->
buf_size
,
DMA_FROM_DEVICE
);
rxq
->
rx_desc_count
--
;
rx
++
;
mp
->
work_rx_refill
|=
1
<<
rxq
->
index
;
byte_cnt
=
rx_desc
->
byte_cnt
;
/*
* Update statistics.
*
...
...
@@ -573,7 +517,7 @@ static int rxq_process(struct rx_queue *rxq, int budget)
* byte CRC at the end of the packet (which we do count).
*/
stats
->
rx_packets
++
;
stats
->
rx_bytes
+=
rx_desc
->
byte_cnt
-
2
;
stats
->
rx_bytes
+=
byte_cnt
-
2
;
/*
* In case we received a packet without first / last bits
...
...
@@ -596,72 +540,96 @@ static int rxq_process(struct rx_queue *rxq, int budget)
if
(
cmd_sts
&
ERROR_SUMMARY
)
stats
->
rx_errors
++
;
dev_kfree_skb
_irq
(
skb
);
dev_kfree_skb
(
skb
);
}
else
{
/*
* The -4 is for the CRC in the trailer of the
* received packet
*/
skb_put
(
skb
,
rx_desc
->
byte_cnt
-
2
-
4
);
skb_put
(
skb
,
byte_cnt
-
2
-
4
);
if
(
cmd_sts
&
LAYER_4_CHECKSUM_OK
)
{
if
(
cmd_sts
&
LAYER_4_CHECKSUM_OK
)
skb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
skb
->
csum
=
htons
(
(
cmd_sts
&
0x0007fff8
)
>>
3
);
}
skb
->
protocol
=
eth_type_trans
(
skb
,
mp
->
dev
);
#ifdef MV643XX_ETH_NAPI
netif_receive_skb
(
skb
);
#else
netif_rx
(
skb
);
#endif
}
mp
->
dev
->
last_rx
=
jiffies
;
}
rxq_refill
(
rxq
);
if
(
rx
<
budget
)
mp
->
work_rx
&=
~
(
1
<<
rxq
->
index
);
return
rx
;
}
#ifdef MV643XX_ETH_NAPI
static
int
mv643xx_eth_poll
(
struct
napi_struct
*
napi
,
int
budget
)
static
int
rxq_refill
(
struct
rx_queue
*
rxq
,
int
budget
)
{
struct
mv643xx_eth_private
*
mp
;
int
rx
;
int
i
;
struct
mv643xx_eth_private
*
mp
=
rxq_to_mp
(
rxq
)
;
int
skb_size
;
int
refilled
;
mp
=
container_of
(
napi
,
struct
mv643xx_eth_private
,
napi
);
/*
* Reserve 2+14 bytes for an ethernet header (the hardware
* automatically prepends 2 bytes of dummy data to each
* received packet), 16 bytes for up to four VLAN tags, and
* 4 bytes for the trailing FCS -- 36 bytes total.
*/
skb_size
=
rxq_to_mp
(
rxq
)
->
dev
->
mtu
+
36
;
#ifdef MV643XX_ETH_TX_FAST_REFILL
if
(
++
mp
->
tx_clean_threshold
>
5
)
{
mp
->
tx_clean_threshold
=
0
;
for
(
i
=
0
;
i
<
8
;
i
++
)
if
(
mp
->
txq_mask
&
(
1
<<
i
))
txq_reclaim
(
mp
->
txq
+
i
,
0
);
if
(
netif_carrier_ok
(
mp
->
dev
))
{
spin_lock_irq
(
&
mp
->
lock
);
__txq_maybe_wake
(
mp
->
txq
+
mp
->
txq_primary
);
spin_unlock_irq
(
&
mp
->
lock
);
/*
* Make sure that the skb size is a multiple of 8 bytes, as
* the lower three bits of the receive descriptor's buffer
* size field are ignored by the hardware.
*/
skb_size
=
(
skb_size
+
7
)
&
~
7
;
refilled
=
0
;
while
(
refilled
<
budget
&&
rxq
->
rx_desc_count
<
rxq
->
rx_ring_size
)
{
struct
sk_buff
*
skb
;
int
unaligned
;
int
rx
;
skb
=
dev_alloc_skb
(
skb_size
+
dma_get_cache_alignment
()
-
1
);
if
(
skb
==
NULL
)
{
mp
->
work_rx_oom
|=
1
<<
rxq
->
index
;
goto
oom
;
}
}
#endif
rx
=
0
;
for
(
i
=
7
;
rx
<
budget
&&
i
>=
0
;
i
--
)
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rx
+=
rxq_process
(
mp
->
rxq
+
i
,
budget
-
rx
);
unaligned
=
(
u32
)
skb
->
data
&
(
dma_get_cache_alignment
()
-
1
);
if
(
unaligned
)
skb_reserve
(
skb
,
dma_get_cache_alignment
()
-
unaligned
);
if
(
rx
<
budget
)
{
netif_rx_complete
(
mp
->
dev
,
napi
);
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
INT_TX_END
|
INT_RX
|
INT_EXT
);
refilled
++
;
rxq
->
rx_desc_count
++
;
rx
=
rxq
->
rx_used_desc
++
;
if
(
rxq
->
rx_used_desc
==
rxq
->
rx_ring_size
)
rxq
->
rx_used_desc
=
0
;
rxq
->
rx_desc_area
[
rx
].
buf_ptr
=
dma_map_single
(
NULL
,
skb
->
data
,
skb_size
,
DMA_FROM_DEVICE
);
rxq
->
rx_desc_area
[
rx
].
buf_size
=
skb_size
;
rxq
->
rx_skb
[
rx
]
=
skb
;
wmb
();
rxq
->
rx_desc_area
[
rx
].
cmd_sts
=
BUFFER_OWNED_BY_DMA
|
RX_ENABLE_INTERRUPT
;
wmb
();
/*
* The hardware automatically prepends 2 bytes of
* dummy data to each received packet, so that the
* IP header ends up 16-byte aligned.
*/
skb_reserve
(
skb
,
2
);
}
return
rx
;
if
(
refilled
<
budget
)
mp
->
work_rx_refill
&=
~
(
1
<<
rxq
->
index
);
oom:
return
refilled
;
}
#endif
/* tx ***********************************************************************/
...
...
@@ -684,8 +652,9 @@ static int txq_alloc_desc_index(struct tx_queue *txq)
BUG_ON
(
txq
->
tx_desc_count
>=
txq
->
tx_ring_size
);
tx_desc_curr
=
txq
->
tx_curr_desc
;
txq
->
tx_curr_desc
=
(
tx_desc_curr
+
1
)
%
txq
->
tx_ring_size
;
tx_desc_curr
=
txq
->
tx_curr_desc
++
;
if
(
txq
->
tx_curr_desc
==
txq
->
tx_ring_size
)
txq
->
tx_curr_desc
=
0
;
BUG_ON
(
txq
->
tx_curr_desc
==
txq
->
tx_used_desc
);
...
...
@@ -714,10 +683,8 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
desc
->
cmd_sts
=
BUFFER_OWNED_BY_DMA
|
ZERO_PADDING
|
TX_LAST_DESC
|
TX_ENABLE_INTERRUPT
;
txq
->
tx_skb
[
tx_index
]
=
skb
;
}
else
{
desc
->
cmd_sts
=
BUFFER_OWNED_BY_DMA
;
txq
->
tx_skb
[
tx_index
]
=
NULL
;
}
desc
->
l4i_chk
=
0
;
...
...
@@ -734,144 +701,222 @@ static inline __be16 sum16_as_be(__sum16 sum)
return
(
__force
__be16
)
sum
;
}
static
void
txq_submit_skb
(
struct
tx_queue
*
txq
,
struct
sk_buff
*
skb
)
static
int
txq_submit_skb
(
struct
tx_queue
*
txq
,
struct
sk_buff
*
skb
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
int
nr_frags
=
skb_shinfo
(
skb
)
->
nr_frags
;
int
tx_index
;
struct
tx_desc
*
desc
;
u32
cmd_sts
;
u16
l4i_chk
;
int
length
;
cmd_sts
=
TX_FIRST_DESC
|
GEN_CRC
|
BUFFER_OWNED_BY_DMA
;
tx_index
=
txq_alloc_desc_index
(
txq
);
desc
=
&
txq
->
tx_desc_area
[
tx_index
];
if
(
nr_frags
)
{
txq_submit_frag_skb
(
txq
,
skb
);
length
=
skb_headlen
(
skb
);
txq
->
tx_skb
[
tx_index
]
=
NULL
;
}
else
{
cmd_sts
|=
ZERO_PADDING
|
TX_LAST_DESC
|
TX_ENABLE_INTERRUPT
;
length
=
skb
->
len
;
txq
->
tx_skb
[
tx_index
]
=
skb
;
}
desc
->
byte_cnt
=
length
;
desc
->
buf_ptr
=
dma_map_single
(
NULL
,
skb
->
data
,
length
,
DMA_TO_DEVICE
);
l4i_chk
=
0
;
if
(
skb
->
ip_summed
==
CHECKSUM_PARTIAL
)
{
int
mac_hdr_len
;
int
tag_bytes
;
BUG_ON
(
skb
->
protocol
!=
htons
(
ETH_P_IP
)
&&
skb
->
protocol
!=
htons
(
ETH_P_8021Q
));
cmd_sts
|=
GEN_TCP_UDP_CHECKSUM
|
GEN_IP_V4_CHECKSUM
|
ip_hdr
(
skb
)
->
ihl
<<
TX_IHL_SHIFT
;
tag_bytes
=
(
void
*
)
ip_hdr
(
skb
)
-
(
void
*
)
skb
->
data
-
ETH_HLEN
;
if
(
unlikely
(
tag_bytes
&
~
12
))
{
if
(
skb_checksum_help
(
skb
)
==
0
)
goto
no_csum
;
kfree_skb
(
skb
);
return
1
;
}
mac_hdr_len
=
(
void
*
)
ip_hdr
(
skb
)
-
(
void
*
)
skb
->
data
;
switch
(
mac_hdr_len
-
ETH_HLEN
)
{
case
0
:
break
;
case
4
:
if
(
tag_bytes
&
4
)
cmd_sts
|=
MAC_HDR_EXTRA_4_BYTES
;
break
;
case
8
:
if
(
tag_bytes
&
8
)
cmd_sts
|=
MAC_HDR_EXTRA_8_BYTES
;
break
;
case
12
:
cmd_sts
|=
MAC_HDR_EXTRA_4_BYTES
;
cmd_sts
|=
MAC_HDR_EXTRA_8_BYTES
;
break
;
default:
if
(
net_ratelimit
())
dev_printk
(
KERN_ERR
,
&
txq_to_mp
(
txq
)
->
dev
->
dev
,
"mac header length is %d?!
\n
"
,
mac_hdr_len
);
break
;
}
cmd_sts
|=
GEN_TCP_UDP_CHECKSUM
|
GEN_IP_V4_CHECKSUM
|
ip_hdr
(
skb
)
->
ihl
<<
TX_IHL_SHIFT
;
switch
(
ip_hdr
(
skb
)
->
protocol
)
{
case
IPPROTO_UDP
:
cmd_sts
|=
UDP_FRAME
;
desc
->
l4i_chk
=
ntohs
(
sum16_as_be
(
udp_hdr
(
skb
)
->
check
));
l4i_chk
=
ntohs
(
sum16_as_be
(
udp_hdr
(
skb
)
->
check
));
break
;
case
IPPROTO_TCP
:
desc
->
l4i_chk
=
ntohs
(
sum16_as_be
(
tcp_hdr
(
skb
)
->
check
));
l4i_chk
=
ntohs
(
sum16_as_be
(
tcp_hdr
(
skb
)
->
check
));
break
;
default:
BUG
();
}
}
else
{
no_csum:
/* Errata BTS #50, IHL must be 5 if no HW checksum */
cmd_sts
|=
5
<<
TX_IHL_SHIFT
;
desc
->
l4i_chk
=
0
;
}
tx_index
=
txq_alloc_desc_index
(
txq
);
desc
=
&
txq
->
tx_desc_area
[
tx_index
];
if
(
nr_frags
)
{
txq_submit_frag_skb
(
txq
,
skb
);
length
=
skb_headlen
(
skb
);
}
else
{
cmd_sts
|=
ZERO_PADDING
|
TX_LAST_DESC
|
TX_ENABLE_INTERRUPT
;
length
=
skb
->
len
;
}
desc
->
l4i_chk
=
l4i_chk
;
desc
->
byte_cnt
=
length
;
desc
->
buf_ptr
=
dma_map_single
(
NULL
,
skb
->
data
,
length
,
DMA_TO_DEVICE
);
__skb_queue_tail
(
&
txq
->
tx_skb
,
skb
);
/* ensure all other descriptors are written before first cmd_sts */
wmb
();
desc
->
cmd_sts
=
cmd_sts
;
/* clear TX_END interrupt status */
wrl
(
mp
,
INT_CAUSE
(
mp
->
port_num
),
~
(
INT_TX_END_0
<<
txq
->
index
));
rdl
(
mp
,
INT_CAUSE
(
mp
->
port_num
));
/* clear TX_END status */
mp
->
work_tx_end
&=
~
(
1
<<
txq
->
index
);
/* ensure all descriptors are written before poking hardware */
wmb
();
txq_enable
(
txq
);
txq
->
tx_desc_count
+=
nr_frags
+
1
;
return
0
;
}
static
int
mv643xx_eth_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
dev
->
stats
;
int
queue
;
struct
tx_queue
*
txq
;
unsigned
long
flags
;
struct
netdev_queue
*
nq
;
queue
=
skb_get_queue_mapping
(
skb
);
txq
=
mp
->
txq
+
queue
;
nq
=
netdev_get_tx_queue
(
dev
,
queue
);
if
(
has_tiny_unaligned_frags
(
skb
)
&&
__skb_linearize
(
skb
))
{
stats
->
tx_dropped
++
;
txq
->
tx_dropped
++
;
dev_printk
(
KERN_DEBUG
,
&
dev
->
dev
,
"failed to linearize skb with tiny "
"unaligned fragment
\n
"
);
return
NETDEV_TX_BUSY
;
}
spin_lock_irqsave
(
&
mp
->
lock
,
flags
);
txq
=
mp
->
txq
+
mp
->
txq_primary
;
if
(
txq
->
tx_ring_size
-
txq
->
tx_desc_count
<
MAX_DESCS_PER_SKB
)
{
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
if
(
txq
->
index
==
mp
->
txq_primary
&&
net_ratelimit
())
dev_printk
(
KERN_ERR
,
&
dev
->
dev
,
"primary tx queue full?!
\n
"
);
if
(
txq
->
tx_ring_size
-
txq
->
tx_desc_count
<
MAX_SKB_FRAGS
+
1
)
{
if
(
net_ratelimit
())
dev_printk
(
KERN_ERR
,
&
dev
->
dev
,
"tx queue full?!
\n
"
);
kfree_skb
(
skb
);
return
NETDEV_TX_OK
;
}
txq_submit_skb
(
txq
,
skb
);
stats
->
tx_bytes
+=
skb
->
len
;
stats
->
tx_packets
++
;
dev
->
trans_start
=
jiffies
;
if
(
txq
->
index
==
mp
->
txq_primary
)
{
if
(
!
txq_submit_skb
(
txq
,
skb
))
{
int
entries_left
;
txq
->
tx_bytes
+=
skb
->
len
;
txq
->
tx_packets
++
;
dev
->
trans_start
=
jiffies
;
entries_left
=
txq
->
tx_ring_size
-
txq
->
tx_desc_count
;
if
(
entries_left
<
MAX_
DESCS_PER_SKB
)
netif_
stop_queue
(
dev
);
if
(
entries_left
<
MAX_
SKB_FRAGS
+
1
)
netif_
tx_stop_queue
(
nq
);
}
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
return
NETDEV_TX_OK
;
}
/* tx napi ******************************************************************/
static
void
txq_kick
(
struct
tx_queue
*
txq
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
struct
netdev_queue
*
nq
=
netdev_get_tx_queue
(
mp
->
dev
,
txq
->
index
);
u32
hw_desc_ptr
;
u32
expected_ptr
;
__netif_tx_lock
(
nq
,
smp_processor_id
());
if
(
rdl
(
mp
,
TXQ_COMMAND
(
mp
->
port_num
))
&
(
1
<<
txq
->
index
))
goto
out
;
hw_desc_ptr
=
rdl
(
mp
,
TXQ_CURRENT_DESC_PTR
(
mp
->
port_num
,
txq
->
index
));
expected_ptr
=
(
u32
)
txq
->
tx_desc_dma
+
txq
->
tx_curr_desc
*
sizeof
(
struct
tx_desc
);
if
(
hw_desc_ptr
!=
expected_ptr
)
txq_enable
(
txq
);
out:
__netif_tx_unlock
(
nq
);
mp
->
work_tx_end
&=
~
(
1
<<
txq
->
index
);
}
static
int
txq_reclaim
(
struct
tx_queue
*
txq
,
int
budget
,
int
force
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
struct
netdev_queue
*
nq
=
netdev_get_tx_queue
(
mp
->
dev
,
txq
->
index
);
int
reclaimed
;
__netif_tx_lock
(
nq
,
smp_processor_id
());
reclaimed
=
0
;
while
(
reclaimed
<
budget
&&
txq
->
tx_desc_count
>
0
)
{
int
tx_index
;
struct
tx_desc
*
desc
;
u32
cmd_sts
;
struct
sk_buff
*
skb
;
tx_index
=
txq
->
tx_used_desc
;
desc
=
&
txq
->
tx_desc_area
[
tx_index
];
cmd_sts
=
desc
->
cmd_sts
;
if
(
cmd_sts
&
BUFFER_OWNED_BY_DMA
)
{
if
(
!
force
)
break
;
desc
->
cmd_sts
=
cmd_sts
&
~
BUFFER_OWNED_BY_DMA
;
}
txq
->
tx_used_desc
=
tx_index
+
1
;
if
(
txq
->
tx_used_desc
==
txq
->
tx_ring_size
)
txq
->
tx_used_desc
=
0
;
reclaimed
++
;
txq
->
tx_desc_count
--
;
skb
=
NULL
;
if
(
cmd_sts
&
TX_LAST_DESC
)
skb
=
__skb_dequeue
(
&
txq
->
tx_skb
);
if
(
cmd_sts
&
ERROR_SUMMARY
)
{
dev_printk
(
KERN_INFO
,
&
mp
->
dev
->
dev
,
"tx error
\n
"
);
mp
->
dev
->
stats
.
tx_errors
++
;
}
if
(
cmd_sts
&
TX_FIRST_DESC
)
{
dma_unmap_single
(
NULL
,
desc
->
buf_ptr
,
desc
->
byte_cnt
,
DMA_TO_DEVICE
);
}
else
{
dma_unmap_page
(
NULL
,
desc
->
buf_ptr
,
desc
->
byte_cnt
,
DMA_TO_DEVICE
);
}
if
(
skb
)
dev_kfree_skb
(
skb
);
}
__netif_tx_unlock
(
nq
);
if
(
reclaimed
<
budget
)
mp
->
work_tx
&=
~
(
1
<<
txq
->
index
);
return
reclaimed
;
}
/* tx rate control **********************************************************/
/*
* Set total maximum TX rate (shared by all TX queues for this port)
...
...
@@ -895,14 +940,17 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst)
if
(
bucket_size
>
65535
)
bucket_size
=
65535
;
if
(
mp
->
shared
->
tx_bw_control_moved
)
{
wrl
(
mp
,
TX_BW_RATE_MOVED
(
mp
->
port_num
),
token_rate
);
wrl
(
mp
,
TX_BW_MTU_MOVED
(
mp
->
port_num
),
mtu
);
wrl
(
mp
,
TX_BW_BURST_MOVED
(
mp
->
port_num
),
bucket_size
);
}
else
{
switch
(
mp
->
shared
->
tx_bw_control
)
{
case
TX_BW_CONTROL_OLD_LAYOUT
:
wrl
(
mp
,
TX_BW_RATE
(
mp
->
port_num
),
token_rate
);
wrl
(
mp
,
TX_BW_MTU
(
mp
->
port_num
),
mtu
);
wrl
(
mp
,
TX_BW_BURST
(
mp
->
port_num
),
bucket_size
);
break
;
case
TX_BW_CONTROL_NEW_LAYOUT
:
wrl
(
mp
,
TX_BW_RATE_MOVED
(
mp
->
port_num
),
token_rate
);
wrl
(
mp
,
TX_BW_MTU_MOVED
(
mp
->
port_num
),
mtu
);
wrl
(
mp
,
TX_BW_BURST_MOVED
(
mp
->
port_num
),
bucket_size
);
break
;
}
}
...
...
@@ -934,14 +982,21 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq)
/*
* Turn on fixed priority mode.
*/
if
(
mp
->
shared
->
tx_bw_control_moved
)
off
=
TXQ_FIX_PRIO_CONF_MOVED
(
mp
->
port_num
);
else
off
=
0
;
switch
(
mp
->
shared
->
tx_bw_control
)
{
case
TX_BW_CONTROL_OLD_LAYOUT
:
off
=
TXQ_FIX_PRIO_CONF
(
mp
->
port_num
);
break
;
case
TX_BW_CONTROL_NEW_LAYOUT
:
off
=
TXQ_FIX_PRIO_CONF_MOVED
(
mp
->
port_num
);
break
;
}
val
=
rdl
(
mp
,
off
);
val
|=
1
<<
txq
->
index
;
wrl
(
mp
,
off
,
val
);
if
(
off
)
{
val
=
rdl
(
mp
,
off
);
val
|=
1
<<
txq
->
index
;
wrl
(
mp
,
off
,
val
);
}
}
static
void
txq_set_wrr
(
struct
tx_queue
*
txq
,
int
weight
)
...
...
@@ -953,95 +1008,147 @@ static void txq_set_wrr(struct tx_queue *txq, int weight)
/*
* Turn off fixed priority mode.
*/
if
(
mp
->
shared
->
tx_bw_control_moved
)
off
=
TXQ_FIX_PRIO_CONF_MOVED
(
mp
->
port_num
);
else
off
=
0
;
switch
(
mp
->
shared
->
tx_bw_control
)
{
case
TX_BW_CONTROL_OLD_LAYOUT
:
off
=
TXQ_FIX_PRIO_CONF
(
mp
->
port_num
);
break
;
case
TX_BW_CONTROL_NEW_LAYOUT
:
off
=
TXQ_FIX_PRIO_CONF_MOVED
(
mp
->
port_num
);
break
;
}
val
=
rdl
(
mp
,
off
);
val
&=
~
(
1
<<
txq
->
index
);
wrl
(
mp
,
off
,
val
);
if
(
off
)
{
val
=
rdl
(
mp
,
off
);
val
&=
~
(
1
<<
txq
->
index
);
wrl
(
mp
,
off
,
val
);
/*
* Configure WRR weight for this queue.
*/
off
=
TXQ_BW_WRR_CONF
(
mp
->
port_num
,
txq
->
index
);
/*
* Configure WRR weight for this queue.
*/
off
=
TXQ_BW_WRR_CONF
(
mp
->
port_num
,
txq
->
index
);
val
=
rdl
(
mp
,
off
);
val
=
(
val
&
~
0xff
)
|
(
weight
&
0xff
);
wrl
(
mp
,
off
,
val
);
val
=
rdl
(
mp
,
off
);
val
=
(
val
&
~
0xff
)
|
(
weight
&
0xff
);
wrl
(
mp
,
off
,
val
);
}
}
/* mii management interface *************************************************/
#define SMI_BUSY 0x10000000
#define SMI_READ_VALID 0x08000000
#define SMI_OPCODE_READ 0x04000000
#define SMI_OPCODE_WRITE 0x00000000
static
irqreturn_t
mv643xx_eth_err_irq
(
int
irq
,
void
*
dev_id
)
{
struct
mv643xx_eth_shared_private
*
msp
=
dev_id
;
if
(
readl
(
msp
->
base
+
ERR_INT_CAUSE
)
&
ERR_INT_SMI_DONE
)
{
writel
(
~
ERR_INT_SMI_DONE
,
msp
->
base
+
ERR_INT_CAUSE
);
wake_up
(
&
msp
->
smi_busy_wait
);
return
IRQ_HANDLED
;
}
return
IRQ_NONE
;
}
static
void
smi_reg_read
(
struct
mv643xx_eth_private
*
mp
,
unsigned
int
addr
,
unsigned
int
reg
,
unsigned
int
*
value
)
static
int
smi_is_done
(
struct
mv643xx_eth_shared_private
*
msp
)
{
void
__iomem
*
smi_reg
=
mp
->
shared_smi
->
base
+
SMI_REG
;
unsigned
long
flags
;
int
i
;
return
!
(
readl
(
msp
->
base
+
SMI_REG
)
&
SMI_BUSY
);
}
/* the SMI register is a shared resource */
spin_lock_irqsave
(
&
mp
->
shared_smi
->
phy_lock
,
flags
);
static
int
smi_wait_ready
(
struct
mv643xx_eth_shared_private
*
msp
)
{
if
(
msp
->
err_interrupt
==
NO_IRQ
)
{
int
i
;
/* wait for the SMI register to become available */
for
(
i
=
0
;
readl
(
smi_reg
)
&
SMI_BUSY
;
i
++
)
{
if
(
i
==
1000
)
{
printk
(
"%s: PHY busy timeout
\n
"
,
mp
->
dev
->
name
);
goto
out
;
for
(
i
=
0
;
!
smi_is_done
(
msp
);
i
++
)
{
if
(
i
==
10
)
return
-
ETIMEDOUT
;
msleep
(
10
);
}
udelay
(
10
);
return
0
;
}
if
(
!
wait_event_timeout
(
msp
->
smi_busy_wait
,
smi_is_done
(
msp
),
msecs_to_jiffies
(
100
)))
return
-
ETIMEDOUT
;
return
0
;
}
static
int
smi_bus_read
(
struct
mii_bus
*
bus
,
int
addr
,
int
reg
)
{
struct
mv643xx_eth_shared_private
*
msp
=
bus
->
priv
;
void
__iomem
*
smi_reg
=
msp
->
base
+
SMI_REG
;
int
ret
;
if
(
smi_wait_ready
(
msp
))
{
printk
(
"mv643xx_eth: SMI bus busy timeout
\n
"
);
return
-
ETIMEDOUT
;
}
writel
(
SMI_OPCODE_READ
|
(
reg
<<
21
)
|
(
addr
<<
16
),
smi_reg
);
/* now wait for the data to be valid */
for
(
i
=
0
;
!
(
readl
(
smi_reg
)
&
SMI_READ_VALID
);
i
++
)
{
if
(
i
==
1000
)
{
printk
(
"%s: PHY read timeout
\n
"
,
mp
->
dev
->
name
);
goto
out
;
}
udelay
(
10
);
if
(
smi_wait_ready
(
msp
))
{
printk
(
"mv643xx_eth: SMI bus busy timeout
\n
"
);
return
-
ETIMEDOUT
;
}
*
value
=
readl
(
smi_reg
)
&
0xffff
;
out:
spin_unlock_irqrestore
(
&
mp
->
shared_smi
->
phy_lock
,
flags
);
ret
=
readl
(
smi_reg
);
if
(
!
(
ret
&
SMI_READ_VALID
))
{
printk
(
"mv643xx_eth: SMI bus read not valid
\n
"
);
return
-
ENODEV
;
}
return
ret
&
0xffff
;
}
static
void
smi_reg_write
(
struct
mv643xx_eth_private
*
mp
,
unsigned
int
addr
,
unsigned
int
reg
,
unsigned
int
value
)
static
int
smi_bus_write
(
struct
mii_bus
*
bus
,
int
addr
,
int
reg
,
u16
val
)
{
void
__iomem
*
smi_reg
=
mp
->
shared_smi
->
base
+
SMI_REG
;
unsigned
long
flags
;
struct
mv643xx_eth_shared_private
*
msp
=
bus
->
priv
;
void
__iomem
*
smi_reg
=
msp
->
base
+
SMI_REG
;
if
(
smi_wait_ready
(
msp
))
{
printk
(
"mv643xx_eth: SMI bus busy timeout
\n
"
);
return
-
ETIMEDOUT
;
}
writel
(
SMI_OPCODE_WRITE
|
(
reg
<<
21
)
|
(
addr
<<
16
)
|
(
val
&
0xffff
),
smi_reg
);
if
(
smi_wait_ready
(
msp
))
{
printk
(
"mv643xx_eth: SMI bus busy timeout
\n
"
);
return
-
ETIMEDOUT
;
}
return
0
;
}
/* statistics ***************************************************************/
static
struct
net_device_stats
*
mv643xx_eth_get_stats
(
struct
net_device
*
dev
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
struct
net_device_stats
*
stats
=
&
dev
->
stats
;
unsigned
long
tx_packets
=
0
;
unsigned
long
tx_bytes
=
0
;
unsigned
long
tx_dropped
=
0
;
int
i
;
/* the SMI register is a shared resource */
spin_lock_irqsave
(
&
mp
->
shared_smi
->
phy_lock
,
flags
)
;
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
{
struct
tx_queue
*
txq
=
mp
->
txq
+
i
;
/* wait for the SMI register to become available */
for
(
i
=
0
;
readl
(
smi_reg
)
&
SMI_BUSY
;
i
++
)
{
if
(
i
==
1000
)
{
printk
(
"%s: PHY busy timeout
\n
"
,
mp
->
dev
->
name
);
goto
out
;
}
udelay
(
10
);
tx_packets
+=
txq
->
tx_packets
;
tx_bytes
+=
txq
->
tx_bytes
;
tx_dropped
+=
txq
->
tx_dropped
;
}
writel
(
SMI_OPCODE_WRITE
|
(
reg
<<
21
)
|
(
addr
<<
16
)
|
(
value
&
0xffff
),
smi_reg
);
out:
spin_unlock_irqrestore
(
&
mp
->
shared_smi
->
phy_lock
,
flags
);
}
stats
->
tx_packets
=
tx_packets
;
stats
->
tx_bytes
=
tx_bytes
;
stats
->
tx_dropped
=
tx_dropped
;
return
stats
;
}
/* mib counters *************************************************************/
static
inline
u32
mib_read
(
struct
mv643xx_eth_private
*
mp
,
int
offset
)
{
return
rdl
(
mp
,
MIB_COUNTERS
(
mp
->
port_num
)
+
offset
);
...
...
@@ -1059,6 +1166,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
{
struct
mib_counters
*
p
=
&
mp
->
mib_counters
;
spin_lock
(
&
mp
->
mib_counters_lock
);
p
->
good_octets_received
+=
mib_read
(
mp
,
0x00
);
p
->
good_octets_received
+=
(
u64
)
mib_read
(
mp
,
0x04
)
<<
32
;
p
->
bad_octets_received
+=
mib_read
(
mp
,
0x08
);
...
...
@@ -1091,6 +1199,16 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
p
->
bad_crc_event
+=
mib_read
(
mp
,
0x74
);
p
->
collision
+=
mib_read
(
mp
,
0x78
);
p
->
late_collision
+=
mib_read
(
mp
,
0x7c
);
spin_unlock
(
&
mp
->
mib_counters_lock
);
mod_timer
(
&
mp
->
mib_counters_timer
,
jiffies
+
30
*
HZ
);
}
static
void
mib_counters_timer_wrapper
(
unsigned
long
_mp
)
{
struct
mv643xx_eth_private
*
mp
=
(
void
*
)
_mp
;
mib_counters_update
(
mp
);
}
...
...
@@ -1156,9 +1274,9 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
int
err
;
spin_lock_irq
(
&
mp
->
lock
);
err
=
mii_ethtool_gset
(
&
mp
->
mii
,
cmd
);
spin_unlock_irq
(
&
mp
->
lock
);
err
=
phy_read_status
(
mp
->
phy
);
if
(
err
==
0
)
err
=
phy_ethtool_gset
(
mp
->
phy
,
cmd
);
/*
* The MAC does not support 1000baseT_Half.
...
...
@@ -1206,18 +1324,13 @@ static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethto
static
int
mv643xx_eth_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
int
err
;
/*
* The MAC does not support 1000baseT_Half.
*/
cmd
->
advertising
&=
~
ADVERTISED_1000baseT_Half
;
spin_lock_irq
(
&
mp
->
lock
);
err
=
mii_ethtool_sset
(
&
mp
->
mii
,
cmd
);
spin_unlock_irq
(
&
mp
->
lock
);
return
err
;
return
phy_ethtool_sset
(
mp
->
phy
,
cmd
);
}
static
int
mv643xx_eth_set_settings_phyless
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
...
...
@@ -1239,7 +1352,7 @@ static int mv643xx_eth_nway_reset(struct net_device *dev)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
return
mii_nway_restart
(
&
mp
->
mii
);
return
genphy_restart_aneg
(
mp
->
phy
);
}
static
int
mv643xx_eth_nway_reset_phyless
(
struct
net_device
*
dev
)
...
...
@@ -1249,14 +1362,7 @@ static int mv643xx_eth_nway_reset_phyless(struct net_device *dev)
static
u32
mv643xx_eth_get_link
(
struct
net_device
*
dev
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
return
mii_link_ok
(
&
mp
->
mii
);
}
static
u32
mv643xx_eth_get_link_phyless
(
struct
net_device
*
dev
)
{
return
1
;
return
!!
netif_carrier_ok
(
dev
);
}
static
void
mv643xx_eth_get_strings
(
struct
net_device
*
dev
,
...
...
@@ -1277,9 +1383,10 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
struct
ethtool_stats
*
stats
,
uint64_t
*
data
)
{
struct
mv643xx_eth_private
*
mp
=
dev
->
priv
;
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
)
;
int
i
;
mv643xx_eth_get_stats
(
dev
);
mib_counters_update
(
mp
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
mv643xx_eth_stats
);
i
++
)
{
...
...
@@ -1323,7 +1430,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = {
.
set_settings
=
mv643xx_eth_set_settings_phyless
,
.
get_drvinfo
=
mv643xx_eth_get_drvinfo
,
.
nway_reset
=
mv643xx_eth_nway_reset_phyless
,
.
get_link
=
mv643xx_eth_get_link
_phyless
,
.
get_link
=
mv643xx_eth_get_link
,
.
set_sg
=
ethtool_op_set_sg
,
.
get_strings
=
mv643xx_eth_get_strings
,
.
get_ethtool_stats
=
mv643xx_eth_get_ethtool_stats
,
...
...
@@ -1487,7 +1594,7 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
size
=
rxq
->
rx_ring_size
*
sizeof
(
struct
rx_desc
);
if
(
index
==
mp
->
rxq_primary
&&
size
<=
mp
->
rx_desc_sram_size
)
{
if
(
index
==
0
&&
size
<=
mp
->
rx_desc_sram_size
)
{
rxq
->
rx_desc_area
=
ioremap
(
mp
->
rx_desc_sram_addr
,
mp
->
rx_desc_sram_size
);
rxq
->
rx_desc_dma
=
mp
->
rx_desc_sram_addr
;
...
...
@@ -1515,20 +1622,21 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
rx_desc
=
(
struct
rx_desc
*
)
rxq
->
rx_desc_area
;
for
(
i
=
0
;
i
<
rxq
->
rx_ring_size
;
i
++
)
{
int
nexti
=
(
i
+
1
)
%
rxq
->
rx_ring_size
;
int
nexti
;
nexti
=
i
+
1
;
if
(
nexti
==
rxq
->
rx_ring_size
)
nexti
=
0
;
rx_desc
[
i
].
next_desc_ptr
=
rxq
->
rx_desc_dma
+
nexti
*
sizeof
(
struct
rx_desc
);
}
init_timer
(
&
rxq
->
rx_oom
);
rxq
->
rx_oom
.
data
=
(
unsigned
long
)
rxq
;
rxq
->
rx_oom
.
function
=
rxq_refill_timer_wrapper
;
return
0
;
out_free:
if
(
index
==
mp
->
rxq_primary
&&
size
<=
mp
->
rx_desc_sram_size
)
if
(
index
==
0
&&
size
<=
mp
->
rx_desc_sram_size
)
iounmap
(
rxq
->
rx_desc_area
);
else
dma_free_coherent
(
NULL
,
size
,
...
...
@@ -1546,8 +1654,6 @@ static void rxq_deinit(struct rx_queue *rxq)
rxq_disable
(
rxq
);
del_timer_sync
(
&
rxq
->
rx_oom
);
for
(
i
=
0
;
i
<
rxq
->
rx_ring_size
;
i
++
)
{
if
(
rxq
->
rx_skb
[
i
])
{
dev_kfree_skb
(
rxq
->
rx_skb
[
i
]);
...
...
@@ -1561,7 +1667,7 @@ static void rxq_deinit(struct rx_queue *rxq)
rxq
->
rx_desc_count
);
}
if
(
rxq
->
index
==
mp
->
rxq_primary
&&
if
(
rxq
->
index
==
0
&&
rxq
->
rx_desc_area_size
<=
mp
->
rx_desc_sram_size
)
iounmap
(
rxq
->
rx_desc_area
);
else
...
...
@@ -1588,7 +1694,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
size
=
txq
->
tx_ring_size
*
sizeof
(
struct
tx_desc
);
if
(
index
==
mp
->
txq_primary
&&
size
<=
mp
->
tx_desc_sram_size
)
{
if
(
index
==
0
&&
size
<=
mp
->
tx_desc_sram_size
)
{
txq
->
tx_desc_area
=
ioremap
(
mp
->
tx_desc_sram_addr
,
mp
->
tx_desc_sram_size
);
txq
->
tx_desc_dma
=
mp
->
tx_desc_sram_addr
;
...
...
@@ -1601,120 +1707,97 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
if
(
txq
->
tx_desc_area
==
NULL
)
{
dev_printk
(
KERN_ERR
,
&
mp
->
dev
->
dev
,
"can't allocate tx ring (%d bytes)
\n
"
,
size
);
goto
out
;
return
-
ENOMEM
;
}
memset
(
txq
->
tx_desc_area
,
0
,
size
);
txq
->
tx_desc_area_size
=
size
;
txq
->
tx_skb
=
kmalloc
(
txq
->
tx_ring_size
*
sizeof
(
*
txq
->
tx_skb
),
GFP_KERNEL
);
if
(
txq
->
tx_skb
==
NULL
)
{
dev_printk
(
KERN_ERR
,
&
mp
->
dev
->
dev
,
"can't allocate tx skb ring
\n
"
);
goto
out_free
;
}
tx_desc
=
(
struct
tx_desc
*
)
txq
->
tx_desc_area
;
for
(
i
=
0
;
i
<
txq
->
tx_ring_size
;
i
++
)
{
struct
tx_desc
*
txd
=
tx_desc
+
i
;
int
nexti
=
(
i
+
1
)
%
txq
->
tx_ring_size
;
int
nexti
;
nexti
=
i
+
1
;
if
(
nexti
==
txq
->
tx_ring_size
)
nexti
=
0
;
txd
->
cmd_sts
=
0
;
txd
->
next_desc_ptr
=
txq
->
tx_desc_dma
+
nexti
*
sizeof
(
struct
tx_desc
);
}
return
0
;
out_free:
if
(
index
==
mp
->
txq_primary
&&
size
<=
mp
->
tx_desc_sram_size
)
iounmap
(
txq
->
tx_desc_area
);
else
dma_free_coherent
(
NULL
,
size
,
txq
->
tx_desc_area
,
txq
->
tx_desc_dma
);
skb_queue_head_init
(
&
txq
->
tx_skb
);
out:
return
-
ENOMEM
;
return
0
;
}
static
void
txq_
reclaim
(
struct
tx_queue
*
txq
,
int
force
)
static
void
txq_
deinit
(
struct
tx_queue
*
txq
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
mp
->
lock
,
flags
);
while
(
txq
->
tx_desc_count
>
0
)
{
int
tx_index
;
struct
tx_desc
*
desc
;
u32
cmd_sts
;
struct
sk_buff
*
skb
;
dma_addr_t
addr
;
int
count
;
tx_index
=
txq
->
tx_used_desc
;
desc
=
&
txq
->
tx_desc_area
[
tx_index
];
cmd_sts
=
desc
->
cmd_sts
;
txq_disable
(
txq
);
txq_reclaim
(
txq
,
txq
->
tx_ring_size
,
1
);
if
(
cmd_sts
&
BUFFER_OWNED_BY_DMA
)
{
if
(
!
force
)
break
;
desc
->
cmd_sts
=
cmd_sts
&
~
BUFFER_OWNED_BY_DMA
;
}
BUG_ON
(
txq
->
tx_used_desc
!=
txq
->
tx_curr_desc
);
txq
->
tx_used_desc
=
(
tx_index
+
1
)
%
txq
->
tx_ring_size
;
txq
->
tx_desc_count
--
;
if
(
txq
->
index
==
0
&&
txq
->
tx_desc_area_size
<=
mp
->
tx_desc_sram_size
)
iounmap
(
txq
->
tx_desc_area
);
else
dma_free_coherent
(
NULL
,
txq
->
tx_desc_area_size
,
txq
->
tx_desc_area
,
txq
->
tx_desc_dma
);
}
addr
=
desc
->
buf_ptr
;
count
=
desc
->
byte_cnt
;
skb
=
txq
->
tx_skb
[
tx_index
];
txq
->
tx_skb
[
tx_index
]
=
NULL
;
if
(
cmd_sts
&
ERROR_SUMMARY
)
{
dev_printk
(
KERN_INFO
,
&
mp
->
dev
->
dev
,
"tx error
\n
"
);
mp
->
dev
->
stats
.
tx_errors
++
;
}
/* netdev ops and related ***************************************************/
static
int
mv643xx_eth_collect_events
(
struct
mv643xx_eth_private
*
mp
)
{
u32
int_cause
;
u32
int_cause_ext
;
/*
* Drop mp->lock while we free the skb.
*/
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
)
;
int_cause
=
rdl
(
mp
,
INT_CAUSE
(
mp
->
port_num
))
&
(
INT_TX_END
|
INT_RX
|
INT_EXT
);
if
(
int_cause
==
0
)
return
0
;
if
(
cmd_sts
&
TX_FIRST_DESC
)
dma_unmap_single
(
NULL
,
addr
,
count
,
DMA_TO_DEVICE
);
else
dma_unmap_page
(
NULL
,
addr
,
count
,
DMA_TO_DEVICE
);
int_cause_ext
=
0
;
if
(
int_cause
&
INT_EXT
)
int_cause_ext
=
rdl
(
mp
,
INT_CAUSE_EXT
(
mp
->
port_num
));
if
(
skb
)
dev_kfree_skb_irq
(
skb
);
int_cause
&=
INT_TX_END
|
INT_RX
;
if
(
int_cause
)
{
wrl
(
mp
,
INT_CAUSE
(
mp
->
port_num
),
~
int_cause
);
mp
->
work_tx_end
|=
((
int_cause
&
INT_TX_END
)
>>
19
)
&
~
(
rdl
(
mp
,
TXQ_COMMAND
(
mp
->
port_num
))
&
0xff
);
mp
->
work_rx
|=
(
int_cause
&
INT_RX
)
>>
2
;
}
spin_lock_irqsave
(
&
mp
->
lock
,
flags
);
int_cause_ext
&=
INT_EXT_LINK_PHY
|
INT_EXT_TX
;
if
(
int_cause_ext
)
{
wrl
(
mp
,
INT_CAUSE_EXT
(
mp
->
port_num
),
~
int_cause_ext
);
if
(
int_cause_ext
&
INT_EXT_LINK_PHY
)
mp
->
work_link
=
1
;
mp
->
work_tx
|=
int_cause_ext
&
INT_EXT_TX
;
}
spin_unlock_irqrestore
(
&
mp
->
lock
,
flags
);
return
1
;
}
static
void
txq_deinit
(
struct
tx_queue
*
txq
)
static
irqreturn_t
mv643xx_eth_irq
(
int
irq
,
void
*
dev_id
)
{
struct
mv643xx_eth_private
*
mp
=
txq_to_mp
(
txq
);
txq_disable
(
txq
);
txq_reclaim
(
txq
,
1
);
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
BUG_ON
(
txq
->
tx_used_desc
!=
txq
->
tx_curr_desc
);
if
(
unlikely
(
!
mv643xx_eth_collect_events
(
mp
)))
return
IRQ_NONE
;
if
(
txq
->
index
==
mp
->
txq_primary
&&
txq
->
tx_desc_area_size
<=
mp
->
tx_desc_sram_size
)
iounmap
(
txq
->
tx_desc_area
);
else
dma_free_coherent
(
NULL
,
txq
->
tx_desc_area_size
,
txq
->
tx_desc_area
,
txq
->
tx_desc_dma
);
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
0
);
napi_schedule
(
&
mp
->
napi
);
kfree
(
txq
->
tx_skb
)
;
return
IRQ_HANDLED
;
}
/* netdev ops and related ***************************************************/
static
void
handle_link_event
(
struct
mv643xx_eth_private
*
mp
)
{
struct
net_device
*
dev
=
mp
->
dev
;
...
...
@@ -1731,15 +1814,12 @@ static void handle_link_event(struct mv643xx_eth_private *mp)
printk
(
KERN_INFO
"%s: link down
\n
"
,
dev
->
name
);
netif_carrier_off
(
dev
);
netif_stop_queue
(
dev
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
{
struct
tx_queue
*
txq
=
mp
->
txq
+
i
;
if
(
mp
->
txq_mask
&
(
1
<<
i
))
{
txq_reclaim
(
txq
,
1
);
txq_reset_hw_ptr
(
txq
);
}
txq_reclaim
(
txq
,
txq
->
tx_ring_size
,
1
);
txq_reset_hw_ptr
(
txq
);
}
}
return
;
...
...
@@ -1767,119 +1847,93 @@ static void handle_link_event(struct mv643xx_eth_private *mp)
speed
,
duplex
?
"full"
:
"half"
,
fc
?
"en"
:
"dis"
);
if
(
!
netif_carrier_ok
(
dev
))
{
if
(
!
netif_carrier_ok
(
dev
))
netif_carrier_on
(
dev
);
netif_wake_queue
(
dev
);
}
}
static
i
rqreturn_t
mv643xx_eth_irq
(
int
irq
,
void
*
dev_id
)
static
i
nt
mv643xx_eth_poll
(
struct
napi_struct
*
napi
,
int
budget
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
u32
int_cause
;
u32
int_cause_ext
;
int_cause
=
rdl
(
mp
,
INT_CAUSE
(
mp
->
port_num
))
&
(
INT_TX_END
|
INT_RX
|
INT_EXT
);
if
(
int_cause
==
0
)
return
IRQ_NONE
;
int_cause_ext
=
0
;
if
(
int_cause
&
INT_EXT
)
{
int_cause_ext
=
rdl
(
mp
,
INT_CAUSE_EXT
(
mp
->
port_num
))
&
(
INT_EXT_LINK
|
INT_EXT_PHY
|
INT_EXT_TX
);
wrl
(
mp
,
INT_CAUSE_EXT
(
mp
->
port_num
),
~
int_cause_ext
);
}
if
(
int_cause_ext
&
(
INT_EXT_PHY
|
INT_EXT_LINK
))
handle_link_event
(
mp
);
struct
mv643xx_eth_private
*
mp
;
int
work_done
;
/*
* RxBuffer or RxError set for any of the 8 queues?
*/
#ifdef MV643XX_ETH_NAPI
if
(
int_cause
&
INT_RX
)
{
wrl
(
mp
,
INT_CAUSE
(
mp
->
port_num
),
~
(
int_cause
&
INT_RX
));
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
0x00000000
);
rdl
(
mp
,
INT_MASK
(
mp
->
port_num
));
mp
=
container_of
(
napi
,
struct
mv643xx_eth_private
,
napi
);
netif_rx_schedule
(
dev
,
&
mp
->
napi
);
}
#else
if
(
int_cause
&
INT_RX
)
{
int
i
;
mp
->
work_rx_refill
|=
mp
->
work_rx_oom
;
mp
->
work_rx_oom
=
0
;
for
(
i
=
7
;
i
>=
0
;
i
--
)
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rxq_process
(
mp
->
rxq
+
i
,
INT_MAX
)
;
}
#endif
work_done
=
0
;
while
(
work_done
<
budget
)
{
u8
queue_mask
;
int
queue
;
int
work_tbd
;
/*
* TxBuffer or TxError set for any of the 8 queues?
*/
if
(
int_cause_ext
&
INT_EXT_TX
)
{
int
i
;
if
(
mp
->
work_link
)
{
mp
->
work_link
=
0
;
handle_link_event
(
mp
);
continue
;
}
for
(
i
=
0
;
i
<
8
;
i
++
)
if
(
mp
->
txq_mask
&
(
1
<<
i
))
txq_reclaim
(
mp
->
txq
+
i
,
0
);
queue_mask
=
mp
->
work_tx
|
mp
->
work_tx_end
|
mp
->
work_rx
|
mp
->
work_rx_refill
;
if
(
!
queue_mask
)
{
if
(
mv643xx_eth_collect_events
(
mp
))
continue
;
break
;
}
/*
* Enough space again in the primary TX queue for a
* full packet?
*/
if
(
netif_carrier_ok
(
dev
))
{
spin_lock
(
&
mp
->
lock
);
__txq_maybe_wake
(
mp
->
txq
+
mp
->
txq_primary
);
spin_unlock
(
&
mp
->
lock
);
queue
=
fls
(
queue_mask
)
-
1
;
queue_mask
=
1
<<
queue
;
work_tbd
=
budget
-
work_done
;
if
(
work_tbd
>
16
)
work_tbd
=
16
;
if
(
mp
->
work_tx_end
&
queue_mask
)
{
txq_kick
(
mp
->
txq
+
queue
);
}
else
if
(
mp
->
work_tx
&
queue_mask
)
{
work_done
+=
txq_reclaim
(
mp
->
txq
+
queue
,
work_tbd
,
0
);
txq_maybe_wake
(
mp
->
txq
+
queue
);
}
else
if
(
mp
->
work_rx
&
queue_mask
)
{
work_done
+=
rxq_process
(
mp
->
rxq
+
queue
,
work_tbd
);
}
else
if
(
mp
->
work_rx_refill
&
queue_mask
)
{
work_done
+=
rxq_refill
(
mp
->
rxq
+
queue
,
work_tbd
);
}
else
{
BUG
();
}
}
/*
* Any TxEnd interrupts?
*/
if
(
int_cause
&
INT_TX_END
)
{
int
i
;
wrl
(
mp
,
INT_CAUSE
(
mp
->
port_num
),
~
(
int_cause
&
INT_TX_END
));
spin_lock
(
&
mp
->
lock
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
struct
tx_queue
*
txq
=
mp
->
txq
+
i
;
u32
hw_desc_ptr
;
u32
expected_ptr
;
if
((
int_cause
&
(
INT_TX_END_0
<<
i
))
==
0
)
continue
;
if
(
work_done
<
budget
)
{
if
(
mp
->
work_rx_oom
)
mod_timer
(
&
mp
->
rx_oom
,
jiffies
+
(
HZ
/
10
));
napi_complete
(
napi
);
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
INT_TX_END
|
INT_RX
|
INT_EXT
);
}
hw_desc_ptr
=
rdl
(
mp
,
TXQ_CURRENT_DESC_PTR
(
mp
->
port_num
,
i
));
expected_ptr
=
(
u32
)
txq
->
tx_desc_dma
+
txq
->
tx_curr_desc
*
sizeof
(
struct
tx_desc
);
return
work_done
;
}
if
(
hw_desc_ptr
!=
expected_ptr
)
txq_enable
(
txq
);
}
spin_unlock
(
&
mp
->
lock
);
}
static
inline
void
oom_timer_wrapper
(
unsigned
long
data
)
{
struct
mv643xx_eth_private
*
mp
=
(
void
*
)
data
;
return
IRQ_HANDLED
;
napi_schedule
(
&
mp
->
napi
)
;
}
static
void
phy_reset
(
struct
mv643xx_eth_private
*
mp
)
{
unsigned
int
data
;
int
data
;
data
=
phy_read
(
mp
->
phy
,
MII_BMCR
);
if
(
data
<
0
)
return
;
smi_reg_read
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
&
data
);
data
|=
BMCR_RESET
;
smi_reg_write
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
data
);
if
(
phy_write
(
mp
->
phy
,
MII_BMCR
,
data
)
<
0
)
return
;
do
{
udelay
(
1
);
smi_reg_read
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
&
data
);
}
while
(
data
&
BMCR_RESET
);
data
=
phy_read
(
mp
->
phy
,
MII_BMCR
);
}
while
(
data
>=
0
&&
data
&
BMCR_RESET
);
}
static
void
port_start
(
struct
mv643xx_eth_private
*
mp
)
...
...
@@ -1890,7 +1944,7 @@ static void port_start(struct mv643xx_eth_private *mp)
/*
* Perform PHY reset, if there is a PHY.
*/
if
(
mp
->
phy
_addr
!=
-
1
)
{
if
(
mp
->
phy
!=
NULL
)
{
struct
ethtool_cmd
cmd
;
mv643xx_eth_get_settings
(
mp
->
dev
,
&
cmd
);
...
...
@@ -1907,7 +1961,7 @@ static void port_start(struct mv643xx_eth_private *mp)
wrl
(
mp
,
PORT_SERIAL_CONTROL
(
mp
->
port_num
),
pscr
);
pscr
|=
DO_NOT_FORCE_LINK_FAIL
;
if
(
mp
->
phy
_addr
==
-
1
)
if
(
mp
->
phy
==
NULL
)
pscr
|=
FORCE_LINK_PASS
;
wrl
(
mp
,
PORT_SERIAL_CONTROL
(
mp
->
port_num
),
pscr
);
...
...
@@ -1917,12 +1971,9 @@ static void port_start(struct mv643xx_eth_private *mp)
* Configure TX path and queues.
*/
tx_set_rate
(
mp
,
1000000000
,
16777216
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
{
struct
tx_queue
*
txq
=
mp
->
txq
+
i
;
if
((
mp
->
txq_mask
&
(
1
<<
i
))
==
0
)
continue
;
txq_reset_hw_ptr
(
txq
);
txq_set_rate
(
txq
,
1000000000
,
16777216
);
txq_set_fixed_prio_mode
(
txq
);
...
...
@@ -1935,9 +1986,10 @@ static void port_start(struct mv643xx_eth_private *mp)
/*
* Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
* frames to RX queue #0.
* frames to RX queue #0, and include the pseudo-header when
* calculating receive checksums.
*/
wrl
(
mp
,
PORT_CONFIG
(
mp
->
port_num
),
0x0
0
000000
);
wrl
(
mp
,
PORT_CONFIG
(
mp
->
port_num
),
0x0
2
000000
);
/*
* Treat BPDUs as normal multicasts, and disable partition mode.
...
...
@@ -1947,14 +1999,11 @@ static void port_start(struct mv643xx_eth_private *mp)
/*
* Enable the receive queues.
*/
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
i
=
0
;
i
<
mp
->
rxq_count
;
i
++
)
{
struct
rx_queue
*
rxq
=
mp
->
rxq
+
i
;
int
off
=
RXQ_CURRENT_DESC_PTR
(
mp
->
port_num
,
i
);
u32
addr
;
if
((
mp
->
rxq_mask
&
(
1
<<
i
))
==
0
)
continue
;
addr
=
(
u32
)
rxq
->
rx_desc_dma
;
addr
+=
rxq
->
rx_curr_desc
*
sizeof
(
struct
rx_desc
);
wrl
(
mp
,
off
,
addr
);
...
...
@@ -2004,8 +2053,7 @@ static int mv643xx_eth_open(struct net_device *dev)
rdl
(
mp
,
INT_CAUSE_EXT
(
mp
->
port_num
));
err
=
request_irq
(
dev
->
irq
,
mv643xx_eth_irq
,
IRQF_SHARED
|
IRQF_SAMPLE_RANDOM
,
dev
->
name
,
dev
);
IRQF_SHARED
,
dev
->
name
,
dev
);
if
(
err
)
{
dev_printk
(
KERN_ERR
,
&
dev
->
dev
,
"can't assign irq
\n
"
);
return
-
EAGAIN
;
...
...
@@ -2013,58 +2061,49 @@ static int mv643xx_eth_open(struct net_device *dev)
init_mac_tables
(
mp
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
((
mp
->
rxq_mask
&
(
1
<<
i
))
==
0
)
continue
;
napi_enable
(
&
mp
->
napi
);
for
(
i
=
0
;
i
<
mp
->
rxq_count
;
i
++
)
{
err
=
rxq_init
(
mp
,
i
);
if
(
err
)
{
while
(
--
i
>=
0
)
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rxq_deinit
(
mp
->
rxq
+
i
);
rxq_deinit
(
mp
->
rxq
+
i
);
goto
out
;
}
rxq_refill
(
mp
->
rxq
+
i
);
rxq_refill
(
mp
->
rxq
+
i
,
INT_MAX
);
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
((
mp
->
txq_mask
&
(
1
<<
i
))
==
0
)
continue
;
if
(
mp
->
work_rx_oom
)
{
mp
->
rx_oom
.
expires
=
jiffies
+
(
HZ
/
10
);
add_timer
(
&
mp
->
rx_oom
);
}
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
{
err
=
txq_init
(
mp
,
i
);
if
(
err
)
{
while
(
--
i
>=
0
)
if
(
mp
->
txq_mask
&
(
1
<<
i
))
txq_deinit
(
mp
->
txq
+
i
);
txq_deinit
(
mp
->
txq
+
i
);
goto
out_free
;
}
}
#ifdef MV643XX_ETH_NAPI
napi_enable
(
&
mp
->
napi
);
#endif
netif_carrier_off
(
dev
);
netif_stop_queue
(
dev
);
port_start
(
mp
);
set_rx_coal
(
mp
,
0
);
set_tx_coal
(
mp
,
0
);
wrl
(
mp
,
INT_MASK_EXT
(
mp
->
port_num
),
INT_EXT_LINK
|
INT_EXT_PHY
|
INT_EXT_TX
);
wrl
(
mp
,
INT_MASK_EXT
(
mp
->
port_num
),
INT_EXT_LINK_PHY
|
INT_EXT_TX
);
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
INT_TX_END
|
INT_RX
|
INT_EXT
);
return
0
;
out_free:
for
(
i
=
0
;
i
<
8
;
i
++
)
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rxq_deinit
(
mp
->
rxq
+
i
);
for
(
i
=
0
;
i
<
mp
->
rxq_count
;
i
++
)
rxq_deinit
(
mp
->
rxq
+
i
);
out:
free_irq
(
dev
->
irq
,
dev
);
...
...
@@ -2076,12 +2115,10 @@ static void port_reset(struct mv643xx_eth_private *mp)
unsigned
int
data
;
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rxq_disable
(
mp
->
rxq
+
i
);
if
(
mp
->
txq_mask
&
(
1
<<
i
))
txq_disable
(
mp
->
txq
+
i
);
}
for
(
i
=
0
;
i
<
mp
->
rxq_count
;
i
++
)
rxq_disable
(
mp
->
rxq
+
i
);
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
txq_disable
(
mp
->
txq
+
i
);
while
(
1
)
{
u32
ps
=
rdl
(
mp
,
PORT_STATUS
(
mp
->
port_num
));
...
...
@@ -2107,23 +2144,24 @@ static int mv643xx_eth_stop(struct net_device *dev)
wrl
(
mp
,
INT_MASK
(
mp
->
port_num
),
0x00000000
);
rdl
(
mp
,
INT_MASK
(
mp
->
port_num
));
#ifdef MV643XX_ETH_NAPI
del_timer_sync
(
&
mp
->
mib_counters_timer
);
napi_disable
(
&
mp
->
napi
);
#endif
del_timer_sync
(
&
mp
->
rx_oom
);
netif_carrier_off
(
dev
);
netif_stop_queue
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
port_reset
(
mp
);
mv643xx_eth_get_stats
(
dev
);
mib_counters_update
(
mp
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
mp
->
rxq_mask
&
(
1
<<
i
))
rxq_deinit
(
mp
->
rxq
+
i
);
if
(
mp
->
txq_mask
&
(
1
<<
i
))
txq_deinit
(
mp
->
txq
+
i
);
}
for
(
i
=
0
;
i
<
mp
->
rxq_count
;
i
++
)
rxq_deinit
(
mp
->
rxq
+
i
);
for
(
i
=
0
;
i
<
mp
->
txq_count
;
i
++
)
txq_deinit
(
mp
->
txq
+
i
);
return
0
;
}
...
...
@@ -2132,8 +2170,8 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
if
(
mp
->
phy
_addr
!=
-
1
)
return
generic_mii_ioctl
(
&
mp
->
mii
,
if_mii
(
ifr
),
cmd
,
NULL
);
if
(
mp
->
phy
!=
NULL
)
return
phy_mii_ioctl
(
mp
->
phy
,
if_mii
(
ifr
),
cmd
);
return
-
EOPNOTSUPP
;
}
...
...
@@ -2173,12 +2211,10 @@ static void tx_timeout_task(struct work_struct *ugly)
mp
=
container_of
(
ugly
,
struct
mv643xx_eth_private
,
tx_timeout_task
);
if
(
netif_running
(
mp
->
dev
))
{
netif_stop_queue
(
mp
->
dev
);
netif_tx_stop_all_queues
(
mp
->
dev
);
port_reset
(
mp
);
port_start
(
mp
);
__txq_maybe_wake
(
mp
->
txq
+
mp
->
txq_primary
);
netif_tx_wake_all_queues
(
mp
->
dev
);
}
}
...
...
@@ -2205,22 +2241,6 @@ static void mv643xx_eth_netpoll(struct net_device *dev)
}
#endif
static
int
mv643xx_eth_mdio_read
(
struct
net_device
*
dev
,
int
addr
,
int
reg
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
int
val
;
smi_reg_read
(
mp
,
addr
,
reg
,
&
val
);
return
val
;
}
static
void
mv643xx_eth_mdio_write
(
struct
net_device
*
dev
,
int
addr
,
int
reg
,
int
val
)
{
struct
mv643xx_eth_private
*
mp
=
netdev_priv
(
dev
);
smi_reg_write
(
mp
,
addr
,
reg
,
val
);
}
/* platform glue ************************************************************/
static
void
...
...
@@ -2272,14 +2292,20 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
msp
->
extended_rx_coal_limit
=
0
;
/*
* Check whether the TX rate control registers are in the
* old or the new place.
* Check whether the MAC supports TX rate control, and if
* yes, whether its associated registers are in the old or
* the new place.
*/
writel
(
1
,
msp
->
base
+
TX_BW_MTU_MOVED
(
0
));
if
(
readl
(
msp
->
base
+
TX_BW_MTU_MOVED
(
0
))
&
1
)
msp
->
tx_bw_control_moved
=
1
;
else
msp
->
tx_bw_control_moved
=
0
;
if
(
readl
(
msp
->
base
+
TX_BW_MTU_MOVED
(
0
))
&
1
)
{
msp
->
tx_bw_control
=
TX_BW_CONTROL_NEW_LAYOUT
;
}
else
{
writel
(
7
,
msp
->
base
+
TX_BW_RATE
(
0
));
if
(
readl
(
msp
->
base
+
TX_BW_RATE
(
0
))
&
7
)
msp
->
tx_bw_control
=
TX_BW_CONTROL_OLD_LAYOUT
;
else
msp
->
tx_bw_control
=
TX_BW_CONTROL_ABSENT
;
}
}
static
int
mv643xx_eth_shared_probe
(
struct
platform_device
*
pdev
)
...
...
@@ -2309,7 +2335,41 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if
(
msp
->
base
==
NULL
)
goto
out_free
;
spin_lock_init
(
&
msp
->
phy_lock
);
/*
* Set up and register SMI bus.
*/
if
(
pd
==
NULL
||
pd
->
shared_smi
==
NULL
)
{
msp
->
smi_bus
.
priv
=
msp
;
msp
->
smi_bus
.
name
=
"mv643xx_eth smi"
;
msp
->
smi_bus
.
read
=
smi_bus_read
;
msp
->
smi_bus
.
write
=
smi_bus_write
,
snprintf
(
msp
->
smi_bus
.
id
,
MII_BUS_ID_SIZE
,
"%d"
,
pdev
->
id
);
msp
->
smi_bus
.
dev
=
&
pdev
->
dev
;
msp
->
smi_bus
.
phy_mask
=
0xffffffff
;
if
(
mdiobus_register
(
&
msp
->
smi_bus
)
<
0
)
goto
out_unmap
;
msp
->
smi
=
msp
;
}
else
{
msp
->
smi
=
platform_get_drvdata
(
pd
->
shared_smi
);
}
msp
->
err_interrupt
=
NO_IRQ
;
init_waitqueue_head
(
&
msp
->
smi_busy_wait
);
/*
* Check whether the error interrupt is hooked up.
*/
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
if
(
res
!=
NULL
)
{
int
err
;
err
=
request_irq
(
res
->
start
,
mv643xx_eth_err_irq
,
IRQF_SHARED
,
"mv643xx_eth"
,
msp
);
if
(
!
err
)
{
writel
(
ERR_INT_SMI_DONE
,
msp
->
base
+
ERR_INT_MASK
);
msp
->
err_interrupt
=
res
->
start
;
}
}
/*
* (Re-)program MBUS remapping windows if we are asked to.
...
...
@@ -2327,6 +2387,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
return
0
;
out_unmap:
iounmap
(
msp
->
base
);
out_free:
kfree
(
msp
);
out:
...
...
@@ -2336,7 +2398,12 @@ out:
static
int
mv643xx_eth_shared_remove
(
struct
platform_device
*
pdev
)
{
struct
mv643xx_eth_shared_private
*
msp
=
platform_get_drvdata
(
pdev
);
struct
mv643xx_eth_shared_platform_data
*
pd
=
pdev
->
dev
.
platform_data
;
if
(
pd
==
NULL
||
pd
->
shared_smi
==
NULL
)
mdiobus_unregister
(
&
msp
->
smi_bus
);
if
(
msp
->
err_interrupt
!=
NO_IRQ
)
free_irq
(
msp
->
err_interrupt
,
msp
);
iounmap
(
msp
->
base
);
kfree
(
msp
);
...
...
@@ -2382,33 +2449,13 @@ static void set_params(struct mv643xx_eth_private *mp,
else
uc_addr_get
(
mp
,
dev
->
dev_addr
);
if
(
pd
->
phy_addr
==
-
1
)
{
mp
->
shared_smi
=
NULL
;
mp
->
phy_addr
=
-
1
;
}
else
{
mp
->
shared_smi
=
mp
->
shared
;
if
(
pd
->
shared_smi
!=
NULL
)
mp
->
shared_smi
=
platform_get_drvdata
(
pd
->
shared_smi
);
if
(
pd
->
force_phy_addr
||
pd
->
phy_addr
)
{
mp
->
phy_addr
=
pd
->
phy_addr
&
0x3f
;
phy_addr_set
(
mp
,
mp
->
phy_addr
);
}
else
{
mp
->
phy_addr
=
phy_addr_get
(
mp
);
}
}
mp
->
default_rx_ring_size
=
DEFAULT_RX_QUEUE_SIZE
;
if
(
pd
->
rx_queue_size
)
mp
->
default_rx_ring_size
=
pd
->
rx_queue_size
;
mp
->
rx_desc_sram_addr
=
pd
->
rx_sram_addr
;
mp
->
rx_desc_sram_size
=
pd
->
rx_sram_size
;
if
(
pd
->
rx_queue_mask
)
mp
->
rxq_mask
=
pd
->
rx_queue_mask
;
else
mp
->
rxq_mask
=
0x01
;
mp
->
rxq_primary
=
fls
(
mp
->
rxq_mask
)
-
1
;
mp
->
rxq_count
=
pd
->
rx_queue_count
?
:
1
;
mp
->
default_tx_ring_size
=
DEFAULT_TX_QUEUE_SIZE
;
if
(
pd
->
tx_queue_size
)
...
...
@@ -2416,76 +2463,63 @@ static void set_params(struct mv643xx_eth_private *mp,
mp
->
tx_desc_sram_addr
=
pd
->
tx_sram_addr
;
mp
->
tx_desc_sram_size
=
pd
->
tx_sram_size
;
if
(
pd
->
tx_queue_mask
)
mp
->
txq_mask
=
pd
->
tx_queue_mask
;
else
mp
->
txq_mask
=
0x01
;
mp
->
txq_primary
=
fls
(
mp
->
txq_mask
)
-
1
;
mp
->
txq_count
=
pd
->
tx_queue_count
?
:
1
;
}
static
int
phy_detect
(
struct
mv643xx_eth_private
*
mp
)
static
struct
phy_device
*
phy_scan
(
struct
mv643xx_eth_private
*
mp
,
int
phy_addr
)
{
unsigned
int
data
;
unsigned
int
data2
;
struct
mii_bus
*
bus
=
&
mp
->
shared
->
smi
->
smi_bus
;
struct
phy_device
*
phydev
;
int
start
;
int
num
;
int
i
;
smi_reg_read
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
&
data
);
smi_reg_write
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
data
^
BMCR_ANENABLE
);
if
(
phy_addr
==
MV643XX_ETH_PHY_ADDR_DEFAULT
)
{
start
=
phy_addr_get
(
mp
)
&
0x1f
;
num
=
32
;
}
else
{
start
=
phy_addr
&
0x1f
;
num
=
1
;
}
smi_reg_read
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
&
data2
)
;
if
(((
data
^
data2
)
&
BMCR_ANENABLE
)
==
0
)
return
-
ENODEV
;
phydev
=
NULL
;
for
(
i
=
0
;
i
<
num
;
i
++
)
{
int
addr
=
(
start
+
i
)
&
0x1f
;
smi_reg_write
(
mp
,
mp
->
phy_addr
,
MII_BMCR
,
data
);
if
(
bus
->
phy_map
[
addr
]
==
NULL
)
mdiobus_scan
(
bus
,
addr
);
return
0
;
if
(
phydev
==
NULL
)
{
phydev
=
bus
->
phy_map
[
addr
];
if
(
phydev
!=
NULL
)
phy_addr_set
(
mp
,
addr
);
}
}
return
phydev
;
}
static
int
phy_init
(
struct
mv643xx_eth_private
*
mp
,
struct
mv643xx_eth_platform_data
*
pd
)
static
void
phy_init
(
struct
mv643xx_eth_private
*
mp
,
int
speed
,
int
duplex
)
{
struct
ethtool_cmd
cmd
;
int
err
;
struct
phy_device
*
phy
=
mp
->
phy
;
err
=
phy_detect
(
mp
);
if
(
err
)
{
dev_printk
(
KERN_INFO
,
&
mp
->
dev
->
dev
,
"no PHY detected at addr %d
\n
"
,
mp
->
phy_addr
);
return
err
;
}
phy_reset
(
mp
);
mp
->
mii
.
phy_id
=
mp
->
phy_addr
;
mp
->
mii
.
phy_id_mask
=
0x3f
;
mp
->
mii
.
reg_num_mask
=
0x1f
;
mp
->
mii
.
dev
=
mp
->
dev
;
mp
->
mii
.
mdio_read
=
mv643xx_eth_mdio_read
;
mp
->
mii
.
mdio_write
=
mv643xx_eth_mdio_write
;
mp
->
mii
.
supports_gmii
=
mii_check_gmii_support
(
&
mp
->
mii
);
memset
(
&
cmd
,
0
,
sizeof
(
cmd
));
cmd
.
port
=
PORT_MII
;
cmd
.
transceiver
=
XCVR_INTERNAL
;
cmd
.
phy_address
=
mp
->
phy_addr
;
if
(
pd
->
speed
==
0
)
{
cmd
.
autoneg
=
AUTONEG_ENABLE
;
cmd
.
speed
=
SPEED_100
;
cmd
.
advertising
=
ADVERTISED_10baseT_Half
|
ADVERTISED_10baseT_Full
|
ADVERTISED_100baseT_Half
|
ADVERTISED_100baseT_Full
;
if
(
mp
->
mii
.
supports_gmii
)
cmd
.
advertising
|=
ADVERTISED_1000baseT_Full
;
phy_attach
(
mp
->
dev
,
phy
->
dev
.
bus_id
,
0
,
PHY_INTERFACE_MODE_GMII
);
if
(
speed
==
0
)
{
phy
->
autoneg
=
AUTONEG_ENABLE
;
phy
->
speed
=
0
;
phy
->
duplex
=
0
;
phy
->
advertising
=
phy
->
supported
|
ADVERTISED_Autoneg
;
}
else
{
cmd
.
autoneg
=
AUTONEG_DISABLE
;
cmd
.
speed
=
pd
->
speed
;
cmd
.
duplex
=
pd
->
duplex
;
phy
->
autoneg
=
AUTONEG_DISABLE
;
phy
->
advertising
=
0
;
phy
->
speed
=
speed
;
phy
->
duplex
=
duplex
;
}
mv643xx_eth_set_settings
(
mp
->
dev
,
&
cmd
);
return
0
;
phy_start_aneg
(
phy
);
}
static
void
init_pscr
(
struct
mv643xx_eth_private
*
mp
,
int
speed
,
int
duplex
)
...
...
@@ -2499,7 +2533,7 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
}
pscr
=
MAX_RX_PACKET_9700BYTE
|
SERIAL_PORT_CONTROL_RESERVED
;
if
(
mp
->
phy
_addr
==
-
1
)
{
if
(
mp
->
phy
==
NULL
)
{
pscr
|=
DISABLE_AUTO_NEG_SPEED_GMII
;
if
(
speed
==
SPEED_1000
)
pscr
|=
SET_GMII_SPEED_TO_1000
;
...
...
@@ -2538,7 +2572,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
return
-
ENODEV
;
}
dev
=
alloc_etherdev
(
sizeof
(
struct
mv643xx_eth_private
)
);
dev
=
alloc_etherdev
_mq
(
sizeof
(
struct
mv643xx_eth_private
),
8
);
if
(
!
dev
)
return
-
ENOMEM
;
...
...
@@ -2549,33 +2583,47 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mp
->
port_num
=
pd
->
port_number
;
mp
->
dev
=
dev
;
#ifdef MV643XX_ETH_NAPI
netif_napi_add
(
dev
,
&
mp
->
napi
,
mv643xx_eth_poll
,
64
);
#endif
set_params
(
mp
,
pd
);
dev
->
real_num_tx_queues
=
mp
->
txq_count
;
spin_lock_init
(
&
mp
->
lock
);
mib_counters_clear
(
mp
);
INIT_WORK
(
&
mp
->
tx_timeout_task
,
tx_timeout_task
);
if
(
mp
->
phy_addr
!=
-
1
)
{
err
=
phy_init
(
mp
,
pd
);
if
(
err
)
goto
out
;
if
(
pd
->
phy_addr
!=
MV643XX_ETH_PHY_NONE
)
mp
->
phy
=
phy_scan
(
mp
,
pd
->
phy_addr
);
if
(
mp
->
phy
!=
NULL
)
{
phy_init
(
mp
,
pd
->
speed
,
pd
->
duplex
);
SET_ETHTOOL_OPS
(
dev
,
&
mv643xx_eth_ethtool_ops
);
}
else
{
SET_ETHTOOL_OPS
(
dev
,
&
mv643xx_eth_ethtool_ops_phyless
);
}
init_pscr
(
mp
,
pd
->
speed
,
pd
->
duplex
);
mib_counters_clear
(
mp
);
init_timer
(
&
mp
->
mib_counters_timer
);
mp
->
mib_counters_timer
.
data
=
(
unsigned
long
)
mp
;
mp
->
mib_counters_timer
.
function
=
mib_counters_timer_wrapper
;
mp
->
mib_counters_timer
.
expires
=
jiffies
+
30
*
HZ
;
add_timer
(
&
mp
->
mib_counters_timer
);
spin_lock_init
(
&
mp
->
mib_counters_lock
);
INIT_WORK
(
&
mp
->
tx_timeout_task
,
tx_timeout_task
);
netif_napi_add
(
dev
,
&
mp
->
napi
,
mv643xx_eth_poll
,
128
);
init_timer
(
&
mp
->
rx_oom
);
mp
->
rx_oom
.
data
=
(
unsigned
long
)
mp
;
mp
->
rx_oom
.
function
=
oom_timer_wrapper
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
BUG_ON
(
!
res
);
dev
->
irq
=
res
->
start
;
dev
->
get_stats
=
mv643xx_eth_get_stats
;
dev
->
hard_start_xmit
=
mv643xx_eth_xmit
;
dev
->
open
=
mv643xx_eth_open
;
dev
->
stop
=
mv643xx_eth_stop
;
...
...
@@ -2590,14 +2638,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev
->
watchdog_timeo
=
2
*
HZ
;
dev
->
base_addr
=
0
;
#ifdef MV643XX_ETH_CHECKSUM_OFFLOAD_TX
/*
* Zero copy can only work if we use Discovery II memory. Else, we will
* have to map the buffers to ISA memory which is only 16 MB
*/
dev
->
features
=
NETIF_F_SG
|
NETIF_F_IP_CSUM
;
dev
->
vlan_features
=
NETIF_F_SG
|
NETIF_F_IP_CSUM
;
#endif
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
...
...
@@ -2611,16 +2653,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev_printk
(
KERN_NOTICE
,
&
dev
->
dev
,
"port %d with MAC address %s
\n
"
,
mp
->
port_num
,
print_mac
(
mac
,
dev
->
dev_addr
));
if
(
dev
->
features
&
NETIF_F_SG
)
dev_printk
(
KERN_NOTICE
,
&
dev
->
dev
,
"scatter/gather enabled
\n
"
);
if
(
dev
->
features
&
NETIF_F_IP_CSUM
)
dev_printk
(
KERN_NOTICE
,
&
dev
->
dev
,
"tx checksum offload
\n
"
);
#ifdef MV643XX_ETH_NAPI
dev_printk
(
KERN_NOTICE
,
&
dev
->
dev
,
"napi enabled
\n
"
);
#endif
if
(
mp
->
tx_desc_sram_size
>
0
)
dev_printk
(
KERN_NOTICE
,
&
dev
->
dev
,
"configured with sram
\n
"
);
...
...
@@ -2637,6 +2669,8 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
struct
mv643xx_eth_private
*
mp
=
platform_get_drvdata
(
pdev
);
unregister_netdev
(
mp
->
dev
);
if
(
mp
->
phy
!=
NULL
)
phy_detach
(
mp
->
phy
);
flush_scheduled_work
();
free_netdev
(
mp
->
dev
);
...
...
drivers/net/phy/mdio_bus.c
View file @
ae19161e
...
...
@@ -60,49 +60,14 @@ int mdiobus_register(struct mii_bus *bus)
bus
->
reset
(
bus
);
for
(
i
=
0
;
i
<
PHY_MAX_ADDR
;
i
++
)
{
struct
phy_device
*
phydev
;
bus
->
phy_map
[
i
]
=
NULL
;
if
((
bus
->
phy_mask
&
(
1
<<
i
))
==
0
)
{
struct
phy_device
*
phydev
;
if
(
bus
->
phy_mask
&
(
1
<<
i
))
{
bus
->
phy_map
[
i
]
=
NULL
;
continue
;
phydev
=
mdiobus_scan
(
bus
,
i
);
if
(
IS_ERR
(
phydev
))
err
=
PTR_ERR
(
phydev
)
;
}
phydev
=
get_phy_device
(
bus
,
i
);
if
(
IS_ERR
(
phydev
))
return
PTR_ERR
(
phydev
);
/* There's a PHY at this address
* We need to set:
* 1) IRQ
* 2) bus_id
* 3) parent
* 4) bus
* 5) mii_bus
* And, we need to register it */
if
(
phydev
)
{
phydev
->
irq
=
bus
->
irq
[
i
];
phydev
->
dev
.
parent
=
bus
->
dev
;
phydev
->
dev
.
bus
=
&
mdio_bus_type
;
snprintf
(
phydev
->
dev
.
bus_id
,
BUS_ID_SIZE
,
PHY_ID_FMT
,
bus
->
id
,
i
);
phydev
->
bus
=
bus
;
/* Run all of the fixups for this PHY */
phy_scan_fixups
(
phydev
);
err
=
device_register
(
&
phydev
->
dev
);
if
(
err
)
{
printk
(
KERN_ERR
"phy %d failed to register
\n
"
,
i
);
phy_device_free
(
phydev
);
phydev
=
NULL
;
}
}
bus
->
phy_map
[
i
]
=
phydev
;
}
pr_info
(
"%s: probed
\n
"
,
bus
->
name
);
...
...
@@ -122,6 +87,48 @@ void mdiobus_unregister(struct mii_bus *bus)
}
EXPORT_SYMBOL
(
mdiobus_unregister
);
struct
phy_device
*
mdiobus_scan
(
struct
mii_bus
*
bus
,
int
addr
)
{
struct
phy_device
*
phydev
;
int
err
;
phydev
=
get_phy_device
(
bus
,
addr
);
if
(
IS_ERR
(
phydev
)
||
phydev
==
NULL
)
return
phydev
;
/* There's a PHY at this address
* We need to set:
* 1) IRQ
* 2) bus_id
* 3) parent
* 4) bus
* 5) mii_bus
* And, we need to register it */
phydev
->
irq
=
bus
->
irq
!=
NULL
?
bus
->
irq
[
addr
]
:
PHY_POLL
;
phydev
->
dev
.
parent
=
bus
->
dev
;
phydev
->
dev
.
bus
=
&
mdio_bus_type
;
snprintf
(
phydev
->
dev
.
bus_id
,
BUS_ID_SIZE
,
PHY_ID_FMT
,
bus
->
id
,
addr
);
phydev
->
bus
=
bus
;
/* Run all of the fixups for this PHY */
phy_scan_fixups
(
phydev
);
err
=
device_register
(
&
phydev
->
dev
);
if
(
err
)
{
printk
(
KERN_ERR
"phy %d failed to register
\n
"
,
addr
);
phy_device_free
(
phydev
);
phydev
=
NULL
;
}
bus
->
phy_map
[
addr
]
=
phydev
;
return
phydev
;
}
EXPORT_SYMBOL
(
mdiobus_scan
);
/**
* mdio_bus_match - determine if given PHY driver supports the given PHY device
* @dev: target PHY device
...
...
include/linux/mv643xx_eth.h
View file @
ae19161e
...
...
@@ -17,9 +17,14 @@
struct
mv643xx_eth_shared_platform_data
{
struct
mbus_dram_target_info
*
dram
;
struct
platform_device
*
shared_smi
;
unsigned
int
t_clk
;
};
#define MV643XX_ETH_PHY_ADDR_DEFAULT 0
#define MV643XX_ETH_PHY_ADDR(x) (0x80 | (x))
#define MV643XX_ETH_PHY_NONE 0xff
struct
mv643xx_eth_platform_data
{
/*
* Pointer back to our parent instance, and our port number.
...
...
@@ -30,8 +35,6 @@ struct mv643xx_eth_platform_data {
/*
* Whether a PHY is present, and if yes, at which address.
*/
struct
platform_device
*
shared_smi
;
int
force_phy_addr
;
int
phy_addr
;
/*
...
...
@@ -49,10 +52,10 @@ struct mv643xx_eth_platform_data {
int
duplex
;
/*
*
Which
RX/TX queues to use.
*
How many
RX/TX queues to use.
*/
int
rx_queue_
mask
;
int
tx_queue_
mask
;
int
rx_queue_
count
;
int
tx_queue_
count
;
/*
* Override default RX/TX queue sizes if nonzero.
...
...
include/linux/phy.h
View file @
ae19161e
...
...
@@ -410,6 +410,8 @@ int phy_start_aneg(struct phy_device *phydev);
int
mdiobus_register
(
struct
mii_bus
*
bus
);
void
mdiobus_unregister
(
struct
mii_bus
*
bus
);
struct
phy_device
*
mdiobus_scan
(
struct
mii_bus
*
bus
,
int
addr
);
void
phy_sanitize_settings
(
struct
phy_device
*
phydev
);
int
phy_stop_interrupts
(
struct
phy_device
*
phydev
);
int
phy_enable_interrupts
(
struct
phy_device
*
phydev
);
...
...
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