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
6502fb5d
Commit
6502fb5d
authored
Apr 05, 2002
by
Zwane Mwaikambo
Committed by
Linus Torvalds
Apr 05, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add power management support to 3c509 net driver.
parent
af5c1040
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
189 additions
and
73 deletions
+189
-73
drivers/net/3c509.c
drivers/net/3c509.c
+189
-73
No files found.
drivers/net/3c509.c
View file @
6502fb5d
...
...
@@ -45,11 +45,13 @@
- Reviewed against 1.18 from scyld.com
v1.18a 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com>
- ethtool support
v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
- Power Management support
*/
#define DRV_NAME "3c509"
#define DRV_VERSION "1.18
a
"
#define DRV_RELDATE "1
7Nov2001
"
#define DRV_VERSION "1.18
b
"
#define DRV_RELDATE "1
Mar2002
"
/* A few values that may be tweaked. */
...
...
@@ -82,8 +84,9 @@ static int max_interrupt_work = 10;
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/pm.h>
static
char
versionA
[]
__initdata
=
DRV_NAME
".c:"
DRV_VERSION
" "
DRV_RELDATE
"becker@scyld.com
\n
"
;
static
char
versionA
[]
__initdata
=
DRV_NAME
".c:"
DRV_VERSION
" "
DRV_RELDATE
"
becker@scyld.com
\n
"
;
static
char
versionB
[]
__initdata
=
"http://www.scyld.com/network/3c509.html
\n
"
;
#ifdef EL3_DEBUG
...
...
@@ -116,7 +119,8 @@ enum c509cmd {
FakeIntr
=
12
<<
11
,
AckIntr
=
13
<<
11
,
SetIntrEnb
=
14
<<
11
,
SetStatusEnb
=
15
<<
11
,
SetRxFilter
=
16
<<
11
,
SetRxThreshold
=
17
<<
11
,
SetTxThreshold
=
18
<<
11
,
SetTxStart
=
19
<<
11
,
StatsEnable
=
21
<<
11
,
StatsDisable
=
22
<<
11
,
StopCoax
=
23
<<
11
,};
StatsDisable
=
22
<<
11
,
StopCoax
=
23
<<
11
,
PowerUp
=
27
<<
11
,
PowerDown
=
28
<<
11
,
PowerAuto
=
29
<<
11
};
enum
c509status
{
IntLatch
=
0x0001
,
AdapterFailure
=
0x0002
,
TxComplete
=
0x0004
,
...
...
@@ -152,6 +156,9 @@ struct el3_private {
int
head
,
size
;
struct
sk_buff
*
queue
[
SKB_QUEUE_SIZE
];
char
mca_slot
;
#ifdef CONFIG_PM
struct
pm_dev
*
pmdev
;
#endif
};
static
int
id_port
__initdata
=
0x110
;
/* Start with 0x110 to avoid new sound cards.*/
static
struct
net_device
*
el3_root_dev
;
...
...
@@ -168,6 +175,13 @@ static int el3_close(struct net_device *dev);
static
void
set_multicast_list
(
struct
net_device
*
dev
);
static
void
el3_tx_timeout
(
struct
net_device
*
dev
);
static
int
netdev_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
void
el3_down
(
struct
net_device
*
dev
);
static
void
el3_up
(
struct
net_device
*
dev
);
#ifdef CONFIG_PM
static
int
el3_suspend
(
struct
pm_dev
*
pdev
);
static
int
el3_resume
(
struct
pm_dev
*
pdev
);
static
int
el3_pm_callback
(
struct
pm_dev
*
pdev
,
pm_request_t
rqst
,
void
*
data
);
#endif
#ifdef CONFIG_MCA
struct
el3_mca_adapters_struct
{
...
...
@@ -219,7 +233,7 @@ static u16 el3_isapnp_phys_addr[8][3];
#endif
/* __ISAPNP__ */
static
int
nopnp
;
int
__init
el3_probe
(
struct
net_device
*
dev
)
int
__init
el3_probe
(
struct
net_device
*
dev
,
int
card_idx
)
{
struct
el3_private
*
lp
;
short
lrs_state
=
0xff
,
i
;
...
...
@@ -525,6 +539,16 @@ int __init el3_probe(struct net_device *dev)
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
dev
->
do_ioctl
=
netdev_ioctl
;
#ifdef CONFIG_PM
/* register power management */
lp
->
pmdev
=
pm_register
(
PM_ISA_DEV
,
card_idx
,
el3_pm_callback
);
if
(
lp
->
pmdev
)
{
struct
pm_dev
*
p
;
p
=
lp
->
pmdev
;
p
->
data
=
(
struct
net_device
*
)
dev
;
}
#endif
/* Fill in the generic fields of the device structure. */
ether_setup
(
dev
);
return
0
;
...
...
@@ -581,53 +605,7 @@ el3_open(struct net_device *dev)
printk
(
"%s: Opening, IRQ %d status@%x %4.4x.
\n
"
,
dev
->
name
,
dev
->
irq
,
ioaddr
+
EL3_STATUS
,
inw
(
ioaddr
+
EL3_STATUS
));
/* Activate board: this is probably unnecessary. */
outw
(
0x0001
,
ioaddr
+
4
);
/* Set the IRQ line. */
outw
((
dev
->
irq
<<
12
)
|
0x0f00
,
ioaddr
+
WN0_IRQ
);
/* Set the station address in window 2 each time opened. */
EL3WINDOW
(
2
);
for
(
i
=
0
;
i
<
6
;
i
++
)
outb
(
dev
->
dev_addr
[
i
],
ioaddr
+
i
);
if
(
dev
->
if_port
==
3
)
/* Start the thinnet transceiver. We should really wait 50ms...*/
outw
(
StartCoax
,
ioaddr
+
EL3_CMD
);
else
if
(
dev
->
if_port
==
0
)
{
/* 10baseT interface, enabled link beat and jabber check. */
EL3WINDOW
(
4
);
outw
(
inw
(
ioaddr
+
WN4_MEDIA
)
|
MEDIA_TP
,
ioaddr
+
WN4_MEDIA
);
}
/* Switch to the stats window, and clear all stats by reading. */
outw
(
StatsDisable
,
ioaddr
+
EL3_CMD
);
EL3WINDOW
(
6
);
for
(
i
=
0
;
i
<
9
;
i
++
)
inb
(
ioaddr
+
i
);
inw
(
ioaddr
+
10
);
inw
(
ioaddr
+
12
);
/* Switch to register set 1 for normal use. */
EL3WINDOW
(
1
);
/* Accept b-case and phys addr only. */
outw
(
SetRxFilter
|
RxStation
|
RxBroadcast
,
ioaddr
+
EL3_CMD
);
outw
(
StatsEnable
,
ioaddr
+
EL3_CMD
);
/* Turn on statistics. */
netif_start_queue
(
dev
);
outw
(
RxEnable
,
ioaddr
+
EL3_CMD
);
/* Enable the receiver. */
outw
(
TxEnable
,
ioaddr
+
EL3_CMD
);
/* Enable transmitter. */
/* Allow status bits to be seen. */
outw
(
SetStatusEnb
|
0xff
,
ioaddr
+
EL3_CMD
);
/* Ack all pending events, and set active indicator mask. */
outw
(
AckIntr
|
IntLatch
|
TxAvailable
|
RxEarly
|
IntReq
,
ioaddr
+
EL3_CMD
);
outw
(
SetIntrEnb
|
IntLatch
|
TxAvailable
|
TxComplete
|
RxComplete
|
StatsFull
,
ioaddr
+
EL3_CMD
);
el3_up
(
dev
);
if
(
el3_debug
>
3
)
printk
(
"%s: Opened 3c509 IRQ %d status %4.4x.
\n
"
,
...
...
@@ -986,23 +964,7 @@ el3_close(struct net_device *dev)
if
(
el3_debug
>
2
)
printk
(
"%s: Shutting down ethercard.
\n
"
,
dev
->
name
);
netif_stop_queue
(
dev
);
/* Turn off statistics ASAP. We update lp->stats below. */
outw
(
StatsDisable
,
ioaddr
+
EL3_CMD
);
/* Disable the receiver and transmitter. */
outw
(
RxDisable
,
ioaddr
+
EL3_CMD
);
outw
(
TxDisable
,
ioaddr
+
EL3_CMD
);
if
(
dev
->
if_port
==
3
)
/* Turn off thinnet power. Green! */
outw
(
StopCoax
,
ioaddr
+
EL3_CMD
);
else
if
(
dev
->
if_port
==
0
)
{
/* Disable link beat and jabber, if_port may change ere next open(). */
EL3WINDOW
(
4
);
outw
(
inw
(
ioaddr
+
WN4_MEDIA
)
&
~
MEDIA_TP
,
ioaddr
+
WN4_MEDIA
);
}
el3_down
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
/* Switching back to window 0 disables the IRQ. */
...
...
@@ -1010,7 +972,6 @@ el3_close(struct net_device *dev)
/* But we explicitly zero the IRQ line select anyway. */
outw
(
0x0f00
,
ioaddr
+
WN0_IRQ
);
update_stats
(
dev
);
return
0
;
}
...
...
@@ -1092,7 +1053,157 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return
rc
;
}
static
void
el3_down
(
struct
net_device
*
dev
)
{
int
ioaddr
=
dev
->
base_addr
;
netif_stop_queue
(
dev
);
/* Turn off statistics ASAP. We update lp->stats below. */
outw
(
StatsDisable
,
ioaddr
+
EL3_CMD
);
/* Disable the receiver and transmitter. */
outw
(
RxDisable
,
ioaddr
+
EL3_CMD
);
outw
(
TxDisable
,
ioaddr
+
EL3_CMD
);
if
(
dev
->
if_port
==
3
)
/* Turn off thinnet power. Green! */
outw
(
StopCoax
,
ioaddr
+
EL3_CMD
);
else
if
(
dev
->
if_port
==
0
)
{
/* Disable link beat and jabber, if_port may change ere next open(). */
EL3WINDOW
(
4
);
outw
(
inw
(
ioaddr
+
WN4_MEDIA
)
&
~
MEDIA_TP
,
ioaddr
+
WN4_MEDIA
);
}
outw
(
SetIntrEnb
|
0x0000
,
ioaddr
+
EL3_CMD
);
update_stats
(
dev
);
}
static
void
el3_up
(
struct
net_device
*
dev
)
{
int
i
;
int
ioaddr
=
dev
->
base_addr
;
/* Activating the board required and does no harm otherwise */
outw
(
0x0001
,
ioaddr
+
4
);
/* Set the IRQ line. */
outw
((
dev
->
irq
<<
12
)
|
0x0f00
,
ioaddr
+
WN0_IRQ
);
/* Set the station address in window 2 each time opened. */
EL3WINDOW
(
2
);
for
(
i
=
0
;
i
<
6
;
i
++
)
outb
(
dev
->
dev_addr
[
i
],
ioaddr
+
i
);
if
(
dev
->
if_port
==
3
)
/* Start the thinnet transceiver. We should really wait 50ms...*/
outw
(
StartCoax
,
ioaddr
+
EL3_CMD
);
else
if
(
dev
->
if_port
==
0
)
{
/* 10baseT interface, enabled link beat and jabber check. */
EL3WINDOW
(
4
);
outw
(
inw
(
ioaddr
+
WN4_MEDIA
)
|
MEDIA_TP
,
ioaddr
+
WN4_MEDIA
);
}
/* Switch to the stats window, and clear all stats by reading. */
outw
(
StatsDisable
,
ioaddr
+
EL3_CMD
);
EL3WINDOW
(
6
);
for
(
i
=
0
;
i
<
9
;
i
++
)
inb
(
ioaddr
+
i
);
inw
(
ioaddr
+
10
);
inw
(
ioaddr
+
12
);
/* Switch to register set 1 for normal use. */
EL3WINDOW
(
1
);
/* Accept b-case and phys addr only. */
outw
(
SetRxFilter
|
RxStation
|
RxBroadcast
,
ioaddr
+
EL3_CMD
);
outw
(
StatsEnable
,
ioaddr
+
EL3_CMD
);
/* Turn on statistics. */
outw
(
RxEnable
,
ioaddr
+
EL3_CMD
);
/* Enable the receiver. */
outw
(
TxEnable
,
ioaddr
+
EL3_CMD
);
/* Enable transmitter. */
/* Allow status bits to be seen. */
outw
(
SetStatusEnb
|
0xff
,
ioaddr
+
EL3_CMD
);
/* Ack all pending events, and set active indicator mask. */
outw
(
AckIntr
|
IntLatch
|
TxAvailable
|
RxEarly
|
IntReq
,
ioaddr
+
EL3_CMD
);
outw
(
SetIntrEnb
|
IntLatch
|
TxAvailable
|
TxComplete
|
RxComplete
|
StatsFull
,
ioaddr
+
EL3_CMD
);
netif_start_queue
(
dev
);
}
/* Power Management support functions */
#ifdef CONFIG_PM
static
int
el3_suspend
(
struct
pm_dev
*
pdev
)
{
unsigned
long
flags
;
struct
net_device
*
dev
;
struct
el3_private
*
lp
;
int
ioaddr
;
if
(
!
pdev
&&
!
pdev
->
data
)
return
-
EINVAL
;
dev
=
(
struct
net_device
*
)
pdev
->
data
;
lp
=
(
struct
el3_private
*
)
dev
->
priv
;
ioaddr
=
dev
->
base_addr
;
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
if
(
netif_running
(
dev
))
netif_device_detach
(
dev
);
el3_down
(
dev
);
outw
(
PowerDown
,
ioaddr
+
EL3_CMD
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
return
0
;
}
static
int
el3_resume
(
struct
pm_dev
*
pdev
)
{
unsigned
long
flags
;
struct
net_device
*
dev
;
struct
el3_private
*
lp
;
int
ioaddr
;
if
(
!
pdev
&&
!
pdev
->
data
)
return
-
EINVAL
;
dev
=
(
struct
net_device
*
)
pdev
->
data
;
lp
=
(
struct
el3_private
*
)
dev
->
priv
;
ioaddr
=
dev
->
base_addr
;
spin_lock_irqsave
(
&
lp
->
lock
,
flags
);
outw
(
PowerUp
,
ioaddr
+
EL3_CMD
);
el3_up
(
dev
);
if
(
netif_running
(
dev
))
netif_device_attach
(
dev
);
spin_unlock_irqrestore
(
&
lp
->
lock
,
flags
);
return
0
;
}
static
int
el3_pm_callback
(
struct
pm_dev
*
pdev
,
pm_request_t
rqst
,
void
*
data
)
{
switch
(
rqst
)
{
case
PM_SUSPEND
:
return
el3_suspend
(
pdev
);
case
PM_RESUME
:
return
el3_resume
(
pdev
);
}
return
0
;
}
#endif
/* CONFIG_PM */
#ifdef MODULE
/* Parameters that may be passed into the module. */
static
int
debug
=
-
1
;
...
...
@@ -1122,7 +1233,7 @@ init_module(void)
el3_debug
=
debug
;
el3_root_dev
=
NULL
;
while
(
el3_probe
(
0
)
==
0
)
{
while
(
el3_probe
(
0
,
el3_cards
)
==
0
)
{
if
(
irq
[
el3_cards
]
>
1
)
el3_root_dev
->
irq
=
irq
[
el3_cards
];
if
(
xcvr
[
el3_cards
]
>=
0
)
...
...
@@ -1144,7 +1255,12 @@ cleanup_module(void)
#ifdef CONFIG_MCA
if
(
lp
->
mca_slot
!=-
1
)
mca_mark_as_unused
(
lp
->
mca_slot
);
#endif
#endif
#ifdef CONFIG_PM
if
(
lp
->
pmdev
)
pm_unregister
(
lp
->
pmdev
);
#endif
next_dev
=
lp
->
next_dev
;
unregister_netdev
(
el3_root_dev
);
release_region
(
el3_root_dev
->
base_addr
,
EL3_IO_EXTENT
);
...
...
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