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
Kirill Smelkov
linux
Commits
db62983a
Commit
db62983a
authored
Feb 22, 2011
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'net/ax88796' of
git://git.pengutronix.de/git/mkl/linux-2.6
parents
9e1453c5
f6d7f2c6
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
395 additions
and
419 deletions
+395
-419
drivers/net/Kconfig
drivers/net/Kconfig
+2
-2
drivers/net/ax88796.c
drivers/net/ax88796.c
+393
-417
No files found.
drivers/net/Kconfig
View file @
db62983a
...
@@ -238,8 +238,8 @@ source "drivers/net/arm/Kconfig"
...
@@ -238,8 +238,8 @@ source "drivers/net/arm/Kconfig"
config AX88796
config AX88796
tristate "ASIX AX88796 NE2000 clone support"
tristate "ASIX AX88796 NE2000 clone support"
depends on ARM || MIPS || SUPERH
depends on ARM || MIPS || SUPERH
select
CRC32
select
PHYLIB
select M
II
select M
DIO_BITBANG
help
help
AX88796 driver, using platform bus to provide
AX88796 driver, using platform bus to provide
chip detection and resources
chip detection and resources
...
...
drivers/net/ax88796.c
View file @
db62983a
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* published by the Free Software Foundation.
*/
*/
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
...
@@ -17,22 +17,21 @@
...
@@ -17,22 +17,21 @@
#include <linux/isapnp.h>
#include <linux/isapnp.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/mdio-bitbang.h>
#include <linux/phy.h>
#include <linux/eeprom_93cx6.h>
#include <linux/eeprom_93cx6.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <net/ax88796.h>
#include <net/ax88796.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/io.h>
static
int
phy_debug
=
0
;
/* Rename the lib8390.c functions to show that they are in this driver */
/* Rename the lib8390.c functions to show that they are in this driver */
#define __ei_open ax_ei_open
#define __ei_open ax_ei_open
...
@@ -78,19 +77,22 @@ static unsigned char version[] = "ax88796.c: Copyright 2005,2007 Simtec Electron
...
@@ -78,19 +77,22 @@ static unsigned char version[] = "ax88796.c: Copyright 2005,2007 Simtec Electron
#define NESM_START_PG 0x40
/* First page of TX buffer */
#define NESM_START_PG 0x40
/* First page of TX buffer */
#define NESM_STOP_PG 0x80
/* Last page +1 of RX ring */
#define NESM_STOP_PG 0x80
/* Last page +1 of RX ring */
#define AX_GPOC_PPDSET BIT(6)
/* device private data */
/* device private data */
struct
ax_device
{
struct
ax_device
{
struct
timer_list
mii_timer
;
struct
mii_bus
*
mii_bus
;
spinlock_t
mii_lock
;
struct
mdiobb_ctrl
bb_ctrl
;
struct
mii_if_info
mii
;
struct
phy_device
*
phy_dev
;
void
__iomem
*
addr_memr
;
u8
reg_memr
;
int
link
;
int
speed
;
int
duplex
;
u32
msg_enable
;
void
__iomem
*
map2
;
void
__iomem
*
map2
;
struct
platform_device
*
dev
;
const
struct
ax_plat_data
*
plat
;
struct
resource
*
mem
;
struct
resource
*
mem2
;
struct
ax_plat_data
*
plat
;
unsigned
char
running
;
unsigned
char
running
;
unsigned
char
resume_open
;
unsigned
char
resume_open
;
...
@@ -102,15 +104,15 @@ struct ax_device {
...
@@ -102,15 +104,15 @@ struct ax_device {
static
inline
struct
ax_device
*
to_ax_dev
(
struct
net_device
*
dev
)
static
inline
struct
ax_device
*
to_ax_dev
(
struct
net_device
*
dev
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
return
(
struct
ax_device
*
)(
ei_local
+
1
);
return
(
struct
ax_device
*
)(
ei_local
+
1
);
}
}
/* ax_initial_check
/*
* ax_initial_check
*
*
* do an initial probe for the card to check wether it exists
* do an initial probe for the card to check wether it exists
* and is functional
* and is functional
*/
*/
static
int
ax_initial_check
(
struct
net_device
*
dev
)
static
int
ax_initial_check
(
struct
net_device
*
dev
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
...
@@ -122,10 +124,10 @@ static int ax_initial_check(struct net_device *dev)
...
@@ -122,10 +124,10 @@ static int ax_initial_check(struct net_device *dev)
if
(
reg0
==
0xFF
)
if
(
reg0
==
0xFF
)
return
-
ENODEV
;
return
-
ENODEV
;
ei_outb
(
E8390_NODMA
+
E8390_PAGE1
+
E8390_STOP
,
ioaddr
+
E8390_CMD
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE1
+
E8390_STOP
,
ioaddr
+
E8390_CMD
);
regd
=
ei_inb
(
ioaddr
+
0x0d
);
regd
=
ei_inb
(
ioaddr
+
0x0d
);
ei_outb
(
0xff
,
ioaddr
+
0x0d
);
ei_outb
(
0xff
,
ioaddr
+
0x0d
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
,
ioaddr
+
E8390_CMD
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
,
ioaddr
+
E8390_CMD
);
ei_inb
(
ioaddr
+
EN0_COUNTER0
);
/* Clear the counter by reading. */
ei_inb
(
ioaddr
+
EN0_COUNTER0
);
/* Clear the counter by reading. */
if
(
ei_inb
(
ioaddr
+
EN0_COUNTER0
)
!=
0
)
{
if
(
ei_inb
(
ioaddr
+
EN0_COUNTER0
)
!=
0
)
{
ei_outb
(
reg0
,
ioaddr
);
ei_outb
(
reg0
,
ioaddr
);
...
@@ -136,29 +138,28 @@ static int ax_initial_check(struct net_device *dev)
...
@@ -136,29 +138,28 @@ static int ax_initial_check(struct net_device *dev)
return
0
;
return
0
;
}
}
/* Hard reset the card. This used to pause for the same period that a
/*
8390 reset command required, but that shouldn't be necessary. */
* Hard reset the card. This used to pause for the same period that a
* 8390 reset command required, but that shouldn't be necessary.
*/
static
void
ax_reset_8390
(
struct
net_device
*
dev
)
static
void
ax_reset_8390
(
struct
net_device
*
dev
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
reset_start_time
=
jiffies
;
unsigned
long
reset_start_time
=
jiffies
;
void
__iomem
*
addr
=
(
void
__iomem
*
)
dev
->
base_addr
;
void
__iomem
*
addr
=
(
void
__iomem
*
)
dev
->
base_addr
;
if
(
ei_debug
>
1
)
if
(
ei_debug
>
1
)
dev_dbg
(
&
ax
->
dev
->
dev
,
"resetting the 8390 t=%ld
\n
"
,
jiffies
);
netdev_dbg
(
dev
,
"resetting the 8390 t=%ld
\n
"
,
jiffies
);
ei_outb
(
ei_inb
(
addr
+
NE_RESET
),
addr
+
NE_RESET
);
ei_outb
(
ei_inb
(
addr
+
NE_RESET
),
addr
+
NE_RESET
);
ei_
status
.
txing
=
0
;
ei_
local
->
txing
=
0
;
ei_
status
.
dmaing
=
0
;
ei_
local
->
dmaing
=
0
;
/* This check _should_not_ be necessary, omit eventually. */
/* This check _should_not_ be necessary, omit eventually. */
while
((
ei_inb
(
addr
+
EN0_ISR
)
&
ENISR_RESET
)
==
0
)
{
while
((
ei_inb
(
addr
+
EN0_ISR
)
&
ENISR_RESET
)
==
0
)
{
if
(
jiffies
-
reset_start_time
>
2
*
HZ
/
100
)
{
if
(
jiffies
-
reset_start_time
>
2
*
HZ
/
100
)
{
dev_warn
(
&
ax
->
dev
->
dev
,
"%s: %s did not complete.
\n
"
,
netdev_warn
(
dev
,
"%s: did not complete.
\n
"
,
__func__
);
__func__
,
dev
->
name
);
break
;
break
;
}
}
}
}
...
@@ -171,70 +172,72 @@ static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
...
@@ -171,70 +172,72 @@ static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int
ring_page
)
int
ring_page
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
void
__iomem
*
nic_base
=
ei_local
->
mem
;
void
__iomem
*
nic_base
=
ei_local
->
mem
;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if
(
ei_
status
.
dmaing
)
{
if
(
ei_
local
->
dmaing
)
{
dev_err
(
&
ax
->
dev
->
dev
,
"%s:
DMAing conflict in %s "
netdev_err
(
dev
,
"
DMAing conflict in %s "
"[DMAstat:%d][irqlock:%d].
\n
"
,
"[DMAstat:%d][irqlock:%d].
\n
"
,
dev
->
name
,
__func__
,
__func__
,
ei_
status
.
dmaing
,
ei_status
.
irqlock
);
ei_
local
->
dmaing
,
ei_local
->
irqlock
);
return
;
return
;
}
}
ei_
status
.
dmaing
|=
0x01
;
ei_
local
->
dmaing
|=
0x01
;
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
sizeof
(
struct
e8390_pkt_hdr
),
nic_base
+
EN0_RCNTLO
);
ei_outb
(
sizeof
(
struct
e8390_pkt_hdr
),
nic_base
+
EN0_RCNTLO
);
ei_outb
(
0
,
nic_base
+
EN0_RCNTHI
);
ei_outb
(
0
,
nic_base
+
EN0_RCNTHI
);
ei_outb
(
0
,
nic_base
+
EN0_RSARLO
);
/* On page boundary */
ei_outb
(
0
,
nic_base
+
EN0_RSARLO
);
/* On page boundary */
ei_outb
(
ring_page
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
ring_page
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
E8390_RREAD
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_RREAD
+
E8390_START
,
nic_base
+
NE_CMD
);
if
(
ei_status
.
word16
)
if
(
ei_local
->
word16
)
readsw
(
nic_base
+
NE_DATAPORT
,
hdr
,
sizeof
(
struct
e8390_pkt_hdr
)
>>
1
);
readsw
(
nic_base
+
NE_DATAPORT
,
hdr
,
sizeof
(
struct
e8390_pkt_hdr
)
>>
1
);
else
else
readsb
(
nic_base
+
NE_DATAPORT
,
hdr
,
sizeof
(
struct
e8390_pkt_hdr
));
readsb
(
nic_base
+
NE_DATAPORT
,
hdr
,
sizeof
(
struct
e8390_pkt_hdr
));
ei_outb
(
ENISR_RDC
,
nic_base
+
EN0_ISR
);
/* Ack intr. */
ei_outb
(
ENISR_RDC
,
nic_base
+
EN0_ISR
);
/* Ack intr. */
ei_
status
.
dmaing
&=
~
0x01
;
ei_
local
->
dmaing
&=
~
0x01
;
le16_to_cpus
(
&
hdr
->
count
);
le16_to_cpus
(
&
hdr
->
count
);
}
}
/* Block input and output, similar to the Crynwr packet driver. If you
/*
are porting to a new ethercard, look at the packet driver source for hints.
* Block input and output, similar to the Crynwr packet driver. If
The NEx000 doesn't share the on-board packet memory -- you have to put
* you are porting to a new ethercard, look at the packet driver
the packet out through the "remote DMA" dataport using ei_outb. */
* source for hints. The NEx000 doesn't share the on-board packet
* memory -- you have to put the packet out through the "remote DMA"
* dataport using ei_outb.
*/
static
void
ax_block_input
(
struct
net_device
*
dev
,
int
count
,
static
void
ax_block_input
(
struct
net_device
*
dev
,
int
count
,
struct
sk_buff
*
skb
,
int
ring_offset
)
struct
sk_buff
*
skb
,
int
ring_offset
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
void
__iomem
*
nic_base
=
ei_local
->
mem
;
void
__iomem
*
nic_base
=
ei_local
->
mem
;
char
*
buf
=
skb
->
data
;
char
*
buf
=
skb
->
data
;
if
(
ei_
status
.
dmaing
)
{
if
(
ei_
local
->
dmaing
)
{
dev_err
(
&
ax
->
dev
->
dev
,
netdev_err
(
dev
,
"
%s:
DMAing conflict in %s "
"DMAing conflict in %s "
"[DMAstat:%d][irqlock:%d].
\n
"
,
"[DMAstat:%d][irqlock:%d].
\n
"
,
dev
->
name
,
__func__
,
__func__
,
ei_
status
.
dmaing
,
ei_status
.
irqlock
);
ei_
local
->
dmaing
,
ei_local
->
irqlock
);
return
;
return
;
}
}
ei_
status
.
dmaing
|=
0x01
;
ei_
local
->
dmaing
|=
0x01
;
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
count
&
0xff
,
nic_base
+
EN0_RCNTLO
);
ei_outb
(
count
&
0xff
,
nic_base
+
EN0_RCNTLO
);
ei_outb
(
count
>>
8
,
nic_base
+
EN0_RCNTHI
);
ei_outb
(
count
>>
8
,
nic_base
+
EN0_RCNTHI
);
ei_outb
(
ring_offset
&
0xff
,
nic_base
+
EN0_RSARLO
);
ei_outb
(
ring_offset
&
0xff
,
nic_base
+
EN0_RSARLO
);
ei_outb
(
ring_offset
>>
8
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
ring_offset
>>
8
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
E8390_RREAD
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_RREAD
+
E8390_START
,
nic_base
+
NE_CMD
);
if
(
ei_
status
.
word16
)
{
if
(
ei_
local
->
word16
)
{
readsw
(
nic_base
+
NE_DATAPORT
,
buf
,
count
>>
1
);
readsw
(
nic_base
+
NE_DATAPORT
,
buf
,
count
>>
1
);
if
(
count
&
0x01
)
if
(
count
&
0x01
)
buf
[
count
-
1
]
=
ei_inb
(
nic_base
+
NE_DATAPORT
);
buf
[
count
-
1
]
=
ei_inb
(
nic_base
+
NE_DATAPORT
);
...
@@ -243,34 +246,34 @@ static void ax_block_input(struct net_device *dev, int count,
...
@@ -243,34 +246,34 @@ static void ax_block_input(struct net_device *dev, int count,
readsb
(
nic_base
+
NE_DATAPORT
,
buf
,
count
);
readsb
(
nic_base
+
NE_DATAPORT
,
buf
,
count
);
}
}
ei_
status
.
dmaing
&=
~
1
;
ei_
local
->
dmaing
&=
~
1
;
}
}
static
void
ax_block_output
(
struct
net_device
*
dev
,
int
count
,
static
void
ax_block_output
(
struct
net_device
*
dev
,
int
count
,
const
unsigned
char
*
buf
,
const
int
start_page
)
const
unsigned
char
*
buf
,
const
int
start_page
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
void
__iomem
*
nic_base
=
ei_local
->
mem
;
void
__iomem
*
nic_base
=
ei_local
->
mem
;
unsigned
long
dma_start
;
unsigned
long
dma_start
;
/* Round the count up for word writes. Do we need to do this?
/*
What effect will an odd byte count have on the 8390?
* Round the count up for word writes. Do we need to do this?
I should check someday. */
* What effect will an odd byte count have on the 8390? I
* should check someday.
if
(
ei_status
.
word16
&&
(
count
&
0x01
))
*/
if
(
ei_local
->
word16
&&
(
count
&
0x01
))
count
++
;
count
++
;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if
(
ei_
status
.
dmaing
)
{
if
(
ei_
local
->
dmaing
)
{
dev_err
(
&
ax
->
dev
->
dev
,
"%s:
DMAing conflict in %s."
netdev_err
(
dev
,
"
DMAing conflict in %s."
"[DMAstat:%d][irqlock:%d]
\n
"
,
"[DMAstat:%d][irqlock:%d]
\n
"
,
dev
->
name
,
__func__
,
__func__
,
ei_
status
.
dmaing
,
ei_status
.
irqlock
);
ei_
local
->
dmaing
,
ei_local
->
irqlock
);
return
;
return
;
}
}
ei_
status
.
dmaing
|=
0x01
;
ei_
local
->
dmaing
|=
0x01
;
/* We should already be in page 0, but to be safe... */
/* We should already be in page 0, but to be safe... */
ei_outb
(
E8390_PAGE0
+
E8390_START
+
E8390_NODMA
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_PAGE0
+
E8390_START
+
E8390_NODMA
,
nic_base
+
NE_CMD
);
...
@@ -283,245 +286,165 @@ static void ax_block_output(struct net_device *dev, int count,
...
@@ -283,245 +286,165 @@ static void ax_block_output(struct net_device *dev, int count,
ei_outb
(
start_page
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
start_page
,
nic_base
+
EN0_RSARHI
);
ei_outb
(
E8390_RWRITE
+
E8390_START
,
nic_base
+
NE_CMD
);
ei_outb
(
E8390_RWRITE
+
E8390_START
,
nic_base
+
NE_CMD
);
if
(
ei_
status
.
word16
)
{
if
(
ei_
local
->
word16
)
writesw
(
nic_base
+
NE_DATAPORT
,
buf
,
count
>>
1
);
writesw
(
nic_base
+
NE_DATAPORT
,
buf
,
count
>>
1
);
}
else
{
else
writesb
(
nic_base
+
NE_DATAPORT
,
buf
,
count
);
writesb
(
nic_base
+
NE_DATAPORT
,
buf
,
count
);
}
dma_start
=
jiffies
;
dma_start
=
jiffies
;
while
((
ei_inb
(
nic_base
+
EN0_ISR
)
&
ENISR_RDC
)
==
0
)
{
while
((
ei_inb
(
nic_base
+
EN0_ISR
)
&
ENISR_RDC
)
==
0
)
{
if
(
jiffies
-
dma_start
>
2
*
HZ
/
100
)
{
/* 20ms */
if
(
jiffies
-
dma_start
>
2
*
HZ
/
100
)
{
/* 20ms */
dev_warn
(
&
ax
->
dev
->
dev
,
netdev_warn
(
dev
,
"timeout waiting for Tx RDC.
\n
"
);
"%s: timeout waiting for Tx RDC.
\n
"
,
dev
->
name
);
ax_reset_8390
(
dev
);
ax_reset_8390
(
dev
);
ax_NS8390_init
(
dev
,
1
);
ax_NS8390_init
(
dev
,
1
);
break
;
break
;
}
}
}
}
ei_outb
(
ENISR_RDC
,
nic_base
+
EN0_ISR
);
/* Ack intr. */
ei_outb
(
ENISR_RDC
,
nic_base
+
EN0_ISR
);
/* Ack intr. */
ei_
status
.
dmaing
&=
~
0x01
;
ei_
local
->
dmaing
&=
~
0x01
;
}
}
/* definitions for accessing MII/EEPROM interface */
/* definitions for accessing MII/EEPROM interface */
#define AX_MEMR EI_SHIFT(0x14)
#define AX_MEMR EI_SHIFT(0x14)
#define AX_MEMR_MDC (1<<0)
#define AX_MEMR_MDC BIT(0)
#define AX_MEMR_MDIR (1<<1)
#define AX_MEMR_MDIR BIT(1)
#define AX_MEMR_MDI (1<<2)
#define AX_MEMR_MDI BIT(2)
#define AX_MEMR_MDO (1<<3)
#define AX_MEMR_MDO BIT(3)
#define AX_MEMR_EECS (1<<4)
#define AX_MEMR_EECS BIT(4)
#define AX_MEMR_EEI (1<<5)
#define AX_MEMR_EEI BIT(5)
#define AX_MEMR_EEO (1<<6)
#define AX_MEMR_EEO BIT(6)
#define AX_MEMR_EECLK (1<<7)
#define AX_MEMR_EECLK BIT(7)
/* ax_mii_ei_outbits
static
void
ax_handle_link_change
(
struct
net_device
*
dev
)
*
* write the specified set of bits to the phy
*/
static
void
ax_mii_ei_outbits
(
struct
net_device
*
dev
,
unsigned
int
bits
,
int
len
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
void
__iomem
*
memr_addr
=
(
void
__iomem
*
)
dev
->
base_addr
+
AX_MEMR
;
struct
phy_device
*
phy_dev
=
ax
->
phy_dev
;
unsigned
int
memr
;
int
status_change
=
0
;
/* clock low, data to output mode */
memr
=
ei_inb
(
memr_addr
);
memr
&=
~
(
AX_MEMR_MDC
|
AX_MEMR_MDIR
);
ei_outb
(
memr
,
memr_addr
);
for
(
len
--
;
len
>=
0
;
len
--
)
{
if
(
bits
&
(
1
<<
len
))
memr
|=
AX_MEMR_MDO
;
else
memr
&=
~
AX_MEMR_MDO
;
ei_outb
(
memr
,
memr_addr
);
/* clock high */
ei_outb
(
memr
|
AX_MEMR_MDC
,
memr_addr
);
if
(
phy_dev
->
link
&&
((
ax
->
speed
!=
phy_dev
->
speed
)
||
udelay
(
1
);
(
ax
->
duplex
!=
phy_dev
->
duplex
)))
{
/* clock low */
ax
->
speed
=
phy_dev
->
speed
;
ei_outb
(
memr
,
memr_addr
);
ax
->
duplex
=
phy_dev
->
duplex
;
status_change
=
1
;
}
}
/* leaves the clock line low, mdir input */
if
(
phy_dev
->
link
!=
ax
->
link
)
{
memr
|=
AX_MEMR_MDIR
;
if
(
!
phy_dev
->
link
)
{
ei_outb
(
memr
,
(
void
__iomem
*
)
dev
->
base_addr
+
AX_MEMR
);
ax
->
speed
=
0
;
}
ax
->
duplex
=
-
1
;
/* ax_phy_ei_inbits
*
* read a specified number of bits from the phy
*/
static
unsigned
int
ax_phy_ei_inbits
(
struct
net_device
*
dev
,
int
no
)
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
void
__iomem
*
memr_addr
=
(
void
__iomem
*
)
dev
->
base_addr
+
AX_MEMR
;
unsigned
int
memr
;
unsigned
int
result
=
0
;
/* clock low, data to input mode */
memr
=
ei_inb
(
memr_addr
);
memr
&=
~
AX_MEMR_MDC
;
memr
|=
AX_MEMR_MDIR
;
ei_outb
(
memr
,
memr_addr
);
for
(
no
--
;
no
>=
0
;
no
--
)
{
ei_outb
(
memr
|
AX_MEMR_MDC
,
memr_addr
);
udelay
(
1
);
if
(
ei_inb
(
memr_addr
)
&
AX_MEMR_MDI
)
result
|=
(
1
<<
no
);
ei_outb
(
memr
,
memr_addr
);
}
}
ax
->
link
=
phy_dev
->
link
;
return
result
;
status_change
=
1
;
}
}
/* ax_phy_issueaddr
*
* use the low level bit shifting routines to send the address
* and command to the specified phy
*/
static
void
if
(
status_change
)
ax_phy_issueaddr
(
struct
net_device
*
dev
,
int
phy_addr
,
int
reg
,
int
opc
)
phy_print_status
(
phy_dev
);
{
if
(
phy_debug
)
pr_debug
(
"%s: dev %p, %04x, %04x, %d
\n
"
,
__func__
,
dev
,
phy_addr
,
reg
,
opc
);
ax_mii_ei_outbits
(
dev
,
0x3f
,
6
);
/* pre-amble */
ax_mii_ei_outbits
(
dev
,
1
,
2
);
/* frame-start */
ax_mii_ei_outbits
(
dev
,
opc
,
2
);
/* op code */
ax_mii_ei_outbits
(
dev
,
phy_addr
,
5
);
/* phy address */
ax_mii_ei_outbits
(
dev
,
reg
,
5
);
/* reg address */
}
}
static
int
static
int
ax_mii_probe
(
struct
net_device
*
dev
)
ax_phy_read
(
struct
net_device
*
dev
,
int
phy_addr
,
int
reg
)
{
{
struct
ei_device
*
ei_local
=
netdev_pri
v
(
dev
);
struct
ax_device
*
ax
=
to_ax_de
v
(
dev
);
unsigned
long
flags
;
struct
phy_device
*
phy_dev
=
NULL
;
unsigned
int
resul
t
;
int
re
t
;
spin_lock_irqsave
(
&
ei_local
->
page_lock
,
flags
);
/* find the first phy */
phy_dev
=
phy_find_first
(
ax
->
mii_bus
);
if
(
!
phy_dev
)
{
netdev_err
(
dev
,
"no PHY found
\n
"
);
return
-
ENODEV
;
}
ax_phy_issueaddr
(
dev
,
phy_addr
,
reg
,
2
);
ret
=
phy_connect_direct
(
dev
,
phy_dev
,
ax_handle_link_change
,
0
,
PHY_INTERFACE_MODE_MII
);
if
(
ret
)
{
netdev_err
(
dev
,
"Could not attach to PHY
\n
"
);
return
ret
;
}
result
=
ax_phy_ei_inbits
(
dev
,
17
);
/* mask with MAC supported features */
result
&=
~
(
3
<<
16
);
phy_dev
->
supported
&=
PHY_BASIC_FEATURES
;
phy_dev
->
advertising
=
phy_dev
->
supported
;
spin_unlock_irqrestore
(
&
ei_local
->
page_lock
,
flags
)
;
ax
->
phy_dev
=
phy_dev
;
if
(
phy_debug
)
netdev_info
(
dev
,
"PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)
\n
"
,
pr_debug
(
"%s: %04x.%04x => read %04x
\n
"
,
__func__
,
phy_dev
->
drv
->
name
,
dev_name
(
&
phy_dev
->
dev
),
phy_dev
->
irq
);
phy_addr
,
reg
,
result
);
return
result
;
return
0
;
}
}
static
void
static
void
ax_phy_switch
(
struct
net_device
*
dev
,
int
on
)
ax_phy_write
(
struct
net_device
*
dev
,
int
phy_addr
,
int
reg
,
int
value
)
{
{
struct
ei_device
*
ei
=
netdev_priv
(
dev
);
struct
ei_device
*
ei
_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
flags
;
dev_dbg
(
&
ax
->
dev
->
dev
,
"%s: %p, %04x, %04x %04x
\n
"
,
__func__
,
dev
,
phy_addr
,
reg
,
value
);
spin_lock_irqsave
(
&
ei
->
page_lock
,
flags
);
ax_phy_issueaddr
(
dev
,
phy_addr
,
reg
,
1
);
ax_mii_ei_outbits
(
dev
,
2
,
2
);
/* send TA */
ax_mii_ei_outbits
(
dev
,
value
,
16
);
spin_unlock_irqrestore
(
&
ei
->
page_lock
,
flags
);
}
static
void
ax_mii_expiry
(
unsigned
long
data
)
u8
reg_gpoc
=
ax
->
plat
->
gpoc_val
;
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
ax
->
mii_lock
,
flags
);
if
(
!!
on
)
mii_check_media
(
&
ax
->
mii
,
netif_msg_link
(
ax
),
0
);
reg_gpoc
&=
~
AX_GPOC_PPDSET
;
spin_unlock_irqrestore
(
&
ax
->
mii_lock
,
flags
);
else
reg_gpoc
|=
AX_GPOC_PPDSET
;
if
(
ax
->
running
)
{
ei_outb
(
reg_gpoc
,
ei_local
->
mem
+
EI_SHIFT
(
0x17
));
ax
->
mii_timer
.
expires
=
jiffies
+
HZ
*
2
;
add_timer
(
&
ax
->
mii_timer
);
}
}
}
static
int
ax_open
(
struct
net_device
*
dev
)
static
int
ax_open
(
struct
net_device
*
dev
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
int
ret
;
int
ret
;
dev_dbg
(
&
ax
->
dev
->
dev
,
"%s: open
\n
"
,
dev
->
name
);
netdev_dbg
(
dev
,
"open
\n
"
);
ret
=
request_irq
(
dev
->
irq
,
ax_ei_interrupt
,
ax
->
irqflags
,
ret
=
request_irq
(
dev
->
irq
,
ax_ei_interrupt
,
ax
->
irqflags
,
dev
->
name
,
dev
);
dev
->
name
,
dev
);
if
(
ret
)
if
(
ret
)
return
ret
;
goto
failed_request_irq
;
ret
=
ax_ei_open
(
dev
);
if
(
ret
)
{
free_irq
(
dev
->
irq
,
dev
);
return
ret
;
}
/* turn the phy on (if turned off) */
/* turn the phy on (if turned off) */
ax_phy_switch
(
dev
,
1
);
ei_outb
(
ax
->
plat
->
gpoc_val
,
ei_local
->
mem
+
EI_SHIFT
(
0x17
));
ret
=
ax_mii_probe
(
dev
);
ax
->
running
=
1
;
if
(
ret
)
goto
failed_mii_probe
;
/* start the MII timer */
phy_start
(
ax
->
phy_dev
);
init_timer
(
&
ax
->
mii_timer
);
ax
->
mii_timer
.
expires
=
jiffies
+
1
;
ret
=
ax_ei_open
(
dev
)
;
ax
->
mii_timer
.
data
=
(
unsigned
long
)
dev
;
if
(
ret
)
ax
->
mii_timer
.
function
=
ax_mii_expiry
;
goto
failed_ax_ei_open
;
a
dd_timer
(
&
ax
->
mii_timer
)
;
a
x
->
running
=
1
;
return
0
;
return
0
;
failed_ax_ei_open:
phy_disconnect
(
ax
->
phy_dev
);
failed_mii_probe:
ax_phy_switch
(
dev
,
0
);
free_irq
(
dev
->
irq
,
dev
);
failed_request_irq:
return
ret
;
}
}
static
int
ax_close
(
struct
net_device
*
dev
)
static
int
ax_close
(
struct
net_device
*
dev
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
dev_dbg
(
&
ax
->
dev
->
dev
,
"%s: close
\n
"
,
dev
->
name
);
netdev_dbg
(
dev
,
"close
\n
"
);
/* turn the phy off */
ei_outb
(
ax
->
plat
->
gpoc_val
|
(
1
<<
6
),
ei_local
->
mem
+
EI_SHIFT
(
0x17
));
ax
->
running
=
0
;
ax
->
running
=
0
;
wmb
();
wmb
();
del_timer_sync
(
&
ax
->
mii_timer
);
ax_ei_close
(
dev
);
ax_ei_close
(
dev
);
/* turn the phy off */
ax_phy_switch
(
dev
,
0
);
phy_disconnect
(
ax
->
phy_dev
);
free_irq
(
dev
->
irq
,
dev
);
free_irq
(
dev
->
irq
,
dev
);
return
0
;
return
0
;
}
}
...
@@ -529,17 +452,15 @@ static int ax_close(struct net_device *dev)
...
@@ -529,17 +452,15 @@ static int ax_close(struct net_device *dev)
static
int
ax_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
req
,
int
cmd
)
static
int
ax_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
req
,
int
cmd
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
flags
;
struct
phy_device
*
phy_dev
=
ax
->
phy_dev
;
int
rc
;
if
(
!
netif_running
(
dev
))
if
(
!
netif_running
(
dev
))
return
-
EINVAL
;
return
-
EINVAL
;
spin_lock_irqsave
(
&
ax
->
mii_lock
,
flags
);
if
(
!
phy_dev
)
rc
=
generic_mii_ioctl
(
&
ax
->
mii
,
if_mii
(
req
),
cmd
,
NULL
);
return
-
ENODEV
;
spin_unlock_irqrestore
(
&
ax
->
mii_lock
,
flags
);
return
rc
;
return
phy_mii_ioctl
(
phy_dev
,
req
,
cmd
)
;
}
}
/* ethtool ops */
/* ethtool ops */
...
@@ -547,56 +468,40 @@ static int ax_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
...
@@ -547,56 +468,40 @@ static int ax_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
static
void
ax_get_drvinfo
(
struct
net_device
*
dev
,
static
void
ax_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
struct
ethtool_drvinfo
*
info
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
platform_device
*
pdev
=
to_platform_device
(
dev
->
dev
.
parent
);
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
driver
,
DRV_NAME
);
strcpy
(
info
->
version
,
DRV_VERSION
);
strcpy
(
info
->
version
,
DRV_VERSION
);
strcpy
(
info
->
bus_info
,
ax
->
dev
->
name
);
strcpy
(
info
->
bus_info
,
p
dev
->
name
);
}
}
static
int
ax_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
static
int
ax_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
flags
;
struct
phy_device
*
phy_dev
=
ax
->
phy_dev
;
spin_lock_irqsave
(
&
ax
->
mii_lock
,
flags
);
if
(
!
phy_dev
)
mii_ethtool_gset
(
&
ax
->
mii
,
cmd
);
return
-
ENODEV
;
spin_unlock_irqrestore
(
&
ax
->
mii_lock
,
flags
);
return
0
;
return
phy_ethtool_gset
(
phy_dev
,
cmd
)
;
}
}
static
int
ax_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
static
int
ax_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
unsigned
long
flags
;
struct
phy_device
*
phy_dev
=
ax
->
phy_dev
;
int
rc
;
spin_lock_irqsave
(
&
ax
->
mii_lock
,
flags
);
rc
=
mii_ethtool_sset
(
&
ax
->
mii
,
cmd
);
spin_unlock_irqrestore
(
&
ax
->
mii_lock
,
flags
);
return
rc
;
}
static
int
ax_nway_reset
(
struct
net_device
*
dev
)
if
(
!
phy_dev
)
{
return
-
ENODEV
;
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
return
mii_nway_restart
(
&
ax
->
mii
);
}
static
u32
ax_get_link
(
struct
net_device
*
dev
)
return
phy_ethtool_sset
(
phy_dev
,
cmd
);
{
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
return
mii_link_ok
(
&
ax
->
mii
);
}
}
static
const
struct
ethtool_ops
ax_ethtool_ops
=
{
static
const
struct
ethtool_ops
ax_ethtool_ops
=
{
.
get_drvinfo
=
ax_get_drvinfo
,
.
get_drvinfo
=
ax_get_drvinfo
,
.
get_settings
=
ax_get_settings
,
.
get_settings
=
ax_get_settings
,
.
set_settings
=
ax_set_settings
,
.
set_settings
=
ax_set_settings
,
.
nway_reset
=
ax_nway_reset
,
.
get_link
=
ethtool_op_get_link
,
.
get_link
=
ax_get_link
,
};
};
#ifdef CONFIG_AX88796_93CX6
#ifdef CONFIG_AX88796_93CX6
...
@@ -647,30 +552,124 @@ static const struct net_device_ops ax_netdev_ops = {
...
@@ -647,30 +552,124 @@ static const struct net_device_ops ax_netdev_ops = {
#endif
#endif
};
};
static
void
ax_bb_mdc
(
struct
mdiobb_ctrl
*
ctrl
,
int
level
)
{
struct
ax_device
*
ax
=
container_of
(
ctrl
,
struct
ax_device
,
bb_ctrl
);
if
(
level
)
ax
->
reg_memr
|=
AX_MEMR_MDC
;
else
ax
->
reg_memr
&=
~
AX_MEMR_MDC
;
ei_outb
(
ax
->
reg_memr
,
ax
->
addr_memr
);
}
static
void
ax_bb_dir
(
struct
mdiobb_ctrl
*
ctrl
,
int
output
)
{
struct
ax_device
*
ax
=
container_of
(
ctrl
,
struct
ax_device
,
bb_ctrl
);
if
(
output
)
ax
->
reg_memr
&=
~
AX_MEMR_MDIR
;
else
ax
->
reg_memr
|=
AX_MEMR_MDIR
;
ei_outb
(
ax
->
reg_memr
,
ax
->
addr_memr
);
}
static
void
ax_bb_set_data
(
struct
mdiobb_ctrl
*
ctrl
,
int
value
)
{
struct
ax_device
*
ax
=
container_of
(
ctrl
,
struct
ax_device
,
bb_ctrl
);
if
(
value
)
ax
->
reg_memr
|=
AX_MEMR_MDO
;
else
ax
->
reg_memr
&=
~
AX_MEMR_MDO
;
ei_outb
(
ax
->
reg_memr
,
ax
->
addr_memr
);
}
static
int
ax_bb_get_data
(
struct
mdiobb_ctrl
*
ctrl
)
{
struct
ax_device
*
ax
=
container_of
(
ctrl
,
struct
ax_device
,
bb_ctrl
);
int
reg_memr
=
ei_inb
(
ax
->
addr_memr
);
return
reg_memr
&
AX_MEMR_MDI
?
1
:
0
;
}
static
struct
mdiobb_ops
bb_ops
=
{
.
owner
=
THIS_MODULE
,
.
set_mdc
=
ax_bb_mdc
,
.
set_mdio_dir
=
ax_bb_dir
,
.
set_mdio_data
=
ax_bb_set_data
,
.
get_mdio_data
=
ax_bb_get_data
,
};
/* setup code */
/* setup code */
static
int
ax_mii_init
(
struct
net_device
*
dev
)
{
struct
platform_device
*
pdev
=
to_platform_device
(
dev
->
dev
.
parent
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
int
err
,
i
;
ax
->
bb_ctrl
.
ops
=
&
bb_ops
;
ax
->
addr_memr
=
ei_local
->
mem
+
AX_MEMR
;
ax
->
mii_bus
=
alloc_mdio_bitbang
(
&
ax
->
bb_ctrl
);
if
(
!
ax
->
mii_bus
)
{
err
=
-
ENOMEM
;
goto
out
;
}
ax
->
mii_bus
->
name
=
"ax88796_mii_bus"
;
ax
->
mii_bus
->
parent
=
dev
->
dev
.
parent
;
snprintf
(
ax
->
mii_bus
->
id
,
MII_BUS_ID_SIZE
,
"%x"
,
pdev
->
id
);
ax
->
mii_bus
->
irq
=
kmalloc
(
sizeof
(
int
)
*
PHY_MAX_ADDR
,
GFP_KERNEL
);
if
(
!
ax
->
mii_bus
->
irq
)
{
err
=
-
ENOMEM
;
goto
out_free_mdio_bitbang
;
}
for
(
i
=
0
;
i
<
PHY_MAX_ADDR
;
i
++
)
ax
->
mii_bus
->
irq
[
i
]
=
PHY_POLL
;
err
=
mdiobus_register
(
ax
->
mii_bus
);
if
(
err
)
goto
out_free_irq
;
return
0
;
out_free_irq:
kfree
(
ax
->
mii_bus
->
irq
);
out_free_mdio_bitbang:
free_mdio_bitbang
(
ax
->
mii_bus
);
out:
return
err
;
}
static
void
ax_initial_setup
(
struct
net_device
*
dev
,
struct
ei_device
*
ei_local
)
static
void
ax_initial_setup
(
struct
net_device
*
dev
,
struct
ei_device
*
ei_local
)
{
{
void
__iomem
*
ioaddr
=
ei_local
->
mem
;
void
__iomem
*
ioaddr
=
ei_local
->
mem
;
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
/* Select page 0*/
/* Select page 0
*/
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_STOP
,
ioaddr
+
E8390_CMD
);
ei_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_STOP
,
ioaddr
+
E8390_CMD
);
/* set to byte access */
/* set to byte access */
ei_outb
(
ax
->
plat
->
dcr_val
&
~
1
,
ioaddr
+
EN0_DCFG
);
ei_outb
(
ax
->
plat
->
dcr_val
&
~
1
,
ioaddr
+
EN0_DCFG
);
ei_outb
(
ax
->
plat
->
gpoc_val
,
ioaddr
+
EI_SHIFT
(
0x17
));
ei_outb
(
ax
->
plat
->
gpoc_val
,
ioaddr
+
EI_SHIFT
(
0x17
));
}
}
/* ax_init_dev
/*
* ax_init_dev
*
*
* initialise the specified device, taking care to note the MAC
* initialise the specified device, taking care to note the MAC
* address it may already have (if configured), ensure
* address it may already have (if configured), ensure
* the device is ready to be used by lib8390.c and registerd with
* the device is ready to be used by lib8390.c and registerd with
* the network layer.
* the network layer.
*/
*/
static
int
ax_init_dev
(
struct
net_device
*
dev
)
static
int
ax_init_dev
(
struct
net_device
*
dev
,
int
first_init
)
{
{
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
...
@@ -690,12 +689,12 @@ static int ax_init_dev(struct net_device *dev, int first_init)
...
@@ -690,12 +689,12 @@ static int ax_init_dev(struct net_device *dev, int first_init)
/* read the mac from the card prom if we need it */
/* read the mac from the card prom if we need it */
if
(
first_init
&&
ax
->
plat
->
flags
&
AXFLG_HAS_EEPROM
)
{
if
(
ax
->
plat
->
flags
&
AXFLG_HAS_EEPROM
)
{
unsigned
char
SA_prom
[
32
];
unsigned
char
SA_prom
[
32
];
for
(
i
=
0
;
i
<
sizeof
(
SA_prom
);
i
+=
2
)
{
for
(
i
=
0
;
i
<
sizeof
(
SA_prom
);
i
+=
2
)
{
SA_prom
[
i
]
=
ei_inb
(
ioaddr
+
NE_DATAPORT
);
SA_prom
[
i
]
=
ei_inb
(
ioaddr
+
NE_DATAPORT
);
SA_prom
[
i
+
1
]
=
ei_inb
(
ioaddr
+
NE_DATAPORT
);
SA_prom
[
i
+
1
]
=
ei_inb
(
ioaddr
+
NE_DATAPORT
);
}
}
if
(
ax
->
plat
->
wordlength
==
2
)
if
(
ax
->
plat
->
wordlength
==
2
)
...
@@ -706,7 +705,7 @@ static int ax_init_dev(struct net_device *dev, int first_init)
...
@@ -706,7 +705,7 @@ static int ax_init_dev(struct net_device *dev, int first_init)
}
}
#ifdef CONFIG_AX88796_93CX6
#ifdef CONFIG_AX88796_93CX6
if
(
first_init
&&
ax
->
plat
->
flags
&
AXFLG_HAS_93CX6
)
{
if
(
ax
->
plat
->
flags
&
AXFLG_HAS_93CX6
)
{
unsigned
char
mac_addr
[
6
];
unsigned
char
mac_addr
[
6
];
struct
eeprom_93cx6
eeprom
;
struct
eeprom_93cx6
eeprom
;
...
@@ -732,10 +731,7 @@ static int ax_init_dev(struct net_device *dev, int first_init)
...
@@ -732,10 +731,7 @@ static int ax_init_dev(struct net_device *dev, int first_init)
stop_page
=
NE1SM_STOP_PG
;
stop_page
=
NE1SM_STOP_PG
;
}
}
/* load the mac-address from the device if this is the
/* load the mac-address from the device */
* first time we've initialised */
if
(
first_init
)
{
if
(
ax
->
plat
->
flags
&
AXFLG_MAC_FROMDEV
)
{
if
(
ax
->
plat
->
flags
&
AXFLG_MAC_FROMDEV
)
{
ei_outb
(
E8390_NODMA
+
E8390_PAGE1
+
E8390_STOP
,
ei_outb
(
E8390_NODMA
+
E8390_PAGE1
+
E8390_STOP
,
ei_local
->
mem
+
E8390_CMD
);
/* 0x61 */
ei_local
->
mem
+
E8390_CMD
);
/* 0x61 */
...
@@ -748,51 +744,43 @@ static int ax_init_dev(struct net_device *dev, int first_init)
...
@@ -748,51 +744,43 @@ static int ax_init_dev(struct net_device *dev, int first_init)
ax
->
plat
->
mac_addr
)
ax
->
plat
->
mac_addr
)
memcpy
(
dev
->
dev_addr
,
ax
->
plat
->
mac_addr
,
memcpy
(
dev
->
dev_addr
,
ax
->
plat
->
mac_addr
,
ETHER_ADDR_LEN
);
ETHER_ADDR_LEN
);
}
ax_reset_8390
(
dev
);
ax_reset_8390
(
dev
);
ei_
status
.
name
=
"AX88796"
;
ei_
local
->
name
=
"AX88796"
;
ei_
status
.
tx_start_page
=
start_page
;
ei_
local
->
tx_start_page
=
start_page
;
ei_
status
.
stop_page
=
stop_page
;
ei_
local
->
stop_page
=
stop_page
;
ei_
status
.
word16
=
(
ax
->
plat
->
wordlength
==
2
);
ei_
local
->
word16
=
(
ax
->
plat
->
wordlength
==
2
);
ei_
status
.
rx_start_page
=
start_page
+
TX_PAGES
;
ei_
local
->
rx_start_page
=
start_page
+
TX_PAGES
;
#ifdef PACKETBUF_MEMSIZE
#ifdef PACKETBUF_MEMSIZE
/* Allow the packet buffer size to be overridden by know-it-alls. */
/* Allow the packet buffer size to be overridden by know-it-alls. */
ei_
status
.
stop_page
=
ei_status
.
tx_start_page
+
PACKETBUF_MEMSIZE
;
ei_
local
->
stop_page
=
ei_local
->
tx_start_page
+
PACKETBUF_MEMSIZE
;
#endif
#endif
ei_
status
.
reset_8390
=
&
ax_reset_8390
;
ei_
local
->
reset_8390
=
&
ax_reset_8390
;
ei_
status
.
block_input
=
&
ax_block_input
;
ei_
local
->
block_input
=
&
ax_block_input
;
ei_
status
.
block_output
=
&
ax_block_output
;
ei_
local
->
block_output
=
&
ax_block_output
;
ei_
status
.
get_8390_hdr
=
&
ax_get_8390_hdr
;
ei_
local
->
get_8390_hdr
=
&
ax_get_8390_hdr
;
ei_
status
.
priv
=
0
;
ei_
local
->
priv
=
0
;
dev
->
netdev_ops
=
&
ax_netdev_ops
;
dev
->
netdev_ops
=
&
ax_netdev_ops
;
dev
->
ethtool_ops
=
&
ax_ethtool_ops
;
dev
->
ethtool_ops
=
&
ax_ethtool_ops
;
ax
->
msg_enable
=
NETIF_MSG_LINK
;
ret
=
ax_mii_init
(
dev
);
ax
->
mii
.
phy_id_mask
=
0x1f
;
if
(
ret
)
ax
->
mii
.
reg_num_mask
=
0x1f
;
goto
out_irq
;
ax
->
mii
.
phy_id
=
0x10
;
/* onboard phy */
ax
->
mii
.
force_media
=
0
;
ax
->
mii
.
full_duplex
=
0
;
ax
->
mii
.
mdio_read
=
ax_phy_read
;
ax
->
mii
.
mdio_write
=
ax_phy_write
;
ax
->
mii
.
dev
=
dev
;
ax_NS8390_init
(
dev
,
0
);
ax_NS8390_init
(
dev
,
0
);
if
(
first_init
)
dev_info
(
&
ax
->
dev
->
dev
,
"%dbit, irq %d, %lx, MAC: %pM
\n
"
,
ei_status
.
word16
?
16
:
8
,
dev
->
irq
,
dev
->
base_addr
,
dev
->
dev_addr
);
ret
=
register_netdev
(
dev
);
ret
=
register_netdev
(
dev
);
if
(
ret
)
if
(
ret
)
goto
out_irq
;
goto
out_irq
;
netdev_info
(
dev
,
"%dbit, irq %d, %lx, MAC: %pM
\n
"
,
ei_local
->
word16
?
16
:
8
,
dev
->
irq
,
dev
->
base_addr
,
dev
->
dev_addr
);
return
0
;
return
0
;
out_irq:
out_irq:
...
@@ -802,24 +790,24 @@ static int ax_init_dev(struct net_device *dev, int first_init)
...
@@ -802,24 +790,24 @@ static int ax_init_dev(struct net_device *dev, int first_init)
return
ret
;
return
ret
;
}
}
static
int
ax_remove
(
struct
platform_device
*
_
dev
)
static
int
ax_remove
(
struct
platform_device
*
p
dev
)
{
{
struct
net_device
*
dev
=
platform_get_drvdata
(
_
dev
);
struct
net_device
*
dev
=
platform_get_drvdata
(
p
dev
);
struct
ax_device
*
ax
;
struct
ei_device
*
ei_local
=
netdev_priv
(
dev
)
;
struct
ax_device
*
ax
=
to_ax_dev
(
dev
);
ax
=
to_ax_dev
(
dev
)
;
struct
resource
*
mem
;
unregister_netdev
(
dev
);
unregister_netdev
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
free_irq
(
dev
->
irq
,
dev
);
iounmap
(
ei_
status
.
mem
);
iounmap
(
ei_
local
->
mem
);
release_resource
(
ax
->
mem
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
kfree
(
ax
->
mem
);
release_mem_region
(
mem
->
start
,
resource_size
(
mem
)
);
if
(
ax
->
map2
)
{
if
(
ax
->
map2
)
{
iounmap
(
ax
->
map2
);
iounmap
(
ax
->
map2
);
release_resource
(
ax
->
mem2
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
kfree
(
ax
->
mem2
);
release_mem_region
(
mem
->
start
,
resource_size
(
mem
)
);
}
}
free_netdev
(
dev
);
free_netdev
(
dev
);
...
@@ -827,19 +815,20 @@ static int ax_remove(struct platform_device *_dev)
...
@@ -827,19 +815,20 @@ static int ax_remove(struct platform_device *_dev)
return
0
;
return
0
;
}
}
/* ax_probe
/*
* ax_probe
*
*
* This is the entry point when the platform device system uses to
* This is the entry point when the platform device system uses to
* notify us of a new device to attach to. Allocate memory, find
* notify us of a new device to attach to. Allocate memory, find the
* the resources and information passed, and map the necessary registers.
* resources and information passed, and map the necessary registers.
*/
*/
static
int
ax_probe
(
struct
platform_device
*
pdev
)
static
int
ax_probe
(
struct
platform_device
*
pdev
)
{
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
struct
ei_device
*
ei_local
;
struct
ax_device
*
ax
;
struct
ax_device
*
ax
;
struct
resource
*
res
;
struct
resource
*
irq
,
*
mem
,
*
mem2
;
size_t
size
;
resource_size_t
mem_size
,
mem2_size
=
0
;
int
ret
=
0
;
int
ret
=
0
;
dev
=
ax__alloc_ei_netdev
(
sizeof
(
struct
ax_device
));
dev
=
ax__alloc_ei_netdev
(
sizeof
(
struct
ax_device
));
...
@@ -847,120 +836,107 @@ static int ax_probe(struct platform_device *pdev)
...
@@ -847,120 +836,107 @@ static int ax_probe(struct platform_device *pdev)
return
-
ENOMEM
;
return
-
ENOMEM
;
/* ok, let's setup our device */
/* ok, let's setup our device */
SET_NETDEV_DEV
(
dev
,
&
pdev
->
dev
);
ei_local
=
netdev_priv
(
dev
);
ax
=
to_ax_dev
(
dev
);
ax
=
to_ax_dev
(
dev
);
memset
(
ax
,
0
,
sizeof
(
struct
ax_device
));
spin_lock_init
(
&
ax
->
mii_lock
);
ax
->
dev
=
pdev
;
ax
->
plat
=
pdev
->
dev
.
platform_data
;
ax
->
plat
=
pdev
->
dev
.
platform_data
;
platform_set_drvdata
(
pdev
,
dev
);
platform_set_drvdata
(
pdev
,
dev
);
ei_
status
.
rxcr_base
=
ax
->
plat
->
rcr_val
;
ei_
local
->
rxcr_base
=
ax
->
plat
->
rcr_val
;
/* find the platform resources */
/* find the platform resources */
irq
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_IRQ
,
0
);
if
(
!
irq
)
{
if
(
res
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"no IRQ specified
\n
"
);
dev_err
(
&
pdev
->
dev
,
"no IRQ specified
\n
"
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_mem
;
goto
exit_mem
;
}
}
dev
->
irq
=
res
->
start
;
dev
->
irq
=
irq
->
start
;
ax
->
irqflags
=
res
->
flags
&
IRQF_TRIGGER_MASK
;
ax
->
irqflags
=
irq
->
flags
&
IRQF_TRIGGER_MASK
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
res
==
NULL
)
{
if
(
!
mem
)
{
dev_err
(
&
pdev
->
dev
,
"no MEM specified
\n
"
);
dev_err
(
&
pdev
->
dev
,
"no MEM specified
\n
"
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_mem
;
goto
exit_mem
;
}
}
size
=
(
res
->
end
-
res
->
start
)
+
1
;
mem_size
=
resource_size
(
mem
);
/* setup the register offsets from either the platform data
* or by using the size of the resource provided */
/*
* setup the register offsets from either the platform data or
* by using the size of the resource provided
*/
if
(
ax
->
plat
->
reg_offsets
)
if
(
ax
->
plat
->
reg_offsets
)
ei_
status
.
reg_offset
=
ax
->
plat
->
reg_offsets
;
ei_
local
->
reg_offset
=
ax
->
plat
->
reg_offsets
;
else
{
else
{
ei_
status
.
reg_offset
=
ax
->
reg_offsets
;
ei_
local
->
reg_offset
=
ax
->
reg_offsets
;
for
(
ret
=
0
;
ret
<
0x18
;
ret
++
)
for
(
ret
=
0
;
ret
<
0x18
;
ret
++
)
ax
->
reg_offsets
[
ret
]
=
(
size
/
0x18
)
*
ret
;
ax
->
reg_offsets
[
ret
]
=
(
mem_
size
/
0x18
)
*
ret
;
}
}
ax
->
mem
=
request_mem_region
(
res
->
start
,
size
,
pdev
->
name
);
if
(
!
request_mem_region
(
mem
->
start
,
mem_size
,
pdev
->
name
))
{
if
(
ax
->
mem
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"cannot reserve registers
\n
"
);
dev_err
(
&
pdev
->
dev
,
"cannot reserve registers
\n
"
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_mem
;
goto
exit_mem
;
}
}
ei_
status
.
mem
=
ioremap
(
res
->
start
,
size
);
ei_
local
->
mem
=
ioremap
(
mem
->
start
,
mem_
size
);
dev
->
base_addr
=
(
unsigned
long
)
ei_
status
.
mem
;
dev
->
base_addr
=
(
unsigned
long
)
ei_
local
->
mem
;
if
(
ei_status
.
mem
==
NULL
)
{
if
(
ei_local
->
mem
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"Cannot ioremap area (%08llx,%08llx)
\n
"
,
dev_err
(
&
pdev
->
dev
,
"Cannot ioremap area %pR
\n
"
,
mem
);
(
unsigned
long
long
)
res
->
start
,
(
unsigned
long
long
)
res
->
end
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_req
;
goto
exit_req
;
}
}
/* look for reset area */
/* look for reset area */
mem2
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
if
(
!
mem2
)
{
if
(
res
==
NULL
)
{
if
(
!
ax
->
plat
->
reg_offsets
)
{
if
(
!
ax
->
plat
->
reg_offsets
)
{
for
(
ret
=
0
;
ret
<
0x20
;
ret
++
)
for
(
ret
=
0
;
ret
<
0x20
;
ret
++
)
ax
->
reg_offsets
[
ret
]
=
(
size
/
0x20
)
*
ret
;
ax
->
reg_offsets
[
ret
]
=
(
mem_
size
/
0x20
)
*
ret
;
}
}
ax
->
map2
=
NULL
;
}
else
{
}
else
{
size
=
(
res
->
end
-
res
->
start
)
+
1
;
mem2_size
=
resource_size
(
mem2
)
;
ax
->
mem2
=
request_mem_region
(
res
->
start
,
size
,
pdev
->
name
);
if
(
!
request_mem_region
(
mem2
->
start
,
mem2_size
,
pdev
->
name
))
{
if
(
ax
->
mem2
==
NULL
)
{
dev_err
(
&
pdev
->
dev
,
"cannot reserve registers
\n
"
);
dev_err
(
&
pdev
->
dev
,
"cannot reserve registers
\n
"
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_mem1
;
goto
exit_mem1
;
}
}
ax
->
map2
=
ioremap
(
res
->
start
,
size
);
ax
->
map2
=
ioremap
(
mem2
->
start
,
mem2_
size
);
if
(
ax
->
map2
==
NULL
)
{
if
(
!
ax
->
map2
)
{
dev_err
(
&
pdev
->
dev
,
"cannot map reset register
\n
"
);
dev_err
(
&
pdev
->
dev
,
"cannot map reset register
\n
"
);
ret
=
-
ENXIO
;
ret
=
-
ENXIO
;
goto
exit_mem2
;
goto
exit_mem2
;
}
}
ei_
status
.
reg_offset
[
0x1f
]
=
ax
->
map2
-
ei_status
.
mem
;
ei_
local
->
reg_offset
[
0x1f
]
=
ax
->
map2
-
ei_local
->
mem
;
}
}
/* got resources, now initialise and register device */
/* got resources, now initialise and register device */
ret
=
ax_init_dev
(
dev
);
ret
=
ax_init_dev
(
dev
,
1
);
if
(
!
ret
)
if
(
!
ret
)
return
0
;
return
0
;
if
(
ax
->
map2
==
NULL
)
if
(
!
ax
->
map2
)
goto
exit_mem1
;
goto
exit_mem1
;
iounmap
(
ax
->
map2
);
iounmap
(
ax
->
map2
);
exit_mem2:
exit_mem2:
release_resource
(
ax
->
mem2
);
release_mem_region
(
mem2
->
start
,
mem2_size
);
kfree
(
ax
->
mem2
);
exit_mem1:
exit_mem1:
iounmap
(
ei_
status
.
mem
);
iounmap
(
ei_
local
->
mem
);
exit_req:
exit_req:
release_resource
(
ax
->
mem
);
release_mem_region
(
mem
->
start
,
mem_size
);
kfree
(
ax
->
mem
);
exit_mem:
exit_mem:
free_netdev
(
dev
);
free_netdev
(
dev
);
...
...
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