Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
2098c18d
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
2098c18d
编写于
12月 20, 2008
作者:
K
Krzysztof Hałasa
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
IXP4xx: Add PHYLIB support to Ethernet driver.
Signed-off-by:
N
Krzysztof Hałasa
<
khc@pm.waw.pl
>
上级
b4c7d3b0
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
96 addition
and
100 deletion
+96
-100
drivers/net/arm/Kconfig
drivers/net/arm/Kconfig
+1
-1
drivers/net/arm/ixp4xx_eth.c
drivers/net/arm/ixp4xx_eth.c
+95
-99
未找到文件。
drivers/net/arm/Kconfig
浏览文件 @
2098c18d
...
...
@@ -59,7 +59,7 @@ config EP93XX_ETH
config IXP4XX_ETH
tristate "Intel IXP4xx Ethernet support"
depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
select
MII
select
PHYLIB
help
Say Y here if you want to use built-in Ethernet ports
on IXP4xx processor.
drivers/net/arm/ixp4xx_eth.c
浏览文件 @
2098c18d
...
...
@@ -30,7 +30,7 @@
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/
mii
.h>
#include <linux/
phy
.h>
#include <linux/platform_device.h>
#include <mach/npe.h>
#include <mach/qmgr.h>
...
...
@@ -59,7 +59,6 @@
#define NAPI_WEIGHT 16
#define MDIO_INTERVAL (3 * HZ)
#define MAX_MDIO_RETRIES 100
/* microseconds, typically 30 cycles */
#define MAX_MII_RESET_RETRIES 100
/* mdio_read() cycles, typically 4 */
#define MAX_CLOSE_WAIT 1000
/* microseconds, typically 2-3 cycles */
#define NPE_ID(port_id) ((port_id) >> 4)
...
...
@@ -164,14 +163,13 @@ struct port {
struct
npe
*
npe
;
struct
net_device
*
netdev
;
struct
napi_struct
napi
;
struct
mii_if_info
mii
;
struct
delayed_work
mdio_thread
;
struct
phy_device
*
phydev
;
struct
eth_plat_info
*
plat
;
buffer_t
*
rx_buff_tab
[
RX_DESCS
],
*
tx_buff_tab
[
TX_DESCS
];
struct
desc
*
desc_tab
;
/* coherent */
u32
desc_tab_phys
;
int
id
;
/* logical port ID */
u16
mii_bmcr
;
int
speed
,
duplex
;
};
/* NPE message structure */
...
...
@@ -242,19 +240,20 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
static
spinlock_t
mdio_lock
;
static
struct
eth_regs
__iomem
*
mdio_regs
;
/* mdio command and status only */
struct
mii_bus
*
mdio_bus
;
static
int
ports_open
;
static
struct
port
*
npe_port_tab
[
MAX_NPES
];
static
struct
dma_pool
*
dma_pool
;
static
u16
mdio_cmd
(
struct
net_device
*
dev
,
int
phy_id
,
int
location
,
int
write
,
u16
cmd
)
static
int
ixp4xx_mdio_cmd
(
struct
mii_bus
*
bus
,
int
phy_id
,
int
location
,
int
write
,
u16
cmd
)
{
int
cycles
=
0
;
if
(
__raw_readl
(
&
mdio_regs
->
mdio_command
[
3
])
&
0x80
)
{
printk
(
KERN_ERR
"%s: MII not ready to transmit
\n
"
,
dev
->
name
);
return
0
;
printk
(
KERN_ERR
"%s: MII not ready to transmit
\n
"
,
bus
->
name
);
return
-
1
;
}
if
(
write
)
{
...
...
@@ -273,107 +272,119 @@ static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,
}
if
(
cycles
==
MAX_MDIO_RETRIES
)
{
printk
(
KERN_ERR
"%s: MII write failed
\n
"
,
dev
->
name
);
return
0
;
printk
(
KERN_ERR
"%s #%i: MII write failed
\n
"
,
bus
->
name
,
phy_id
);
return
-
1
;
}
#if DEBUG_MDIO
printk
(
KERN_DEBUG
"%s
: mdio_cmd() took %i cycles
\n
"
,
dev
->
name
,
cycles
);
printk
(
KERN_DEBUG
"%s
#%i: mdio_%s() took %i cycles
\n
"
,
bus
->
name
,
phy_id
,
write
?
"write"
:
"read"
,
cycles
);
#endif
if
(
write
)
return
0
;
if
(
__raw_readl
(
&
mdio_regs
->
mdio_status
[
3
])
&
0x80
)
{
printk
(
KERN_ERR
"%s: MII read failed
\n
"
,
dev
->
name
);
return
0
;
#if DEBUG_MDIO
printk
(
KERN_DEBUG
"%s #%i: MII read failed
\n
"
,
bus
->
name
,
phy_id
);
#endif
return
0xFFFF
;
/* don't return error */
}
return
(
__raw_readl
(
&
mdio_regs
->
mdio_status
[
0
])
&
0xFF
)
|
(
__raw_readl
(
&
mdio_regs
->
mdio_status
[
1
]
)
<<
8
);
(
(
__raw_readl
(
&
mdio_regs
->
mdio_status
[
1
])
&
0xFF
)
<<
8
);
}
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
location
)
static
int
ixp4xx_mdio_read
(
struct
mii_bus
*
bus
,
int
phy_id
,
int
location
)
{
unsigned
long
flags
;
u16
val
;
int
ret
;
spin_lock_irqsave
(
&
mdio_lock
,
flags
);
val
=
mdio_cmd
(
dev
,
phy_id
,
location
,
0
,
0
);
ret
=
ixp4xx_mdio_cmd
(
bus
,
phy_id
,
location
,
0
,
0
);
spin_unlock_irqrestore
(
&
mdio_lock
,
flags
);
return
val
;
#if DEBUG_MDIO
printk
(
KERN_DEBUG
"%s #%i: MII read [%i] -> 0x%X
\n
"
,
bus
->
name
,
phy_id
,
location
,
ret
);
#endif
return
ret
;
}
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
location
,
int
val
)
static
int
ixp4xx_mdio_write
(
struct
mii_bus
*
bus
,
int
phy_id
,
int
location
,
u16
val
)
{
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
mdio_lock
,
flags
);
mdio_cmd
(
dev
,
phy_id
,
location
,
1
,
val
);
ret
=
ixp4xx_mdio_cmd
(
bus
,
phy_id
,
location
,
1
,
val
);
spin_unlock_irqrestore
(
&
mdio_lock
,
flags
);
#if DEBUG_MDIO
printk
(
KERN_DEBUG
"%s #%i: MII read [%i] <- 0x%X, err = %i
\n
"
,
bus
->
name
,
phy_id
,
location
,
val
,
ret
);
#endif
return
ret
;
}
static
void
phy_reset
(
struct
net_device
*
dev
,
int
phy_
id
)
static
int
ixp4xx_mdio_register
(
vo
id
)
{
struct
port
*
port
=
netdev_priv
(
dev
);
int
cycles
=
0
;
int
err
;
if
(
!
(
mdio_bus
=
mdiobus_alloc
()))
return
-
ENOMEM
;
mdio_write
(
dev
,
phy_id
,
MII_BMCR
,
port
->
mii_bmcr
|
BMCR_RESET
);
/* All MII PHY accesses use NPE-B Ethernet registers */
spin_lock_init
(
&
mdio_lock
);
mdio_regs
=
(
struct
eth_regs
__iomem
*
)
IXP4XX_EthB_BASE_VIRT
;
__raw_writel
(
DEFAULT_CORE_CNTRL
,
&
mdio_regs
->
core_control
);
while
(
cycles
<
MAX_MII_RESET_RETRIES
)
{
if
(
!
(
mdio_read
(
dev
,
phy_id
,
MII_BMCR
)
&
BMCR_RESET
))
{
#if DEBUG_MDIO
printk
(
KERN_DEBUG
"%s: phy_reset() took %i cycles
\n
"
,
dev
->
name
,
cycles
);
#endif
return
;
}
udelay
(
1
);
cycles
++
;
}
mdio_bus
->
name
=
"IXP4xx MII Bus"
;
mdio_bus
->
read
=
&
ixp4xx_mdio_read
;
mdio_bus
->
write
=
&
ixp4xx_mdio_write
;
strcpy
(
mdio_bus
->
id
,
"0"
);
printk
(
KERN_ERR
"%s: MII reset failed
\n
"
,
dev
->
name
);
if
((
err
=
mdiobus_register
(
mdio_bus
)))
mdiobus_free
(
mdio_bus
);
return
err
;
}
static
void
eth_set_duplex
(
struct
port
*
port
)
static
void
ixp4xx_mdio_remove
(
void
)
{
if
(
port
->
mii
.
full_duplex
)
__raw_writel
(
DEFAULT_TX_CNTRL0
&
~
TX_CNTRL0_HALFDUPLEX
,
&
port
->
regs
->
tx_control
[
0
]);
else
__raw_writel
(
DEFAULT_TX_CNTRL0
|
TX_CNTRL0_HALFDUPLEX
,
&
port
->
regs
->
tx_control
[
0
]);
mdiobus_unregister
(
mdio_bus
);
mdiobus_free
(
mdio_bus
);
}
static
void
phy_check_media
(
struct
port
*
port
,
int
init
)
static
void
ixp4xx_adjust_link
(
struct
net_device
*
dev
)
{
if
(
mii_check_media
(
&
port
->
mii
,
1
,
init
))
eth_set_duplex
(
port
);
if
(
port
->
mii
.
force_media
)
{
/* mii_check_media() doesn't work */
struct
net_device
*
dev
=
port
->
netdev
;
int
cur_link
=
mii_link_ok
(
&
port
->
mii
);
int
prev_link
=
netif_carrier_ok
(
dev
);
if
(
!
prev_link
&&
cur_link
)
{
printk
(
KERN_INFO
"%s: link up
\n
"
,
dev
->
name
);
netif_carrier_on
(
dev
);
}
else
if
(
prev_link
&&
!
cur_link
)
{
struct
port
*
port
=
netdev_priv
(
dev
);
struct
phy_device
*
phydev
=
port
->
phydev
;
if
(
!
phydev
->
link
)
{
if
(
port
->
speed
)
{
port
->
speed
=
0
;
printk
(
KERN_INFO
"%s: link down
\n
"
,
dev
->
name
);
netif_carrier_off
(
dev
);
}
return
;
}
}
if
(
port
->
speed
==
phydev
->
speed
&&
port
->
duplex
==
phydev
->
duplex
)
return
;
static
void
mdio_thread
(
struct
work_struct
*
work
)
{
struct
port
*
port
=
container_of
(
work
,
struct
port
,
mdio_thread
.
work
);
port
->
speed
=
phydev
->
speed
;
port
->
duplex
=
phydev
->
duplex
;
phy_check_media
(
port
,
0
);
schedule_delayed_work
(
&
port
->
mdio_thread
,
MDIO_INTERVAL
);
if
(
port
->
duplex
)
__raw_writel
(
DEFAULT_TX_CNTRL0
&
~
TX_CNTRL0_HALFDUPLEX
,
&
port
->
regs
->
tx_control
[
0
]);
else
__raw_writel
(
DEFAULT_TX_CNTRL0
|
TX_CNTRL0_HALFDUPLEX
,
&
port
->
regs
->
tx_control
[
0
]);
printk
(
KERN_INFO
"%s: link up, speed %u Mb/s, %s duplex
\n
"
,
dev
->
name
,
port
->
speed
,
port
->
duplex
?
"full"
:
"half"
);
}
...
...
@@ -777,16 +788,9 @@ static void eth_set_mcast_list(struct net_device *dev)
static
int
eth_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
req
,
int
cmd
)
{
struct
port
*
port
=
netdev_priv
(
dev
);
unsigned
int
duplex_chg
;
int
err
;
if
(
!
netif_running
(
dev
))
return
-
EINVAL
;
err
=
generic_mii_ioctl
(
&
port
->
mii
,
if_mii
(
req
),
cmd
,
&
duplex_chg
);
if
(
duplex_chg
)
eth_set_duplex
(
port
);
return
err
;
return
-
EINVAL
;
}
...
...
@@ -938,8 +942,6 @@ static int eth_open(struct net_device *dev)
}
}
mdio_write
(
dev
,
port
->
plat
->
phy
,
MII_BMCR
,
port
->
mii_bmcr
);
memset
(
&
msg
,
0
,
sizeof
(
msg
));
msg
.
cmd
=
NPE_VLAN_SETRXQOSENTRY
;
msg
.
eth_id
=
port
->
id
;
...
...
@@ -977,6 +979,9 @@ static int eth_open(struct net_device *dev)
return
err
;
}
port
->
speed
=
0
;
/* force "link up" message */
phy_start
(
port
->
phydev
);
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
)
__raw_writel
(
dev
->
dev_addr
[
i
],
&
port
->
regs
->
hw_addr
[
i
]);
__raw_writel
(
0x08
,
&
port
->
regs
->
random_seed
);
...
...
@@ -1004,10 +1009,8 @@ static int eth_open(struct net_device *dev)
__raw_writel
(
DEFAULT_RX_CNTRL0
,
&
port
->
regs
->
rx_control
[
0
]);
napi_enable
(
&
port
->
napi
);
phy_check_media
(
port
,
1
);
eth_set_mcast_list
(
dev
);
netif_start_queue
(
dev
);
schedule_delayed_work
(
&
port
->
mdio_thread
,
MDIO_INTERVAL
);
qmgr_set_irq
(
port
->
plat
->
rxq
,
QUEUE_IRQ_SRC_NOT_EMPTY
,
eth_rx_irq
,
dev
);
...
...
@@ -1098,14 +1101,10 @@ static int eth_close(struct net_device *dev)
printk
(
KERN_CRIT
"%s: unable to disable loopback
\n
"
,
dev
->
name
);
port
->
mii_bmcr
=
mdio_read
(
dev
,
port
->
plat
->
phy
,
MII_BMCR
)
&
~
(
BMCR_RESET
|
BMCR_PDOWN
);
/* may have been altered */
mdio_write
(
dev
,
port
->
plat
->
phy
,
MII_BMCR
,
port
->
mii_bmcr
|
BMCR_PDOWN
);
phy_stop
(
port
->
phydev
);
if
(
!
ports_open
)
qmgr_disable_irq
(
TXDONE_QUEUE
);
cancel_rearming_delayed_work
(
&
port
->
mdio_thread
);
destroy_queues
(
port
);
release_queues
(
port
);
return
0
;
...
...
@@ -1117,6 +1116,7 @@ static int __devinit eth_init_one(struct platform_device *pdev)
struct
net_device
*
dev
;
struct
eth_plat_info
*
plat
=
pdev
->
dev
.
platform_data
;
u32
regs_phys
;
char
phy_id
[
BUS_ID_SIZE
];
int
err
;
if
(
!
(
dev
=
alloc_etherdev
(
sizeof
(
struct
port
))))
...
...
@@ -1182,22 +1182,19 @@ static int __devinit eth_init_one(struct platform_device *pdev)
__raw_writel
(
DEFAULT_CORE_CNTRL
,
&
port
->
regs
->
core_control
);
udelay
(
50
);
port
->
mii
.
dev
=
dev
;
port
->
mii
.
mdio_read
=
mdio_read
;
port
->
mii
.
mdio_write
=
mdio_write
;
port
->
mii
.
phy_id
=
plat
->
phy
;
port
->
mii
.
phy_id_mask
=
0x1F
;
port
->
mii
.
reg_num_mask
=
0x1F
;
snprintf
(
phy_id
,
BUS_ID_SIZE
,
PHY_ID_FMT
,
"0"
,
plat
->
phy
);
port
->
phydev
=
phy_connect
(
dev
,
phy_id
,
&
ixp4xx_adjust_link
,
0
,
PHY_INTERFACE_MODE_MII
);
if
(
IS_ERR
(
port
->
phydev
))
{
printk
(
KERN_ERR
"%s: Could not attach to PHY
\n
"
,
dev
->
name
);
return
PTR_ERR
(
port
->
phydev
);
}
port
->
phydev
->
irq
=
PHY_POLL
;
printk
(
KERN_INFO
"%s: MII PHY %i on %s
\n
"
,
dev
->
name
,
plat
->
phy
,
npe_name
(
port
->
npe
));
phy_reset
(
dev
,
plat
->
phy
);
port
->
mii_bmcr
=
mdio_read
(
dev
,
plat
->
phy
,
MII_BMCR
)
&
~
(
BMCR_RESET
|
BMCR_PDOWN
);
mdio_write
(
dev
,
plat
->
phy
,
MII_BMCR
,
port
->
mii_bmcr
|
BMCR_PDOWN
);
INIT_DELAYED_WORK
(
&
port
->
mdio_thread
,
mdio_thread
);
return
0
;
err_unreg:
...
...
@@ -1231,20 +1228,19 @@ static struct platform_driver ixp4xx_eth_driver = {
static
int
__init
eth_init_module
(
void
)
{
int
err
;
if
(
!
(
ixp4xx_read_feature_bits
()
&
IXP4XX_FEATURE_NPEB_ETH0
))
return
-
ENOSYS
;
/* All MII PHY accesses use NPE-B Ethernet registers */
spin_lock_init
(
&
mdio_lock
);
mdio_regs
=
(
struct
eth_regs
__iomem
*
)
IXP4XX_EthB_BASE_VIRT
;
__raw_writel
(
DEFAULT_CORE_CNTRL
,
&
mdio_regs
->
core_control
);
if
((
err
=
ixp4xx_mdio_register
()))
return
err
;
return
platform_driver_register
(
&
ixp4xx_eth_driver
);
}
static
void
__exit
eth_cleanup_module
(
void
)
{
platform_driver_unregister
(
&
ixp4xx_eth_driver
);
ixp4xx_mdio_remove
();
}
MODULE_AUTHOR
(
"Krzysztof Halasa"
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录