Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2894ee53
Commit
2894ee53
authored
Jul 14, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge pobox.com:/spare/repo/netdev-2.6/natsemi
into pobox.com:/spare/repo/net-drivers-2.6
parents
8e231e72
935c0036
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
823 additions
and
243 deletions
+823
-243
drivers/net/natsemi.c
drivers/net/natsemi.c
+823
-243
No files found.
drivers/net/natsemi.c
View file @
2894ee53
...
...
@@ -230,7 +230,14 @@ static int full_duplex[MAX_UNITS];
#define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32))
#define NATSEMI_EEPROM_SIZE 24
/* 12 16-bit values */
#define PKT_BUF_SZ 1536
/* Size of each temporary Rx buffer. */
/* Buffer sizes:
* The nic writes 32-bit values, even if the upper bytes of
* a 32-bit value are beyond the end of the buffer.
*/
#define NATSEMI_HEADERS 22
/* 2*mac,type,vlan,crc */
#define NATSEMI_PADDING 16
/* 2 bytes should be sufficient */
#define NATSEMI_LONGPKT 1518
/* limit for normal packets */
#define NATSEMI_RX_LIMIT 2046
/* maximum supported by hardware */
/* These identify the driver base version and may not be removed. */
static
char
version
[]
__devinitdata
=
...
...
@@ -354,6 +361,18 @@ enum pcistuff {
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
/*
* Support for fibre connections on Am79C874:
* This phy needs a special setup when connected to a fibre cable.
* http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf
*/
#define PHYID_AM79C874 0x0022561b
#define MII_MCTRL 0x15
/* mode control register */
#define MII_FX_SEL 0x0001
/* 100BASE-FX (fiber) */
#define MII_EN_SCRM 0x0004
/* enable scrambler (tp) */
/* array of board data directly indexed by pci_tbl[x].driver_data */
static
struct
{
const
char
*
name
;
...
...
@@ -457,6 +476,9 @@ enum EECtrl_bits {
EE_DataIn
=
0x01
,
EE_ChipSelect
=
0x08
,
EE_DataOut
=
0x02
,
MII_Data
=
0x10
,
MII_Write
=
0x20
,
MII_ShiftClk
=
0x40
,
};
enum
PCIBusCfg_bits
{
...
...
@@ -518,6 +540,22 @@ enum TxConfig_bits {
TxCarrierIgn
=
0x80000000
};
/*
* Tx Configuration:
* - 256 byte DMA burst length
* - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free)
* - 64 bytes initial drain threshold (i.e. begin actual transmission
* when 64 byte are in the fifo)
* - on tx underruns, increase drain threshold by 64.
* - at most use a drain threshold of 1472 bytes: The sum of the fill
* threshold and the drain threshold must be less than 2016 bytes.
*
*/
#define TX_FLTH_VAL ((512/32) << 8)
#define TX_DRTH_VAL_START (64/32)
#define TX_DRTH_VAL_INC 2
#define TX_DRTH_VAL_LIMIT (1472/32)
enum
RxConfig_bits
{
RxDrthMask
=
0x3e
,
RxMxdmaMask
=
0x700000
,
...
...
@@ -534,6 +572,7 @@ enum RxConfig_bits {
RxAcceptRunt
=
0x40000000
,
RxAcceptErr
=
0x80000000
};
#define RX_DRTH_VAL (128/8)
enum
ClkRun_bits
{
PMEEnable
=
0x100
,
...
...
@@ -588,9 +627,12 @@ enum MIntrCtrl_bits {
};
enum
PhyCtrl_bits
{
PhyAddrMask
=
0xf
,
PhyAddrMask
=
0x
1
f
,
};
#define PHY_ADDR_NONE 32
#define PHY_ADDR_INTERNAL 1
/* values we might find in the silicon revision register */
#define SRR_DP83815_C 0x0302
#define SRR_DP83815_D 0x0403
...
...
@@ -650,7 +692,9 @@ struct netdev_private {
int
oom
;
/* Do not touch the nic registers */
int
hands_off
;
/* These values are keep track of the transceiver/media in use */
/* external phy that is used: only valid if dev->if_port != PORT_TP */
int
mii
;
int
phy_addr_external
;
unsigned
int
full_duplex
;
/* Rx filter */
u32
cur_rx_mode
;
...
...
@@ -663,6 +707,10 @@ struct netdev_private {
u32
srr
;
/* expected DSPCFG value */
u16
dspcfg
;
/* parms saved in ethtool format */
u16
speed
;
/* The forced speed, 10Mb, 100Mb, gigabit */
u8
duplex
;
/* Duplex, half or full */
u8
autoneg
;
/* Autonegotiation enabled */
/* MII transceiver section */
u16
advertising
;
unsigned
int
iosize
;
...
...
@@ -670,9 +718,14 @@ struct netdev_private {
u32
msg_enable
;
};
static
void
move_int_phy
(
struct
net_device
*
dev
,
int
addr
);
static
int
eeprom_read
(
long
ioaddr
,
int
location
);
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
);
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
,
u16
data
);
static
int
mdio_read
(
struct
net_device
*
dev
,
int
reg
);
static
void
mdio_write
(
struct
net_device
*
dev
,
int
reg
,
u16
data
);
static
void
init_phy_fixup
(
struct
net_device
*
dev
);
static
int
miiport_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
);
static
void
miiport_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
,
u16
data
);
static
int
find_mii
(
struct
net_device
*
dev
);
static
void
natsemi_reset
(
struct
net_device
*
dev
);
static
void
natsemi_reload_eeprom
(
struct
net_device
*
dev
);
static
void
natsemi_stop_rxtx
(
struct
net_device
*
dev
);
...
...
@@ -696,6 +749,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *reg
static
void
netdev_error
(
struct
net_device
*
dev
,
int
intr_status
);
static
void
netdev_rx
(
struct
net_device
*
dev
);
static
void
netdev_tx_done
(
struct
net_device
*
dev
);
static
int
natsemi_change_mtu
(
struct
net_device
*
dev
,
int
new_mtu
);
static
void
__set_rx_mode
(
struct
net_device
*
dev
);
static
void
set_rx_mode
(
struct
net_device
*
dev
);
static
void
__get_stats
(
struct
net_device
*
dev
);
...
...
@@ -712,6 +766,29 @@ static int netdev_close(struct net_device *dev);
static
int
netdev_get_regs
(
struct
net_device
*
dev
,
u8
*
buf
);
static
int
netdev_get_eeprom
(
struct
net_device
*
dev
,
u8
*
buf
);
static
void
move_int_phy
(
struct
net_device
*
dev
,
int
addr
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
int
target
=
31
;
/*
* The internal phy is visible on the external mii bus. Therefore we must
* move it away before we can send commands to an external phy.
* There are two addresses we must avoid:
* - the address on the external phy that is used for transmission.
* - the address that we want to access. User space can access phys
* on the mii bus with SIOCGMIIREG/SIOCSMIIREG, independant from the
* phy that is used for transmission.
*/
if
(
target
==
addr
)
target
--
;
if
(
target
==
np
->
phy_addr_external
)
target
--
;
writew
(
target
,
dev
->
base_addr
+
PhyCtrl
);
readw
(
dev
->
base_addr
+
PhyCtrl
);
udelay
(
1
);
}
static
int
__devinit
natsemi_probe1
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
...
...
@@ -782,7 +859,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev
->
base_addr
=
ioaddr
;
dev
->
irq
=
irq
;
np
=
dev
->
priv
;
np
=
netdev_priv
(
dev
)
;
np
->
pci_dev
=
pdev
;
pci_set_drvdata
(
pdev
,
dev
);
...
...
@@ -791,10 +868,32 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np
->
msg_enable
=
(
debug
>=
0
)
?
(
1
<<
debug
)
-
1
:
NATSEMI_DEF_MSG
;
np
->
hands_off
=
0
;
/* Initial port:
* - If the nic was configured to use an external phy and if find_mii
* finds a phy: use external port, first phy that replies.
* - Otherwise: internal port.
* Note that the phy address for the internal phy doesn't matter:
* The address would be used to access a phy over the mii bus, but
* the internal phy is accessed through mapped registers.
*/
if
(
readl
(
dev
->
base_addr
+
ChipConfig
)
&
CfgExtPhy
)
dev
->
if_port
=
PORT_MII
;
else
dev
->
if_port
=
PORT_TP
;
/* Reset the chip to erase previous misconfiguration. */
natsemi_reload_eeprom
(
dev
);
natsemi_reset
(
dev
);
if
(
dev
->
if_port
!=
PORT_TP
)
{
np
->
phy_addr_external
=
find_mii
(
dev
);
if
(
np
->
phy_addr_external
==
PHY_ADDR_NONE
)
{
dev
->
if_port
=
PORT_TP
;
np
->
phy_addr_external
=
PHY_ADDR_INTERNAL
;
}
}
else
{
np
->
phy_addr_external
=
PHY_ADDR_INTERNAL
;
}
option
=
find_cnt
<
MAX_UNITS
?
options
[
find_cnt
]
:
0
;
if
(
dev
->
mem_start
)
option
=
dev
->
mem_start
;
...
...
@@ -805,8 +904,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np
->
full_duplex
=
1
;
if
(
option
&
15
)
printk
(
KERN_INFO
"%s: ignoring user supplied media type %d"
,
dev
->
name
,
option
&
15
);
"
natsemi
%s: ignoring user supplied media type %d"
,
pci_name
(
np
->
pci_dev
)
,
option
&
15
);
}
if
(
find_cnt
<
MAX_UNITS
&&
full_duplex
[
find_cnt
])
np
->
full_duplex
=
1
;
...
...
@@ -817,6 +916,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev
->
stop
=
&
netdev_close
;
dev
->
get_stats
=
&
get_stats
;
dev
->
set_multicast_list
=
&
set_rx_mode
;
dev
->
change_mtu
=
&
natsemi_change_mtu
;
dev
->
do_ioctl
=
&
netdev_ioctl
;
dev
->
tx_timeout
=
&
tx_timeout
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
...
...
@@ -824,45 +924,57 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if
(
mtu
)
dev
->
mtu
=
mtu
;
i
=
register_netdev
(
dev
);
if
(
i
)
goto
err_register_netdev
;
netif_carrier_off
(
dev
);
if
(
netif_msg_drv
(
np
))
{
printk
(
KERN_INFO
"%s: %s at %#08lx, "
,
dev
->
name
,
natsemi_pci_info
[
chip_idx
].
name
,
ioaddr
);
for
(
i
=
0
;
i
<
ETH_ALEN
-
1
;
i
++
)
printk
(
"%02x:"
,
dev
->
dev_addr
[
i
]);
printk
(
"%02x, IRQ %d.
\n
"
,
dev
->
dev_addr
[
i
],
irq
);
}
/* get the initial settings from hardware */
tmp
=
mdio_read
(
dev
,
MII_BMCR
);
np
->
speed
=
(
tmp
&
BMCR_SPEED100
)
?
SPEED_100
:
SPEED_10
;
np
->
duplex
=
(
tmp
&
BMCR_FULLDPLX
)
?
DUPLEX_FULL
:
DUPLEX_HALF
;
np
->
autoneg
=
(
tmp
&
BMCR_ANENABLE
)
?
AUTONEG_ENABLE
:
AUTONEG_DISABLE
;
np
->
advertising
=
mdio_read
(
dev
,
MII_ADVERTISE
);
np
->
advertising
=
mdio_read
(
dev
,
1
,
MII_ADVERTISE
);
if
((
readl
(
ioaddr
+
ChipConfig
)
&
0xe000
)
!=
0xe000
if
((
np
->
advertising
&
ADVERTISE_ALL
)
!=
ADVERTISE_ALL
&&
netif_msg_probe
(
np
))
{
u32
chip_config
=
readl
(
ioaddr
+
ChipConfig
);
printk
(
KERN_INFO
"%s: Transceiver default autonegotiation %s "
printk
(
KERN_INFO
"natsemi %s: Transceiver default autonegotiation %s "
"10%s %s duplex.
\n
"
,
dev
->
name
,
chip_config
&
CfgAnegEnable
?
pci_name
(
np
->
pci_dev
)
,
(
mdio_read
(
dev
,
MII_BMCR
)
&
BMCR_ANENABLE
)
?
"enabled, advertise"
:
"disabled, force"
,
chip_config
&
CfgAneg100
?
"0"
:
""
,
chip_config
&
CfgAnegFull
?
"full"
:
"half"
);
(
np
->
advertising
&
(
ADVERTISE_100FULL
|
ADVERTISE_100HALF
))
?
"0"
:
""
,
(
np
->
advertising
&
(
ADVERTISE_100FULL
|
ADVERTISE_10FULL
))
?
"full"
:
"half"
);
}
if
(
netif_msg_probe
(
np
))
printk
(
KERN_INFO
"%s: Transceiver status %#04x advertising %#04x.
\n
"
,
dev
->
name
,
mdio_read
(
dev
,
1
,
MII_BMSR
),
"
natsemi
%s: Transceiver status %#04x advertising %#04x.
\n
"
,
pci_name
(
np
->
pci_dev
),
mdio_read
(
dev
,
MII_BMSR
),
np
->
advertising
);
/* save the silicon revision for later querying */
np
->
srr
=
readl
(
ioaddr
+
SiliconRev
);
if
(
netif_msg_hw
(
np
))
printk
(
KERN_INFO
"%s: silicon revision %#04x.
\n
"
,
dev
->
name
,
np
->
srr
);
printk
(
KERN_INFO
"
natsemi
%s: silicon revision %#04x.
\n
"
,
pci_name
(
np
->
pci_dev
)
,
np
->
srr
);
i
=
register_netdev
(
dev
);
if
(
i
)
goto
err_register_netdev
;
if
(
netif_msg_drv
(
np
))
{
printk
(
KERN_INFO
"natsemi %s: %s at %#08lx (%s), "
,
dev
->
name
,
natsemi_pci_info
[
chip_idx
].
name
,
ioaddr
,
pci_name
(
np
->
pci_dev
));
for
(
i
=
0
;
i
<
ETH_ALEN
-
1
;
i
++
)
printk
(
"%02x:"
,
dev
->
dev_addr
[
i
]);
printk
(
"%02x, IRQ %d"
,
dev
->
dev_addr
[
i
],
irq
);
if
(
dev
->
if_port
==
PORT_TP
)
printk
(
", port TP.
\n
"
);
else
printk
(
", port MII, phy ad %d.
\n
"
,
np
->
phy_addr_external
);
}
return
0
;
err_register_netdev:
...
...
@@ -933,25 +1045,335 @@ static int eeprom_read(long addr, int location)
/* MII transceiver control section.
* The 83815 series has an internal transceiver, and we present the
* management registers as if they were MII connected. */
* internal management registers as if they were MII connected.
* External Phy registers are referenced through the MII interface.
*/
static
int
mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
)
/* clock transitions >= 20ns (25MHz)
* One readl should be good to PCI @ 100MHz
*/
#define mii_delay(dev) readl(dev->base_addr + EECtrl)
static
int
mii_getbit
(
struct
net_device
*
dev
)
{
int
data
;
writel
(
MII_ShiftClk
,
dev
->
base_addr
+
EECtrl
);
data
=
readl
(
dev
->
base_addr
+
EECtrl
);
writel
(
0
,
dev
->
base_addr
+
EECtrl
);
mii_delay
(
dev
);
return
(
data
&
MII_Data
)
?
1
:
0
;
}
static
void
mii_send_bits
(
struct
net_device
*
dev
,
u32
data
,
int
len
)
{
u32
i
;
for
(
i
=
(
1
<<
(
len
-
1
));
i
;
i
>>=
1
)
{
u32
mdio_val
=
MII_Write
|
((
data
&
i
)
?
MII_Data
:
0
);
writel
(
mdio_val
,
dev
->
base_addr
+
EECtrl
);
mii_delay
(
dev
);
writel
(
mdio_val
|
MII_ShiftClk
,
dev
->
base_addr
+
EECtrl
);
mii_delay
(
dev
);
}
writel
(
0
,
dev
->
base_addr
+
EECtrl
);
mii_delay
(
dev
);
}
static
int
miiport_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
)
{
u32
cmd
;
int
i
;
u32
retval
=
0
;
/* Ensure sync */
mii_send_bits
(
dev
,
0xffffffff
,
32
);
/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
/* ST,OP = 0110'b for read operation */
cmd
=
(
0x06
<<
10
)
|
(
phy_id
<<
5
)
|
reg
;
mii_send_bits
(
dev
,
cmd
,
14
);
/* Turnaround */
if
(
mii_getbit
(
dev
))
return
0
;
/* Read data */
for
(
i
=
0
;
i
<
16
;
i
++
)
{
retval
<<=
1
;
retval
|=
mii_getbit
(
dev
);
}
/* End cycle */
mii_getbit
(
dev
);
return
retval
;
}
static
void
miiport_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
,
u16
data
)
{
if
(
phy_id
==
1
&&
reg
<
32
)
return
readl
(
dev
->
base_addr
+
BasicControl
+
(
reg
<<
2
))
&
0xffff
;
u32
cmd
;
/* Ensure sync */
mii_send_bits
(
dev
,
0xffffffff
,
32
);
/* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */
/* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x5002 for write */
cmd
=
(
0x5002
<<
16
)
|
(
phy_id
<<
23
)
|
(
reg
<<
18
)
|
data
;
mii_send_bits
(
dev
,
cmd
,
32
);
/* End cycle */
mii_getbit
(
dev
);
}
static
int
mdio_read
(
struct
net_device
*
dev
,
int
reg
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
/* The 83815 series has two ports:
* - an internal transceiver
* - an external mii bus
*/
if
(
dev
->
if_port
==
PORT_TP
)
return
readw
(
dev
->
base_addr
+
BasicControl
+
(
reg
<<
2
));
else
return
0xffff
;
return
miiport_read
(
dev
,
np
->
phy_addr_external
,
reg
)
;
}
static
void
mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
reg
,
u16
data
)
static
void
mdio_write
(
struct
net_device
*
dev
,
int
reg
,
u16
data
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
if
(
phy_id
==
1
&&
reg
<
32
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
/* The 83815 series has an internal transceiver; handle separately */
if
(
dev
->
if_port
==
PORT_TP
)
writew
(
data
,
dev
->
base_addr
+
BasicControl
+
(
reg
<<
2
));
switch
(
reg
)
{
case
MII_ADVERTISE
:
np
->
advertising
=
data
;
break
;
else
miiport_write
(
dev
,
np
->
phy_addr_external
,
reg
,
data
);
}
static
void
init_phy_fixup
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
long
ioaddr
=
dev
->
base_addr
;
int
i
;
u32
cfg
;
u16
tmp
;
/* restore stuff lost when power was out */
tmp
=
mdio_read
(
dev
,
MII_BMCR
);
if
(
np
->
autoneg
==
AUTONEG_ENABLE
)
{
/* renegotiate if something changed */
if
((
tmp
&
BMCR_ANENABLE
)
==
0
||
np
->
advertising
!=
mdio_read
(
dev
,
MII_ADVERTISE
))
{
/* turn on autonegotiation and force negotiation */
tmp
|=
(
BMCR_ANENABLE
|
BMCR_ANRESTART
);
mdio_write
(
dev
,
MII_ADVERTISE
,
np
->
advertising
);
}
}
else
{
/* turn off auto negotiation, set speed and duplexity */
tmp
&=
~
(
BMCR_ANENABLE
|
BMCR_SPEED100
|
BMCR_FULLDPLX
);
if
(
np
->
speed
==
SPEED_100
)
tmp
|=
BMCR_SPEED100
;
if
(
np
->
duplex
==
DUPLEX_FULL
)
tmp
|=
BMCR_FULLDPLX
;
/*
* Note: there is no good way to inform the link partner
* that our capabilities changed. The user has to unplug
* and replug the network cable after some changes, e.g.
* after switching from 10HD, autoneg off to 100 HD,
* autoneg off.
*/
}
mdio_write
(
dev
,
MII_BMCR
,
tmp
);
readl
(
dev
->
base_addr
+
ChipConfig
);
udelay
(
1
);
/* find out what phy this is */
np
->
mii
=
(
mdio_read
(
dev
,
MII_PHYSID1
)
<<
16
)
+
mdio_read
(
dev
,
MII_PHYSID2
);
/* handle external phys here */
switch
(
np
->
mii
)
{
case
PHYID_AM79C874
:
/* phy specific configuration for fibre/tp operation */
tmp
=
mdio_read
(
dev
,
MII_MCTRL
);
tmp
&=
~
(
MII_FX_SEL
|
MII_EN_SCRM
);
if
(
dev
->
if_port
==
PORT_FIBRE
)
tmp
|=
MII_FX_SEL
;
else
tmp
|=
MII_EN_SCRM
;
mdio_write
(
dev
,
MII_MCTRL
,
tmp
);
break
;
default:
break
;
}
cfg
=
readl
(
dev
->
base_addr
+
ChipConfig
);
if
(
cfg
&
CfgExtPhy
)
return
;
/* On page 78 of the spec, they recommend some settings for "optimum
performance" to be done in sequence. These settings optimize some
of the 100Mbit autodetection circuitry. They say we only want to
do this for rev C of the chip, but engineers at NSC (Bradley
Kennedy) recommends always setting them. If you don't, you get
errors on some autonegotiations that make the device unusable.
It seems that the DSP needs a few usec to reinitialize after
the start of the phy. Just retry writing these values until they
stick.
*/
for
(
i
=
0
;
i
<
NATSEMI_HW_TIMEOUT
;
i
++
)
{
int
dspcfg
;
writew
(
1
,
ioaddr
+
PGSEL
);
writew
(
PMDCSR_VAL
,
ioaddr
+
PMDCSR
);
writew
(
TSTDAT_VAL
,
ioaddr
+
TSTDAT
);
np
->
dspcfg
=
DSPCFG_VAL
;
writew
(
np
->
dspcfg
,
ioaddr
+
DSPCFG
);
writew
(
SDCFG_VAL
,
ioaddr
+
SDCFG
);
writew
(
0
,
ioaddr
+
PGSEL
);
readl
(
ioaddr
+
ChipConfig
);
udelay
(
10
);
writew
(
1
,
ioaddr
+
PGSEL
);
dspcfg
=
readw
(
ioaddr
+
DSPCFG
);
writew
(
0
,
ioaddr
+
PGSEL
);
if
(
np
->
dspcfg
==
dspcfg
)
break
;
}
if
(
netif_msg_link
(
np
))
{
if
(
i
==
NATSEMI_HW_TIMEOUT
)
{
printk
(
KERN_INFO
"%s: DSPCFG mismatch after retrying for %d usec.
\n
"
,
dev
->
name
,
i
*
10
);
}
else
{
printk
(
KERN_INFO
"%s: DSPCFG accepted after %d usec.
\n
"
,
dev
->
name
,
i
*
10
);
}
}
/*
* Enable PHY Specific event based interrupts. Link state change
* and Auto-Negotiation Completion are among the affected.
* Read the intr status to clear it (needed for wake events).
*/
readw
(
ioaddr
+
MIntrStatus
);
writew
(
MICRIntEn
,
ioaddr
+
MIntrCtrl
);
}
static
int
switch_port_external
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
u32
cfg
;
cfg
=
readl
(
dev
->
base_addr
+
ChipConfig
);
if
(
cfg
&
CfgExtPhy
)
return
0
;
if
(
netif_msg_link
(
np
))
{
printk
(
KERN_INFO
"%s: switching to external transceiver.
\n
"
,
dev
->
name
);
}
/* 1) switch back to external phy */
writel
(
cfg
|
(
CfgExtPhy
|
CfgPhyDis
),
dev
->
base_addr
+
ChipConfig
);
readl
(
dev
->
base_addr
+
ChipConfig
);
udelay
(
1
);
/* 2) reset the external phy: */
/* resetting the external PHY has been known to cause a hub supplying
* power over Ethernet to kill the power. We don't want to kill
* power to this computer, so we avoid resetting the phy.
*/
/* 3) reinit the phy fixup, it got lost during power down. */
move_int_phy
(
dev
,
np
->
phy_addr_external
);
init_phy_fixup
(
dev
);
return
1
;
}
static
int
switch_port_internal
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
int
i
;
u32
cfg
;
u16
bmcr
;
cfg
=
readl
(
dev
->
base_addr
+
ChipConfig
);
if
(
!
(
cfg
&
CfgExtPhy
))
return
0
;
if
(
netif_msg_link
(
np
))
{
printk
(
KERN_INFO
"%s: switching to internal transceiver.
\n
"
,
dev
->
name
);
}
/* 1) switch back to internal phy: */
cfg
=
cfg
&
~
(
CfgExtPhy
|
CfgPhyDis
);
writel
(
cfg
,
dev
->
base_addr
+
ChipConfig
);
readl
(
dev
->
base_addr
+
ChipConfig
);
udelay
(
1
);
/* 2) reset the internal phy: */
bmcr
=
readw
(
dev
->
base_addr
+
BasicControl
+
(
MII_BMCR
<<
2
));
writel
(
bmcr
|
BMCR_RESET
,
dev
->
base_addr
+
BasicControl
+
(
MII_BMCR
<<
2
));
readl
(
dev
->
base_addr
+
ChipConfig
);
udelay
(
10
);
for
(
i
=
0
;
i
<
NATSEMI_HW_TIMEOUT
;
i
++
)
{
bmcr
=
readw
(
dev
->
base_addr
+
BasicControl
+
(
MII_BMCR
<<
2
));
if
(
!
(
bmcr
&
BMCR_RESET
))
break
;
udelay
(
10
);
}
if
(
i
==
NATSEMI_HW_TIMEOUT
&&
netif_msg_link
(
np
))
{
printk
(
KERN_INFO
"%s: phy reset did not complete in %d usec.
\n
"
,
dev
->
name
,
i
*
10
);
}
/* 3) reinit the phy fixup, it got lost during power down. */
init_phy_fixup
(
dev
);
return
1
;
}
/* Scan for a PHY on the external mii bus.
* There are two tricky points:
* - Do not scan while the internal phy is enabled. The internal phy will
* crash: e.g. reads from the DSPCFG register will return odd values and
* the nasty random phy reset code will reset the nic every few seconds.
* - The internal phy must be moved around, an external phy could
* have the same address as the internal phy.
*/
static
int
find_mii
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
int
tmp
;
int
i
;
int
did_switch
;
/* Switch to external phy */
did_switch
=
switch_port_external
(
dev
);
/* Scan the possible phy addresses:
*
* PHY address 0 means that the phy is in isolate mode. Not yet
* supported due to lack of test hardware. User space should
* handle it through ethtool.
*/
for
(
i
=
1
;
i
<=
31
;
i
++
)
{
move_int_phy
(
dev
,
i
);
tmp
=
miiport_read
(
dev
,
i
,
MII_BMSR
);
if
(
tmp
!=
0xffff
&&
tmp
!=
0x0000
)
{
/* found something! */
np
->
mii
=
(
mdio_read
(
dev
,
MII_PHYSID1
)
<<
16
)
+
mdio_read
(
dev
,
MII_PHYSID2
);
if
(
netif_msg_probe
(
np
))
{
printk
(
KERN_INFO
"natsemi %s: found external phy %08x at address %d.
\n
"
,
pci_name
(
np
->
pci_dev
),
np
->
mii
,
i
);
}
break
;
}
}
/* And switch back to internal phy: */
if
(
did_switch
)
switch_port_internal
(
dev
);
return
i
;
}
/* CFG bits [13:16] [18:23] */
...
...
@@ -969,7 +1391,7 @@ static void natsemi_reset(struct net_device *dev)
u32
rfcr
;
u16
pmatch
[
3
];
u16
sopass
[
3
];
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
/*
* Resetting the chip causes some registers to be lost.
...
...
@@ -1013,6 +1435,11 @@ static void natsemi_reset(struct net_device *dev)
/* restore CFG */
cfg
|=
readl
(
dev
->
base_addr
+
ChipConfig
)
&
~
CFG_RESET_SAVE
;
/* turn on external phy if it was selected */
if
(
dev
->
if_port
==
PORT_TP
)
cfg
&=
~
(
CfgExtPhy
|
CfgPhyDis
);
else
cfg
|=
(
CfgExtPhy
|
CfgPhyDis
);
writel
(
cfg
,
dev
->
base_addr
+
ChipConfig
);
/* restore WCSR */
wcsr
|=
readl
(
dev
->
base_addr
+
WOLCmd
)
&
~
WCSR_RESET_SAVE
;
...
...
@@ -1034,7 +1461,7 @@ static void natsemi_reset(struct net_device *dev)
static
void
natsemi_reload_eeprom
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
i
;
writel
(
EepromReload
,
dev
->
base_addr
+
PCIBusCfg
);
...
...
@@ -1044,18 +1471,18 @@ static void natsemi_reload_eeprom(struct net_device *dev)
break
;
}
if
(
i
==
NATSEMI_HW_TIMEOUT
)
{
printk
(
KERN_WARNING
"%s: EEPROM did not reload in %d usec.
\n
"
,
dev
->
name
,
i
*
50
);
printk
(
KERN_WARNING
"
natsemi
%s: EEPROM did not reload in %d usec.
\n
"
,
pci_name
(
np
->
pci_dev
)
,
i
*
50
);
}
else
if
(
netif_msg_hw
(
np
))
{
printk
(
KERN_DEBUG
"%s: EEPROM reloaded in %d usec.
\n
"
,
dev
->
name
,
i
*
50
);
printk
(
KERN_DEBUG
"
natsemi
%s: EEPROM reloaded in %d usec.
\n
"
,
pci_name
(
np
->
pci_dev
)
,
i
*
50
);
}
}
static
void
natsemi_stop_rxtx
(
struct
net_device
*
dev
)
{
long
ioaddr
=
dev
->
base_addr
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
i
;
writel
(
RxOff
|
TxOff
,
ioaddr
+
ChipCmd
);
...
...
@@ -1075,7 +1502,7 @@ static void natsemi_stop_rxtx(struct net_device *dev)
static
int
netdev_open
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
int
i
;
...
...
@@ -1124,7 +1551,10 @@ static int netdev_open(struct net_device *dev)
static
void
do_cable_magic
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
if
(
dev
->
if_port
!=
PORT_TP
)
return
;
if
(
np
->
srr
>=
SRR_DP83816_A5
)
return
;
...
...
@@ -1149,7 +1579,7 @@ static void do_cable_magic(struct net_device *dev)
* (these values all come from National)
*/
if
(
!
(
data
&
0x80
)
||
((
data
>=
0xd8
)
&&
(
data
<=
0xff
)))
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
/* the bug has been triggered - fix the coefficient */
writew
(
TSTDAT_FIXED
,
dev
->
base_addr
+
TSTDAT
);
...
...
@@ -1165,7 +1595,10 @@ static void do_cable_magic(struct net_device *dev)
static
void
undo_cable_magic
(
struct
net_device
*
dev
)
{
u16
data
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
if
(
dev
->
if_port
!=
PORT_TP
)
return
;
if
(
np
->
srr
>=
SRR_DP83816_A5
)
return
;
...
...
@@ -1180,12 +1613,19 @@ static void undo_cable_magic(struct net_device *dev)
static
void
check_link
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
int
duplex
;
int
chipcfg
=
readl
(
ioaddr
+
ChipConfig
);
u16
bmsr
;
/* The link status field is latched: it remains low after a temporary
* link failure until it's read. We need the current link status,
* thus read twice.
*/
mdio_read
(
dev
,
MII_BMSR
);
bmsr
=
mdio_read
(
dev
,
MII_BMSR
);
if
(
!
(
chipcfg
&
CfgLink
))
{
if
(
!
(
bmsr
&
BMSR_LSTATUS
))
{
if
(
netif_carrier_ok
(
dev
))
{
if
(
netif_msg_link
(
np
))
printk
(
KERN_NOTICE
"%s: link down.
\n
"
,
...
...
@@ -1202,7 +1642,16 @@ static void check_link(struct net_device *dev)
do_cable_magic
(
dev
);
}
duplex
=
np
->
full_duplex
||
(
chipcfg
&
CfgFullDuplex
?
1
:
0
);
duplex
=
np
->
full_duplex
;
if
(
!
duplex
)
{
if
(
bmsr
&
BMSR_ANEGCOMPLETE
)
{
int
tmp
=
mii_nway_result
(
np
->
advertising
&
mdio_read
(
dev
,
MII_LPA
));
if
(
tmp
==
LPA_100FULL
||
tmp
==
LPA_10FULL
)
duplex
=
1
;
}
else
if
(
mdio_read
(
dev
,
MII_BMCR
)
&
BMCR_FULLDPLX
)
duplex
=
1
;
}
/* if duplex is set then bit 28 must be set, too */
if
(
duplex
^
!!
(
np
->
rx_config
&
RxAcceptTx
))
{
...
...
@@ -1225,42 +1674,10 @@ static void check_link(struct net_device *dev)
static
void
init_registers
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
int
i
;
for
(
i
=
0
;
i
<
NATSEMI_HW_TIMEOUT
;
i
++
)
{
if
(
readl
(
dev
->
base_addr
+
ChipConfig
)
&
CfgAnegDone
)
break
;
udelay
(
10
);
}
if
(
i
==
NATSEMI_HW_TIMEOUT
&&
netif_msg_link
(
np
))
{
printk
(
KERN_INFO
"%s: autonegotiation did not complete in %d usec.
\n
"
,
dev
->
name
,
i
*
10
);
}
/* On page 78 of the spec, they recommend some settings for "optimum
performance" to be done in sequence. These settings optimize some
of the 100Mbit autodetection circuitry. They say we only want to
do this for rev C of the chip, but engineers at NSC (Bradley
Kennedy) recommends always setting them. If you don't, you get
errors on some autonegotiations that make the device unusable.
*/
writew
(
1
,
ioaddr
+
PGSEL
);
writew
(
PMDCSR_VAL
,
ioaddr
+
PMDCSR
);
writew
(
TSTDAT_VAL
,
ioaddr
+
TSTDAT
);
writew
(
DSPCFG_VAL
,
ioaddr
+
DSPCFG
);
writew
(
SDCFG_VAL
,
ioaddr
+
SDCFG
);
writew
(
0
,
ioaddr
+
PGSEL
);
np
->
dspcfg
=
DSPCFG_VAL
;
/* Enable PHY Specific event based interrupts. Link state change
and Auto-Negotiation Completion are among the affected.
Read the intr status to clear it (needed for wake events).
*/
readw
(
ioaddr
+
MIntrStatus
);
writew
(
MICRIntEn
,
ioaddr
+
MIntrCtrl
);
init_phy_fixup
(
dev
);
/* clear any interrupts that are pending, such as wake events */
readl
(
ioaddr
+
IntrStatus
);
...
...
@@ -1283,13 +1700,18 @@ static void init_registers(struct net_device *dev)
* ECRETRY=1
* ATP=1
*/
np
->
tx_config
=
TxAutoPad
|
TxCollRetry
|
TxMxdma_256
|
(
0x1002
);
np
->
tx_config
=
TxAutoPad
|
TxCollRetry
|
TxMxdma_256
|
TX_FLTH_VAL
|
TX_DRTH_VAL_START
;
writel
(
np
->
tx_config
,
ioaddr
+
TxConfig
);
/* DRTH 0x10: start copying to memory if 128 bytes are in the fifo
* MXDMA 0: up to 256 byte bursts
*/
np
->
rx_config
=
RxMxdma_256
|
0x20
;
np
->
rx_config
=
RxMxdma_256
|
RX_DRTH_VAL
;
/* if receive ring now has bigger buffers than normal, enable jumbo */
if
(
np
->
rx_buf_sz
>
NATSEMI_LONGPKT
)
np
->
rx_config
|=
RxAcceptLong
;
writel
(
np
->
rx_config
,
ioaddr
+
RxConfig
);
/* Disable PME:
...
...
@@ -1331,10 +1753,8 @@ static void init_registers(struct net_device *dev)
static
void
netdev_timer
(
unsigned
long
data
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
data
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
next_tick
=
5
*
HZ
;
long
ioaddr
=
dev
->
base_addr
;
u16
dspcfg
;
if
(
netif_msg_timer
(
np
))
{
/* DO NOT read the IntrStatus register,
...
...
@@ -1344,33 +1764,41 @@ static void netdev_timer(unsigned long data)
dev
->
name
);
}
spin_lock_irq
(
&
np
->
lock
);
if
(
dev
->
if_port
==
PORT_TP
)
{
long
ioaddr
=
dev
->
base_addr
;
u16
dspcfg
;
/* check for a nasty random phy-reset - use dspcfg as a flag */
writew
(
1
,
ioaddr
+
PGSEL
);
dspcfg
=
readw
(
ioaddr
+
DSPCFG
);
writew
(
0
,
ioaddr
+
PGSEL
);
if
(
dspcfg
!=
np
->
dspcfg
)
{
if
(
!
netif_queue_stopped
(
dev
))
{
spin_unlock_irq
(
&
np
->
lock
);
if
(
netif_msg_hw
(
np
))
printk
(
KERN_NOTICE
"%s: possible phy reset: "
"re-initializing
\n
"
,
dev
->
name
);
disable_irq
(
dev
->
irq
);
spin_lock_irq
(
&
np
->
lock
);
natsemi_stop_rxtx
(
dev
);
dump_ring
(
dev
);
reinit_ring
(
dev
);
init_registers
(
dev
);
spin_unlock_irq
(
&
np
->
lock
);
enable_irq
(
dev
->
irq
);
spin_lock_irq
(
&
np
->
lock
);
/* check for a nasty random phy-reset - use dspcfg as a flag */
writew
(
1
,
ioaddr
+
PGSEL
);
dspcfg
=
readw
(
ioaddr
+
DSPCFG
);
writew
(
0
,
ioaddr
+
PGSEL
);
if
(
dspcfg
!=
np
->
dspcfg
)
{
if
(
!
netif_queue_stopped
(
dev
))
{
spin_unlock_irq
(
&
np
->
lock
);
if
(
netif_msg_hw
(
np
))
printk
(
KERN_NOTICE
"%s: possible phy reset: "
"re-initializing
\n
"
,
dev
->
name
);
disable_irq
(
dev
->
irq
);
spin_lock_irq
(
&
np
->
lock
);
natsemi_stop_rxtx
(
dev
);
dump_ring
(
dev
);
reinit_ring
(
dev
);
init_registers
(
dev
);
spin_unlock_irq
(
&
np
->
lock
);
enable_irq
(
dev
->
irq
);
}
else
{
/* hurry back */
next_tick
=
HZ
;
spin_unlock_irq
(
&
np
->
lock
);
}
}
else
{
/*
hurry back
*/
next_tick
=
HZ
;
/*
init_registers() calls check_link() for the above case
*/
check_link
(
dev
)
;
spin_unlock_irq
(
&
np
->
lock
);
}
}
else
{
/* init_registers() calls check_link() for the above case */
spin_lock_irq
(
&
np
->
lock
);
check_link
(
dev
);
spin_unlock_irq
(
&
np
->
lock
);
}
...
...
@@ -1390,7 +1818,7 @@ static void netdev_timer(unsigned long data)
static
void
dump_ring
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
if
(
netif_msg_pktdata
(
np
))
{
int
i
;
...
...
@@ -1413,7 +1841,7 @@ static void dump_ring(struct net_device *dev)
static
void
tx_timeout
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
disable_irq
(
dev
->
irq
);
...
...
@@ -1444,7 +1872,7 @@ static void tx_timeout(struct net_device *dev)
static
int
alloc_ring
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
np
->
rx_ring
=
pci_alloc_consistent
(
np
->
pci_dev
,
sizeof
(
struct
netdev_desc
)
*
(
RX_RING_SIZE
+
TX_RING_SIZE
),
&
np
->
ring_dma
);
...
...
@@ -1456,14 +1884,14 @@ static int alloc_ring(struct net_device *dev)
static
void
refill_rx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
/* Refill the Rx ring buffers. */
for
(;
np
->
cur_rx
-
np
->
dirty_rx
>
0
;
np
->
dirty_rx
++
)
{
struct
sk_buff
*
skb
;
int
entry
=
np
->
dirty_rx
%
RX_RING_SIZE
;
if
(
np
->
rx_skbuff
[
entry
]
==
NULL
)
{
unsigned
int
buflen
=
np
->
rx_buf_sz
+
RX_OFFSET
;
unsigned
int
buflen
=
np
->
rx_buf_sz
+
NATSEMI_PADDING
;
skb
=
dev_alloc_skb
(
buflen
);
np
->
rx_skbuff
[
entry
]
=
skb
;
if
(
skb
==
NULL
)
...
...
@@ -1482,10 +1910,19 @@ static void refill_rx(struct net_device *dev)
}
}
static
void
set_bufsize
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
if
(
dev
->
mtu
<=
ETH_DATA_LEN
)
np
->
rx_buf_sz
=
ETH_DATA_LEN
+
NATSEMI_HEADERS
;
else
np
->
rx_buf_sz
=
dev
->
mtu
+
NATSEMI_HEADERS
;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static
void
init_ring
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
i
;
/* 1) TX ring */
...
...
@@ -1501,8 +1938,9 @@ static void init_ring(struct net_device *dev)
/* 2) RX ring */
np
->
dirty_rx
=
0
;
np
->
cur_rx
=
RX_RING_SIZE
;
np
->
rx_buf_sz
=
(
dev
->
mtu
<=
1500
?
PKT_BUF_SZ
:
dev
->
mtu
+
32
);
np
->
oom
=
0
;
set_bufsize
(
dev
);
np
->
rx_head_desc
=
&
np
->
rx_ring
[
0
];
/* Please be carefull before changing this loop - at least gcc-2.95.1
...
...
@@ -1522,7 +1960,7 @@ static void init_ring(struct net_device *dev)
static
void
drain_tx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
i
;
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
{
...
...
@@ -1537,10 +1975,10 @@ static void drain_tx(struct net_device *dev)
}
}
static
void
drain_r
ing
(
struct
net_device
*
dev
)
static
void
drain_r
x
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
unsigned
int
buflen
=
np
->
rx_buf_sz
+
RX_OFFSET
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
unsigned
int
buflen
=
np
->
rx_buf_sz
;
int
i
;
/* Free all the skbuffs in the Rx queue. */
...
...
@@ -1555,28 +1993,27 @@ static void drain_ring(struct net_device *dev)
}
np
->
rx_skbuff
[
i
]
=
NULL
;
}
}
static
void
drain_ring
(
struct
net_device
*
dev
)
{
drain_rx
(
dev
);
drain_tx
(
dev
);
}
static
void
free_ring
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
pci_free_consistent
(
np
->
pci_dev
,
sizeof
(
struct
netdev_desc
)
*
(
RX_RING_SIZE
+
TX_RING_SIZE
),
np
->
rx_ring
,
np
->
ring_dma
);
}
static
void
reinit_r
ing
(
struct
net_device
*
dev
)
static
void
reinit_r
x
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
i
;
/* drain TX ring */
drain_tx
(
dev
);
np
->
dirty_tx
=
np
->
cur_tx
=
0
;
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
np
->
tx_ring
[
i
].
cmd_status
=
0
;
/* RX Ring */
np
->
dirty_rx
=
0
;
np
->
cur_rx
=
RX_RING_SIZE
;
...
...
@@ -1588,9 +2025,23 @@ static void reinit_ring(struct net_device *dev)
refill_rx
(
dev
);
}
static
void
reinit_ring
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
int
i
;
/* drain TX ring */
drain_tx
(
dev
);
np
->
dirty_tx
=
np
->
cur_tx
=
0
;
for
(
i
=
0
;
i
<
TX_RING_SIZE
;
i
++
)
np
->
tx_ring
[
i
].
cmd_status
=
0
;
reinit_rx
(
dev
);
}
static
int
start_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
unsigned
entry
;
/* Note: Ordering is important here, set the field with the
...
...
@@ -1637,7 +2088,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
static
void
netdev_tx_done
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
for
(;
np
->
cur_tx
-
np
->
dirty_tx
>
0
;
np
->
dirty_tx
++
)
{
int
entry
=
np
->
dirty_tx
%
TX_RING_SIZE
;
...
...
@@ -1683,7 +2134,7 @@ static void netdev_tx_done(struct net_device *dev)
static
irqreturn_t
intr_handler
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
rgs
)
{
struct
net_device
*
dev
=
dev_instance
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
int
boguscnt
=
max_interrupt_work
;
unsigned
int
handled
=
0
;
...
...
@@ -1741,20 +2192,22 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
for clarity and better register allocation. */
static
void
netdev_rx
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
int
entry
=
np
->
cur_rx
%
RX_RING_SIZE
;
int
boguscnt
=
np
->
dirty_rx
+
RX_RING_SIZE
-
np
->
cur_rx
;
s32
desc_status
=
le32_to_cpu
(
np
->
rx_head_desc
->
cmd_status
);
unsigned
int
buflen
=
np
->
rx_buf_sz
+
RX_OFFSET
;
unsigned
int
buflen
=
np
->
rx_buf_sz
;
/* If the driver owns the next entry it's a new packet. Send it up. */
while
(
desc_status
<
0
)
{
/* e.g. & DescOwn */
int
pkt_len
;
if
(
netif_msg_rx_status
(
np
))
printk
(
KERN_DEBUG
" netdev_rx() entry %d status was %#08x.
\n
"
,
entry
,
desc_status
);
if
(
--
boguscnt
<
0
)
break
;
pkt_len
=
(
desc_status
&
DescSizeMask
)
-
4
;
if
((
desc_status
&
(
DescMore
|
DescPktOK
|
DescRxLong
))
!=
DescPktOK
){
if
(
desc_status
&
DescMore
)
{
if
(
netif_msg_rx_err
(
np
))
...
...
@@ -1777,10 +2230,14 @@ static void netdev_rx(struct net_device *dev)
if
(
desc_status
&
DescRxCRC
)
np
->
stats
.
rx_crc_errors
++
;
}
}
else
if
(
pkt_len
>
np
->
rx_buf_sz
)
{
/* if this is the tail of a double buffer
* packet, we've already counted the error
* on the first part. Ignore the second half.
*/
}
else
{
struct
sk_buff
*
skb
;
/* Omit CRC size. */
int
pkt_len
=
(
desc_status
&
DescSizeMask
)
-
4
;
/* Check if the packet is long enough to accept
* without copying to a minimally-sized skbuff. */
if
(
pkt_len
<
rx_copybreak
...
...
@@ -1826,19 +2283,18 @@ static void netdev_rx(struct net_device *dev)
static
void
netdev_error
(
struct
net_device
*
dev
,
int
intr_status
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
spin_lock
(
&
np
->
lock
);
if
(
intr_status
&
LinkChange
)
{
u16
adv
=
mdio_read
(
dev
,
1
,
MII_ADVERTISE
);
u16
lpa
=
mdio_read
(
dev
,
1
,
MII_LPA
);
if
(
mdio_read
(
dev
,
1
,
MII_BMCR
)
&
BMCR_ANENABLE
u16
lpa
=
mdio_read
(
dev
,
MII_LPA
);
if
(
mdio_read
(
dev
,
MII_BMCR
)
&
BMCR_ANENABLE
&&
netif_msg_link
(
np
))
{
printk
(
KERN_INFO
"%s: Autonegotiation advertising"
" %#04x partner %#04x.
\n
"
,
dev
->
name
,
adv
,
lpa
);
np
->
advertising
,
lpa
);
}
/* read MII int status to clear the flag */
...
...
@@ -1849,12 +2305,18 @@ static void netdev_error(struct net_device *dev, int intr_status)
__get_stats
(
dev
);
}
if
(
intr_status
&
IntrTxUnderrun
)
{
if
((
np
->
tx_config
&
TxDrthMask
)
<
62
)
np
->
tx_config
+=
2
;
if
(
netif_msg_tx_err
(
np
))
printk
(
KERN_NOTICE
"%s: increased Tx threshold, txcfg %#08x.
\n
"
,
dev
->
name
,
np
->
tx_config
);
if
((
np
->
tx_config
&
TxDrthMask
)
<
TX_DRTH_VAL_LIMIT
)
{
np
->
tx_config
+=
TX_DRTH_VAL_INC
;
if
(
netif_msg_tx_err
(
np
))
printk
(
KERN_NOTICE
"%s: increased tx threshold, txcfg %#08x.
\n
"
,
dev
->
name
,
np
->
tx_config
);
}
else
{
if
(
netif_msg_tx_err
(
np
))
printk
(
KERN_NOTICE
"%s: tx underrun with maximum tx threshold, txcfg %#08x.
\n
"
,
dev
->
name
,
np
->
tx_config
);
}
writel
(
np
->
tx_config
,
ioaddr
+
TxConfig
);
}
if
(
intr_status
&
WOLPkt
&&
netif_msg_wol
(
np
))
{
...
...
@@ -1882,7 +2344,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
static
void
__get_stats
(
struct
net_device
*
dev
)
{
long
ioaddr
=
dev
->
base_addr
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
/* The chip only need report frame silently dropped. */
np
->
stats
.
rx_crc_errors
+=
readl
(
ioaddr
+
RxCRCErrs
);
...
...
@@ -1891,7 +2353,7 @@ static void __get_stats(struct net_device *dev)
static
struct
net_device_stats
*
get_stats
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
/* The chip only need report frame silently dropped. */
spin_lock_irq
(
&
np
->
lock
);
...
...
@@ -1906,7 +2368,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
static
void
__set_rx_mode
(
struct
net_device
*
dev
)
{
long
ioaddr
=
dev
->
base_addr
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u8
mc_filter
[
64
];
/* Multicast hash filter */
u32
rx_mode
;
...
...
@@ -1941,9 +2403,39 @@ static void __set_rx_mode(struct net_device *dev)
np
->
cur_rx_mode
=
rx_mode
;
}
static
int
natsemi_change_mtu
(
struct
net_device
*
dev
,
int
new_mtu
)
{
if
(
new_mtu
<
64
||
new_mtu
>
NATSEMI_RX_LIMIT
-
NATSEMI_HEADERS
)
return
-
EINVAL
;
dev
->
mtu
=
new_mtu
;
/* synchronized against open : rtnl_lock() held by caller */
if
(
netif_running
(
dev
))
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
long
ioaddr
=
dev
->
base_addr
;
disable_irq
(
dev
->
irq
);
spin_lock
(
&
np
->
lock
);
/* stop engines */
natsemi_stop_rxtx
(
dev
);
/* drain rx queue */
drain_rx
(
dev
);
/* change buffers */
set_bufsize
(
dev
);
reinit_rx
(
dev
);
writel
(
np
->
ring_dma
,
ioaddr
+
RxRingPtr
);
/* restart engines */
writel
(
RxOn
|
TxOn
,
ioaddr
+
ChipCmd
);
spin_unlock
(
&
np
->
lock
);
enable_irq
(
dev
->
irq
);
}
return
0
;
}
static
void
set_rx_mode
(
struct
net_device
*
dev
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
spin_lock_irq
(
&
np
->
lock
);
if
(
!
np
->
hands_off
)
__set_rx_mode
(
dev
);
...
...
@@ -1952,7 +2444,7 @@ static void set_rx_mode(struct net_device *dev)
static
int
netdev_ethtool_ioctl
(
struct
net_device
*
dev
,
void
__user
*
useraddr
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u32
cmd
;
if
(
get_user
(
cmd
,
(
u32
__user
*
)
useraddr
))
...
...
@@ -2066,10 +2558,10 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
int
tmp
;
int
r
=
-
EINVAL
;
/* if autoneg is off, it's an error */
tmp
=
mdio_read
(
dev
,
1
,
MII_BMCR
);
tmp
=
mdio_read
(
dev
,
MII_BMCR
);
if
(
tmp
&
BMCR_ANENABLE
)
{
tmp
|=
(
BMCR_ANRESTART
);
mdio_write
(
dev
,
1
,
MII_BMCR
,
tmp
);
mdio_write
(
dev
,
MII_BMCR
,
tmp
);
r
=
0
;
}
return
r
;
...
...
@@ -2078,8 +2570,8 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
case
ETHTOOL_GLINK
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
/* LSTATUS is latched low until a read - so read twice */
mdio_read
(
dev
,
1
,
MII_BMSR
);
edata
.
data
=
(
mdio_read
(
dev
,
1
,
MII_BMSR
)
&
BMSR_LSTATUS
)
?
1
:
0
;
mdio_read
(
dev
,
MII_BMSR
);
edata
.
data
=
(
mdio_read
(
dev
,
MII_BMSR
)
&
BMSR_LSTATUS
)
?
1
:
0
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
...
...
@@ -2123,7 +2615,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
static
int
netdev_set_wol
(
struct
net_device
*
dev
,
u32
newval
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u32
data
=
readl
(
dev
->
base_addr
+
WOLCmd
)
&
~
WakeOptsSummary
;
/* translate to bitmasks this chip understands */
...
...
@@ -2152,7 +2644,7 @@ static int netdev_set_wol(struct net_device *dev, u32 newval)
static
int
netdev_get_wol
(
struct
net_device
*
dev
,
u32
*
supported
,
u32
*
cur
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u32
regval
=
readl
(
dev
->
base_addr
+
WOLCmd
);
*
supported
=
(
WAKE_PHY
|
WAKE_UCAST
|
WAKE_MCAST
|
WAKE_BCAST
...
...
@@ -2187,7 +2679,7 @@ static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur)
static
int
netdev_set_sopass
(
struct
net_device
*
dev
,
u8
*
newval
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u16
*
sval
=
(
u16
*
)
newval
;
u32
addr
;
...
...
@@ -2218,7 +2710,7 @@ static int netdev_set_sopass(struct net_device *dev, u8 *newval)
static
int
netdev_get_sopass
(
struct
net_device
*
dev
,
u8
*
data
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
u16
*
sval
=
(
u16
*
)
data
;
u32
addr
;
...
...
@@ -2246,56 +2738,75 @@ static int netdev_get_sopass(struct net_device *dev, u8 *data)
static
int
netdev_get_ecmd
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
ecmd
)
{
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
u32
tmp
;
ecmd
->
supported
=
(
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_Autoneg
|
SUPPORTED_TP
|
SUPPORTED_MII
);
/* only supports twisted-pair or MII */
tmp
=
readl
(
dev
->
base_addr
+
ChipConfig
);
if
(
tmp
&
CfgExtPhy
)
ecmd
->
port
=
PORT_MII
;
else
ecmd
->
port
=
PORT_TP
;
/* only supports internal transceiver */
ecmd
->
transceiver
=
XCVR_INTERNAL
;
/* not sure what this is for */
ecmd
->
phy_address
=
readw
(
dev
->
base_addr
+
PhyCtrl
)
&
PhyAddrMask
;
ecmd
->
advertising
=
ADVERTISED_TP
|
ADVERTISED_MII
;
tmp
=
mdio_read
(
dev
,
1
,
MII_ADVERTISE
);
if
(
tmp
&
ADVERTISE_10HALF
)
ecmd
->
port
=
dev
->
if_port
;
ecmd
->
speed
=
np
->
speed
;
ecmd
->
duplex
=
np
->
duplex
;
ecmd
->
autoneg
=
np
->
autoneg
;
ecmd
->
advertising
=
0
;
if
(
np
->
advertising
&
ADVERTISE_10HALF
)
ecmd
->
advertising
|=
ADVERTISED_10baseT_Half
;
if
(
tmp
&
ADVERTISE_10FULL
)
if
(
np
->
advertising
&
ADVERTISE_10FULL
)
ecmd
->
advertising
|=
ADVERTISED_10baseT_Full
;
if
(
tmp
&
ADVERTISE_100HALF
)
if
(
np
->
advertising
&
ADVERTISE_100HALF
)
ecmd
->
advertising
|=
ADVERTISED_100baseT_Half
;
if
(
tmp
&
ADVERTISE_100FULL
)
if
(
np
->
advertising
&
ADVERTISE_100FULL
)
ecmd
->
advertising
|=
ADVERTISED_100baseT_Full
;
ecmd
->
supported
=
(
SUPPORTED_Autoneg
|
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_TP
|
SUPPORTED_MII
|
SUPPORTED_FIBRE
);
ecmd
->
phy_address
=
np
->
phy_addr_external
;
/*
* We intentionally report the phy address of the external
* phy, even if the internal phy is used. This is necessary
* to work around a deficiency of the ethtool interface:
* It's only possible to query the settings of the active
* port. Therefore
* # ethtool -s ethX port mii
* actually sends an ioctl to switch to port mii with the
* settings that are used for the current active port.
* If we would report a different phy address in this
* command, then
* # ethtool -s ethX port tp;ethtool -s ethX port mii
* would unintentionally change the phy address.
*
* Fortunately the phy address doesn't matter with the
* internal phy...
*/
tmp
=
mdio_read
(
dev
,
1
,
MII_BMCR
);
if
(
tmp
&
BMCR_ANENABLE
)
{
/* set information based on active port type */
switch
(
ecmd
->
port
)
{
default:
case
PORT_TP
:
ecmd
->
advertising
|=
ADVERTISED_TP
;
ecmd
->
transceiver
=
XCVR_INTERNAL
;
break
;
case
PORT_MII
:
ecmd
->
advertising
|=
ADVERTISED_MII
;
ecmd
->
transceiver
=
XCVR_EXTERNAL
;
break
;
case
PORT_FIBRE
:
ecmd
->
advertising
|=
ADVERTISED_FIBRE
;
ecmd
->
transceiver
=
XCVR_EXTERNAL
;
break
;
}
/* if autonegotiation is on, try to return the active speed/duplex */
if
(
ecmd
->
autoneg
==
AUTONEG_ENABLE
)
{
ecmd
->
advertising
|=
ADVERTISED_Autoneg
;
ecmd
->
autoneg
=
AUTONEG_ENABLE
;
}
else
{
ecmd
->
autoneg
=
AUTONEG_DISABLE
;
}
tmp
=
readl
(
dev
->
base_addr
+
ChipConfig
);
if
(
tmp
&
CfgSpeed100
)
{
ecmd
->
speed
=
SPEED_100
;
}
else
{
ecmd
->
speed
=
SPEED_10
;
}
if
(
tmp
&
CfgFullDuplex
)
{
ecmd
->
duplex
=
DUPLEX_FULL
;
}
else
{
ecmd
->
duplex
=
DUPLEX_HALF
;
tmp
=
mii_nway_result
(
np
->
advertising
&
mdio_read
(
dev
,
MII_LPA
));
if
(
tmp
==
LPA_100FULL
||
tmp
==
LPA_100HALF
)
ecmd
->
speed
=
SPEED_100
;
else
ecmd
->
speed
=
SPEED_10
;
if
(
tmp
==
LPA_100FULL
||
tmp
==
LPA_10FULL
)
ecmd
->
duplex
=
DUPLEX_FULL
;
else
ecmd
->
duplex
=
DUPLEX_HALF
;
}
/* ignore maxtxpkt, maxrxpkt for now */
...
...
@@ -2305,39 +2816,75 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
static
int
netdev_set_ecmd
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
ecmd
)
{
struct
netdev_private
*
np
=
dev
->
priv
;
u32
tmp
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
if
(
ecmd
->
speed
!=
SPEED_10
&&
ecmd
->
speed
!=
SPEED_100
)
if
(
ecmd
->
port
!=
PORT_TP
&&
ecmd
->
port
!=
PORT_MII
&&
ecmd
->
port
!=
PORT_FIBRE
)
return
-
EINVAL
;
if
(
ecmd
->
duplex
!=
DUPLEX_HALF
&&
ecmd
->
duplex
!=
DUPLEX_FUL
L
)
if
(
ecmd
->
transceiver
!=
XCVR_INTERNAL
&&
ecmd
->
transceiver
!=
XCVR_EXTERNA
L
)
return
-
EINVAL
;
if
(
ecmd
->
port
!=
PORT_TP
&&
ecmd
->
port
!=
PORT_MII
)
return
-
EINVAL
;
if
(
ecmd
->
transceiver
!=
XCVR_INTERNAL
)
return
-
EINVAL
;
if
(
ecmd
->
autoneg
!=
AUTONEG_DISABLE
&&
ecmd
->
autoneg
!=
AUTONEG_ENABLE
)
if
(
ecmd
->
autoneg
==
AUTONEG_ENABLE
)
{
if
((
ecmd
->
advertising
&
(
ADVERTISED_10baseT_Half
|
ADVERTISED_10baseT_Full
|
ADVERTISED_100baseT_Half
|
ADVERTISED_100baseT_Full
))
==
0
)
{
return
-
EINVAL
;
}
}
else
if
(
ecmd
->
autoneg
==
AUTONEG_DISABLE
)
{
if
(
ecmd
->
speed
!=
SPEED_10
&&
ecmd
->
speed
!=
SPEED_100
)
return
-
EINVAL
;
if
(
ecmd
->
duplex
!=
DUPLEX_HALF
&&
ecmd
->
duplex
!=
DUPLEX_FULL
)
return
-
EINVAL
;
}
else
{
return
-
EINVAL
;
/* ignore phy_address, maxtxpkt, maxrxpkt for now */
}
/*
* maxtxpkt, maxrxpkt: ignored for now.
*
* transceiver:
* PORT_TP is always XCVR_INTERNAL, PORT_MII and PORT_FIBRE are always
* XCVR_EXTERNAL. The implementation thus ignores ecmd->transceiver and
* selects based on ecmd->port.
*
* Actually PORT_FIBRE is nearly identical to PORT_MII: it's for fibre
* phys that are connected to the mii bus. It's used to apply fibre
* specific updates.
*/
/* WHEW! now lets bang some bits */
tmp
=
mdio_read
(
dev
,
1
,
MII_BMCR
);
if
(
ecmd
->
autoneg
==
AUTONEG_ENABLE
)
{
/* turn on autonegotiation */
tmp
|=
BMCR_ANENABLE
;
np
->
advertising
=
mdio_read
(
dev
,
1
,
MII_ADVERTISE
);
/* save the parms */
dev
->
if_port
=
ecmd
->
port
;
np
->
autoneg
=
ecmd
->
autoneg
;
np
->
phy_addr_external
=
ecmd
->
phy_address
&
PhyAddrMask
;
if
(
np
->
autoneg
==
AUTONEG_ENABLE
)
{
/* advertise only what has been requested */
np
->
advertising
&=
~
(
ADVERTISE_ALL
|
ADVERTISE_100BASE4
);
if
(
ecmd
->
advertising
&
ADVERTISED_10baseT_Half
)
np
->
advertising
|=
ADVERTISE_10HALF
;
if
(
ecmd
->
advertising
&
ADVERTISED_10baseT_Full
)
np
->
advertising
|=
ADVERTISE_10FULL
;
if
(
ecmd
->
advertising
&
ADVERTISED_100baseT_Half
)
np
->
advertising
|=
ADVERTISE_100HALF
;
if
(
ecmd
->
advertising
&
ADVERTISED_100baseT_Full
)
np
->
advertising
|=
ADVERTISE_100FULL
;
}
else
{
/* turn off auto negotiation, set speed and duplexity */
tmp
&=
~
(
BMCR_ANENABLE
|
BMCR_SPEED100
|
BMCR_FULLDPLX
);
if
(
ecmd
->
speed
==
SPEED_100
)
tmp
|=
BMCR_SPEED100
;
if
(
ecmd
->
duplex
==
DUPLEX_FULL
)
tmp
|=
BMCR_FULLDPLX
;
else
np
->
speed
=
ecmd
->
speed
;
np
->
duplex
=
ecmd
->
duplex
;
/* user overriding the initial full duplex parm? */
if
(
np
->
duplex
==
DUPLEX_HALF
)
np
->
full_duplex
=
0
;
}
mdio_write
(
dev
,
1
,
MII_BMCR
,
tmp
);
/* get the right phy enabled */
if
(
ecmd
->
port
==
PORT_TP
)
switch_port_internal
(
dev
);
else
switch_port_external
(
dev
);
/* set parms and see how this affected our link status */
init_phy_fixup
(
dev
);
check_link
(
dev
);
return
0
;
}
...
...
@@ -2348,11 +2895,15 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf)
u32
rfcr
;
u32
*
rbuf
=
(
u32
*
)
buf
;
/* read
all of
page 0 of registers */
for
(
i
=
0
;
i
<
NATSEMI_PG0_NREGS
;
i
++
)
{
/* read
non-mii
page 0 of registers */
for
(
i
=
0
;
i
<
NATSEMI_PG0_NREGS
/
2
;
i
++
)
{
rbuf
[
i
]
=
readl
(
dev
->
base_addr
+
i
*
4
);
}
/* read current mii registers */
for
(
i
=
NATSEMI_PG0_NREGS
/
2
;
i
<
NATSEMI_PG0_NREGS
;
i
++
)
rbuf
[
i
]
=
mdio_read
(
dev
,
i
&
0x1f
);
/* read only the 'magic' registers from page 1 */
writew
(
1
,
dev
->
base_addr
+
PGSEL
);
rbuf
[
i
++
]
=
readw
(
dev
->
base_addr
+
PMDCSR
);
...
...
@@ -2407,27 +2958,56 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf)
static
int
netdev_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
mii_ioctl_data
*
data
=
if_mii
(
rq
);
struct
netdev_private
*
np
=
netdev_priv
(
dev
);
switch
(
cmd
)
{
case
SIOCETHTOOL
:
return
netdev_ethtool_ioctl
(
dev
,
rq
->
ifr_data
);
case
SIOCGMIIPHY
:
/* Get address of MII PHY in use. */
case
SIOCDEVPRIVATE
:
/* for binary compat, remove in 2.5 */
data
->
phy_id
=
1
;
data
->
phy_id
=
np
->
phy_addr_external
;
/* Fall Through */
case
SIOCGMIIREG
:
/* Read MII PHY register. */
case
SIOCDEVPRIVATE
+
1
:
/* for binary compat, remove in 2.5 */
data
->
val_out
=
mdio_read
(
dev
,
data
->
phy_id
&
0x1f
,
data
->
reg_num
&
0x1f
);
/* The phy_id is not enough to uniquely identify
* the intended target. Therefore the command is sent to
* the given mii on the current port.
*/
if
(
dev
->
if_port
==
PORT_TP
)
{
if
((
data
->
phy_id
&
0x1f
)
==
np
->
phy_addr_external
)
data
->
val_out
=
mdio_read
(
dev
,
data
->
reg_num
&
0x1f
);
else
data
->
val_out
=
0
;
}
else
{
move_int_phy
(
dev
,
data
->
phy_id
&
0x1f
);
data
->
val_out
=
miiport_read
(
dev
,
data
->
phy_id
&
0x1f
,
data
->
reg_num
&
0x1f
);
}
return
0
;
case
SIOCSMIIREG
:
/* Write MII PHY register. */
case
SIOCDEVPRIVATE
+
2
:
/* for binary compat, remove in 2.5 */
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
mdio_write
(
dev
,
data
->
phy_id
&
0x1f
,
data
->
reg_num
&
0x1f
,
data
->
val_in
);
if
(
dev
->
if_port
==
PORT_TP
)
{
if
((
data
->
phy_id
&
0x1f
)
==
np
->
phy_addr_external
)
{
if
((
data
->
reg_num
&
0x1f
)
==
MII_ADVERTISE
)
np
->
advertising
=
data
->
val_in
;
mdio_write
(
dev
,
data
->
reg_num
&
0x1f
,
data
->
val_in
);
}
}
else
{
if
((
data
->
phy_id
&
0x1f
)
==
np
->
phy_addr_external
)
{
if
((
data
->
reg_num
&
0x1f
)
==
MII_ADVERTISE
)
np
->
advertising
=
data
->
val_in
;
}
move_int_phy
(
dev
,
data
->
phy_id
&
0x1f
);
miiport_write
(
dev
,
data
->
phy_id
&
0x1f
,
data
->
reg_num
&
0x1f
,
data
->
val_in
);
}
return
0
;
default:
return
-
EOPNOTSUPP
;
...
...
@@ -2437,7 +3017,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static
void
enable_wol_mode
(
struct
net_device
*
dev
,
int
enable_intr
)
{
long
ioaddr
=
dev
->
base_addr
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
if
(
netif_msg_wol
(
np
))
printk
(
KERN_INFO
"%s: remaining active for wake-on-lan
\n
"
,
...
...
@@ -2470,7 +3050,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr)
static
int
netdev_close
(
struct
net_device
*
dev
)
{
long
ioaddr
=
dev
->
base_addr
;
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
if
(
netif_msg_ifdown
(
np
))
printk
(
KERN_DEBUG
...
...
@@ -2582,7 +3162,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
static
int
natsemi_suspend
(
struct
pci_dev
*
pdev
,
u32
state
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
long
ioaddr
=
dev
->
base_addr
;
rtnl_lock
();
...
...
@@ -2629,7 +3209,7 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state)
static
int
natsemi_resume
(
struct
pci_dev
*
pdev
)
{
struct
net_device
*
dev
=
pci_get_drvdata
(
pdev
);
struct
netdev_private
*
np
=
dev
->
priv
;
struct
netdev_private
*
np
=
netdev_priv
(
dev
)
;
rtnl_lock
();
if
(
netif_device_present
(
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