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
57af3ff0
Commit
57af3ff0
authored
Jul 11, 2003
by
Alan Cox
Committed by
Steve French
Jul 11, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] fix up nmclan locking and hang on eject at wrong moment
[Not tested as I no longer have the card]
parent
396f16bd
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
69 additions
and
46 deletions
+69
-46
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/nmclan_cs.c
+69
-46
No files found.
drivers/net/pcmcia/nmclan_cs.c
View file @
57af3ff0
...
...
@@ -8,6 +8,7 @@ Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN.
Written by Roger C. Pao <rpao@paonet.org>
Copyright 1995 Roger C. Pao
Linux 2.5 cleanups Copyright Red Hat 2003
This software may be used and distributed according to the terms of
the GNU General Public License.
...
...
@@ -68,6 +69,10 @@ Driver Notes and Issues
History
-------------------------------------------------------------------------------
Log: nmclan_cs.c,v
* 2.5.75-ac1 2003/07/11 Alan Cox <alan@redhat.com>
* Fixed hang on card eject as we probe it
* Cleaned up to use new style locking.
*
* Revision 0.16 1995/07/01 06:42:17 rpao
* Bug fix: nmclan_reset() called CardServices incorrectly.
*
...
...
@@ -369,6 +374,8 @@ typedef struct _mace_private {
char
tx_free_frames
;
/* Number of free transmit frame buffers */
char
tx_irq_disabled
;
/* MACE TX interrupt disabled */
spinlock_t
bank_lock
;
/* Must be held if you step off bank 0 */
}
mace_private
;
/* ----------------------------------------------------------------------------
...
...
@@ -482,6 +489,7 @@ static dev_link_t *nmclan_attach(void)
link
=
&
lp
->
link
;
link
->
priv
=
dev
;
spin_lock_init
(
&
lp
->
bank_lock
);
init_timer
(
&
link
->
release
);
link
->
release
.
function
=
&
nmclan_release
;
link
->
release
.
data
=
(
u_long
)
link
;
...
...
@@ -561,7 +569,7 @@ static void nmclan_detach(dev_link_t *link)
if
(
*
linkp
==
NULL
)
return
;
del_timer
(
&
link
->
release
);
del_timer
_sync
(
&
link
->
release
);
if
(
link
->
state
&
DEV_CONFIG
)
{
nmclan_release
((
u_long
)
link
);
if
(
link
->
state
&
DEV_STALE_CONFIG
)
{
...
...
@@ -588,7 +596,7 @@ mace_read
assuming that during normal operation, the MACE is always in
bank 0.
---------------------------------------------------------------------------- */
static
int
mace_read
(
ioaddr_t
ioaddr
,
int
reg
)
static
int
mace_read
(
mace_private
*
lp
,
ioaddr_t
ioaddr
,
int
reg
)
{
int
data
=
0xFF
;
unsigned
long
flags
;
...
...
@@ -598,12 +606,11 @@ static int mace_read(ioaddr_t ioaddr, int reg)
data
=
inb
(
ioaddr
+
AM2150_MACE_BASE
+
reg
);
break
;
case
1
:
/* register 16-31 */
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
lp
->
bank_lock
,
flags
);
MACEBANK
(
1
);
data
=
inb
(
ioaddr
+
AM2150_MACE_BASE
+
(
reg
&
0x0F
));
MACEBANK
(
0
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
lp
->
bank_lock
,
flags
);
break
;
}
return
(
data
&
0xFF
);
...
...
@@ -616,7 +623,7 @@ mace_write
are assuming that during normal operation, the MACE is always in
bank 0.
---------------------------------------------------------------------------- */
static
void
mace_write
(
ioaddr_t
ioaddr
,
int
reg
,
int
data
)
static
void
mace_write
(
mace_private
*
lp
,
ioaddr_t
ioaddr
,
int
reg
,
int
data
)
{
unsigned
long
flags
;
...
...
@@ -625,12 +632,11 @@ static void mace_write(ioaddr_t ioaddr, int reg, int data)
outb
(
data
&
0xFF
,
ioaddr
+
AM2150_MACE_BASE
+
reg
);
break
;
case
1
:
/* register 16-31 */
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
lp
->
bank_lock
,
flags
);
MACEBANK
(
1
);
outb
(
data
&
0xFF
,
ioaddr
+
AM2150_MACE_BASE
+
(
reg
&
0x0F
));
MACEBANK
(
0
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
lp
->
bank_lock
,
flags
);
break
;
}
}
/* mace_write */
...
...
@@ -639,22 +645,29 @@ static void mace_write(ioaddr_t ioaddr, int reg, int data)
mace_init
Resets the MACE chip.
---------------------------------------------------------------------------- */
static
void
mace_init
(
ioaddr_t
ioaddr
,
char
*
enet_addr
)
static
int
mace_init
(
mace_private
*
lp
,
ioaddr_t
ioaddr
,
char
*
enet_addr
)
{
int
i
;
int
ct
=
0
;
/* MACE Software reset */
mace_write
(
ioaddr
,
MACE_BIUCC
,
1
);
while
(
mace_read
(
ioaddr
,
MACE_BIUCC
)
&
0x01
)
{
mace_write
(
lp
,
ioaddr
,
MACE_BIUCC
,
1
);
while
(
mace_read
(
lp
,
ioaddr
,
MACE_BIUCC
)
&
0x01
)
{
/* Wait for reset bit to be cleared automatically after <= 200ns */
;
if
(
++
ct
>
500
)
{
printk
(
KERN_ERR
"mace: reset failed, card removed ?
\n
"
);
return
-
1
;
}
udelay
(
1
);
}
mace_write
(
ioaddr
,
MACE_BIUCC
,
0
);
mace_write
(
lp
,
ioaddr
,
MACE_BIUCC
,
0
);
/* The Am2150 requires that the MACE FIFOs operate in burst mode. */
mace_write
(
ioaddr
,
MACE_FIFOCC
,
0x0F
);
mace_write
(
lp
,
ioaddr
,
MACE_FIFOCC
,
0x0F
);
mace_write
(
ioaddr
,
MACE_RCVFC
,
0
);
/* Disable Auto Strip Receive */
mace_write
(
ioaddr
,
MACE_IMR
,
0xFF
);
/* Disable all interrupts until _open */
mace_write
(
lp
,
ioaddr
,
MACE_RCVFC
,
0
);
/* Disable Auto Strip Receive */
mace_write
(
lp
,
ioaddr
,
MACE_IMR
,
0xFF
);
/* Disable all interrupts until _open */
/*
* Bit 2-1 PORTSEL[1-0] Port Select.
...
...
@@ -670,31 +683,39 @@ static void mace_init(ioaddr_t ioaddr, char *enet_addr)
*/
switch
(
if_port
)
{
case
1
:
mace_write
(
ioaddr
,
MACE_PLSCC
,
0x02
);
mace_write
(
lp
,
ioaddr
,
MACE_PLSCC
,
0x02
);
break
;
case
2
:
mace_write
(
ioaddr
,
MACE_PLSCC
,
0x00
);
mace_write
(
lp
,
ioaddr
,
MACE_PLSCC
,
0x00
);
break
;
default:
mace_write
(
ioaddr
,
MACE_PHYCC
,
/* ASEL */
4
);
mace_write
(
lp
,
ioaddr
,
MACE_PHYCC
,
/* ASEL */
4
);
/* ASEL Auto Select. When set, the PORTSEL[1-0] bits are overridden,
and the MACE device will automatically select the operating media
interface port. */
break
;
}
mace_write
(
ioaddr
,
MACE_IAC
,
MACE_IAC_ADDRCHG
|
MACE_IAC_PHYADDR
);
mace_write
(
lp
,
ioaddr
,
MACE_IAC
,
MACE_IAC_ADDRCHG
|
MACE_IAC_PHYADDR
);
/* Poll ADDRCHG bit */
while
(
mace_read
(
ioaddr
,
MACE_IAC
)
&
MACE_IAC_ADDRCHG
)
;
ct
=
0
;
while
(
mace_read
(
lp
,
ioaddr
,
MACE_IAC
)
&
MACE_IAC_ADDRCHG
)
{
if
(
++
ct
>
500
)
{
printk
(
KERN_ERR
"mace: ADDRCHG timeout, card removed ?
\n
"
);
return
-
1
;
}
}
/* Set PADR register */
for
(
i
=
0
;
i
<
ETHER_ADDR_LEN
;
i
++
)
mace_write
(
ioaddr
,
MACE_PADR
,
enet_addr
[
i
]);
mace_write
(
lp
,
ioaddr
,
MACE_PADR
,
enet_addr
[
i
]);
/* MAC Configuration Control Register should be written last */
/* Let set_multicast_list set this. */
/* mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */
mace_write
(
ioaddr
,
MACE_MACCC
,
0x00
);
/* mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
0x00
);
return
0
;
}
/* mace_init */
/* ----------------------------------------------------------------------------
...
...
@@ -759,8 +780,8 @@ static void nmclan_config(dev_link_t *link)
{
char
sig
[
2
];
sig
[
0
]
=
mace_read
(
ioaddr
,
MACE_CHIPIDL
);
sig
[
1
]
=
mace_read
(
ioaddr
,
MACE_CHIPIDH
);
sig
[
0
]
=
mace_read
(
lp
,
ioaddr
,
MACE_CHIPIDL
);
sig
[
1
]
=
mace_read
(
lp
,
ioaddr
,
MACE_CHIPIDH
);
if
((
sig
[
0
]
==
0x40
)
&&
((
sig
[
1
]
&
0x0F
)
==
0x09
))
{
DEBUG
(
0
,
"nmclan_cs configured: mace id=%x %x
\n
"
,
sig
[
0
],
sig
[
1
]);
...
...
@@ -772,7 +793,8 @@ static void nmclan_config(dev_link_t *link)
}
}
mace_init
(
ioaddr
,
dev
->
dev_addr
);
if
(
mace_init
(
lp
,
ioaddr
,
dev
->
dev_addr
)
==
-
1
)
goto
failed
;
/* The if_port symbol can be set when the module is loaded */
if
(
if_port
<=
2
)
...
...
@@ -923,8 +945,8 @@ static void nmclan_reset(struct net_device *dev)
lp
->
tx_free_frames
=
AM2150_MAX_TX_FRAMES
;
/* Reinitialize the MACE chip for operation. */
mace_init
(
dev
->
base_addr
,
dev
->
dev_addr
);
mace_write
(
dev
->
base_addr
,
MACE_IMR
,
MACE_IMR_DEFAULT
);
mace_init
(
lp
,
dev
->
base_addr
,
dev
->
dev_addr
);
mace_write
(
lp
,
dev
->
base_addr
,
MACE_IMR
,
MACE_IMR_DEFAULT
);
/* Restore the multicast list and enable TX and RX. */
restore_multicast_list
(
dev
);
...
...
@@ -1456,9 +1478,9 @@ static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
{
mace_private
*
lp
=
(
mace_private
*
)
dev
->
priv
;
lp
->
mace_stats
.
rcvcc
+=
mace_read
(
ioaddr
,
MACE_RCVCC
);
lp
->
mace_stats
.
rntpc
+=
mace_read
(
ioaddr
,
MACE_RNTPC
);
lp
->
mace_stats
.
mpc
+=
mace_read
(
ioaddr
,
MACE_MPC
);
lp
->
mace_stats
.
rcvcc
+=
mace_read
(
lp
,
ioaddr
,
MACE_RCVCC
);
lp
->
mace_stats
.
rntpc
+=
mace_read
(
lp
,
ioaddr
,
MACE_RNTPC
);
lp
->
mace_stats
.
mpc
+=
mace_read
(
lp
,
ioaddr
,
MACE_MPC
);
/* At this point, mace_stats is fully updated for this call.
We may now update the linux_stats. */
...
...
@@ -1608,30 +1630,30 @@ static void restore_multicast_list(struct net_device *dev)
DEBUG
(
1
,
"Attempt to restore multicast list detected.
\n
"
);
mace_write
(
ioaddr
,
MACE_IAC
,
MACE_IAC_ADDRCHG
|
MACE_IAC_LOGADDR
);
mace_write
(
lp
,
ioaddr
,
MACE_IAC
,
MACE_IAC_ADDRCHG
|
MACE_IAC_LOGADDR
);
/* Poll ADDRCHG bit */
while
(
mace_read
(
ioaddr
,
MACE_IAC
)
&
MACE_IAC_ADDRCHG
)
while
(
mace_read
(
lp
,
ioaddr
,
MACE_IAC
)
&
MACE_IAC_ADDRCHG
)
;
/* Set LADRF register */
for
(
i
=
0
;
i
<
MACE_LADRF_LEN
;
i
++
)
mace_write
(
ioaddr
,
MACE_LADRF
,
ladrf
[
i
]);
mace_write
(
lp
,
ioaddr
,
MACE_LADRF
,
ladrf
[
i
]);
mace_write
(
ioaddr
,
MACE_UTR
,
MACE_UTR_RCVFCSE
|
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
mace_write
(
lp
,
ioaddr
,
MACE_UTR
,
MACE_UTR_RCVFCSE
|
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
}
else
if
(
num_addrs
<
0
)
{
/* Promiscuous mode: receive all packets */
mace_write
(
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
ioaddr
,
MACE_MACCC
,
mace_write
(
lp
,
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
MACE_MACCC_PROM
|
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
}
else
{
/* Normal mode */
mace_write
(
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
mace_write
(
lp
,
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
}
}
/* restore_multicast_list */
...
...
@@ -1691,20 +1713,21 @@ static void set_multicast_list(struct net_device *dev)
static
void
restore_multicast_list
(
struct
net_device
*
dev
)
{
ioaddr_t
ioaddr
=
dev
->
base_addr
;
mace_private
*
lp
=
(
mace_private
*
)
dev
->
priv
;
DEBUG
(
2
,
"%s: restoring Rx mode to %d addresses.
\n
"
,
dev
->
name
,
((
mace_private
*
)(
dev
->
priv
))
->
multicast_num_addrs
);
if
(
dev
->
flags
&
IFF_PROMISC
)
{
/* Promiscuous mode: receive all packets */
mace_write
(
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
ioaddr
,
MACE_MACCC
,
mace_write
(
lp
,
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
MACE_MACCC_PROM
|
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
}
else
{
/* Normal mode */
mace_write
(
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
mace_write
(
lp
,
ioaddr
,
MACE_UTR
,
MACE_UTR_LOOP_EXTERNAL
);
mace_write
(
lp
,
ioaddr
,
MACE_MACCC
,
MACE_MACCC_ENXMT
|
MACE_MACCC_ENRCV
);
}
}
/* restore_multicast_list */
...
...
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