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
9b425022
Commit
9b425022
authored
Oct 11, 2002
by
Zwane Mwaikambo
Committed by
Jeff Garzik
Oct 11, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ethtool media support to smc91c92_cs net driver.
Also fixes a bug when UTP port is unplugged.
parent
eda607d8
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
228 additions
and
25 deletions
+228
-25
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/smc91c92_cs.c
+228
-25
No files found.
drivers/net/pcmcia/smc91c92_cs.c
View file @
9b425022
...
...
@@ -8,7 +8,7 @@
Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
smc91c92_cs.c 1.
113 2001/10/13 00:08:53
smc91c92_cs.c 1.
2 2002/09/28 15:00:00
This driver contains code written by Donald Becker
(becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
...
...
@@ -37,12 +37,15 @@
#include <linux/crc32.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
...
...
@@ -88,6 +91,9 @@ static const char *version =
#define DEBUG(n, args...)
#endif
#define DRV_NAME "smc91c92_cs"
#define DRV_VERSION "1.2"
/*====================================================================*/
/* Operational parameter that usually are not changed. */
...
...
@@ -109,6 +115,7 @@ static dev_link_t *dev_list;
struct
smc_private
{
dev_link_t
link
;
struct
net_device
dev
;
spinlock_t
lock
;
u_short
manfid
;
u_short
cardid
;
struct
net_device_stats
stats
;
...
...
@@ -122,7 +129,7 @@ struct smc_private {
u_short
media_status
;
u_short
fast_poll
;
u_short
link_status
;
int
phy_id
;
struct
mii_if_info
mii_if
;
};
/* Special definitions for Megahertz multifunction cards */
...
...
@@ -292,9 +299,11 @@ static int s9k_config(struct net_device *dev, struct ifmap *map);
static
void
smc_set_xcvr
(
struct
net_device
*
dev
,
int
if_port
);
static
void
smc_reset
(
struct
net_device
*
dev
);
static
void
media_check
(
u_long
arg
);
static
void
mdio_sync
(
ioaddr_t
addr
);
static
int
mdio_read
(
ioaddr_t
addr
,
int
phy_id
,
int
loc
);
static
void
mdio_write
(
ioaddr_t
addr
,
int
phy_id
,
int
loc
,
int
value
);
static
void
smc_mdio_sync
(
ioaddr_t
addr
);
static
int
smc_mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
loc
);
static
void
smc_mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
loc
,
int
value
);
static
int
smc_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
);
static
int
smc_link_ok
(
struct
net_device
*
dev
);
/*======================================================================
...
...
@@ -346,7 +355,7 @@ static dev_link_t *smc91c92_attach(void)
if
(
!
smc
)
return
NULL
;
memset
(
smc
,
0
,
sizeof
(
struct
smc_private
));
link
=
&
smc
->
link
;
dev
=
&
smc
->
dev
;
spin_lock_init
(
&
smc
->
lock
);
link
->
release
.
function
=
&
smc91c92_release
;
link
->
release
.
data
=
(
u_long
)
link
;
link
->
io
.
NumPorts1
=
16
;
...
...
@@ -369,6 +378,7 @@ static dev_link_t *smc91c92_attach(void)
dev
->
get_stats
=
&
smc91c92_get_stats
;
dev
->
set_config
=
&
s9k_config
;
dev
->
set_multicast_list
=
&
set_rx_mode
;
dev
->
do_ioctl
=
&
smc_ioctl
;
ether_setup
(
dev
);
dev
->
open
=
&
smc91c92_open
;
dev
->
stop
=
&
smc91c92_close
;
...
...
@@ -378,6 +388,12 @@ static dev_link_t *smc91c92_attach(void)
#endif
dev
->
priv
=
link
->
priv
=
link
->
irq
.
Instance
=
smc
;
smc
->
mii_if
.
dev
=
dev
;
smc
->
mii_if
.
mdio_read
=
smc_mdio_read
;
smc
->
mii_if
.
mdio_write
=
smc_mdio_write
;
smc
->
mii_if
.
phy_id_mask
=
0x1f
;
smc
->
mii_if
.
reg_num_mask
=
0x1f
;
/* Register with Card Services */
link
->
next
=
dev_list
;
dev_list
=
link
;
...
...
@@ -1044,10 +1060,10 @@ static void smc91c92_config(dev_link_t *link)
SMC_SELECT_BANK
(
3
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
j
=
mdio_read
(
dev
->
base_addr
+
MGMT
,
i
,
1
);
j
=
smc_mdio_read
(
dev
,
i
,
1
);
if
((
j
!=
0
)
&&
(
j
!=
0xffff
))
break
;
}
smc
->
phy_id
=
(
i
<
32
)
?
i
:
-
1
;
smc
->
mii_if
.
phy_id
=
(
i
<
32
)
?
i
:
-
1
;
if
(
i
<
32
)
{
DEBUG
(
0
,
" MII transceiver at index %d, status %x.
\n
"
,
i
,
j
);
}
else
{
...
...
@@ -1190,7 +1206,7 @@ static int smc91c92_event(event_t event, int priority,
#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
#define MDIO_DATA_READ 0x02
static
void
mdio_sync
(
ioaddr_t
addr
)
static
void
smc_
mdio_sync
(
ioaddr_t
addr
)
{
int
bits
;
for
(
bits
=
0
;
bits
<
32
;
bits
++
)
{
...
...
@@ -1199,12 +1215,13 @@ static void mdio_sync(ioaddr_t addr)
}
}
static
int
mdio_read
(
ioaddr_t
addr
,
int
phy_id
,
int
loc
)
static
int
smc_mdio_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
loc
)
{
ioaddr_t
addr
=
dev
->
base_addr
+
MGMT
;
u_int
cmd
=
(
0x06
<<
10
)
|
(
phy_id
<<
5
)
|
loc
;
int
i
,
retval
=
0
;
mdio_sync
(
addr
);
smc_
mdio_sync
(
addr
);
for
(
i
=
13
;
i
>=
0
;
i
--
)
{
int
dat
=
(
cmd
&
(
1
<<
i
))
?
MDIO_DATA_WRITE1
:
MDIO_DATA_WRITE0
;
outb
(
dat
,
addr
);
...
...
@@ -1218,12 +1235,13 @@ static int mdio_read(ioaddr_t addr, int phy_id, int loc)
return
(
retval
>>
1
)
&
0xffff
;
}
static
void
mdio_write
(
ioaddr_t
addr
,
int
phy_id
,
int
loc
,
int
value
)
static
void
smc_mdio_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
loc
,
int
value
)
{
ioaddr_t
addr
=
dev
->
base_addr
+
MGMT
;
u_int
cmd
=
(
0x05
<<
28
)
|
(
phy_id
<<
23
)
|
(
loc
<<
18
)
|
(
1
<<
17
)
|
value
;
int
i
;
mdio_sync
(
addr
);
smc_
mdio_sync
(
addr
);
for
(
i
=
31
;
i
>=
0
;
i
--
)
{
int
dat
=
(
cmd
&
(
1
<<
i
))
?
MDIO_DATA_WRITE1
:
MDIO_DATA_WRITE0
;
outb
(
dat
,
addr
);
...
...
@@ -1777,6 +1795,7 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
static
void
set_rx_mode
(
struct
net_device
*
dev
)
{
ioaddr_t
ioaddr
=
dev
->
base_addr
;
struct
smc_private
*
smc
=
dev
->
priv
;
u_int
multicast_table
[
2
]
=
{
0
,
};
unsigned
long
flags
;
u_short
rx_cfg_setting
;
...
...
@@ -1795,15 +1814,14 @@ static void set_rx_mode(struct net_device *dev)
}
/* Load MC table and Rx setting into the chip without interrupts. */
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
smc
->
lock
,
flags
);
SMC_SELECT_BANK
(
3
);
outl
(
multicast_table
[
0
],
ioaddr
+
MULTICAST0
);
outl
(
multicast_table
[
1
],
ioaddr
+
MULTICAST4
);
SMC_SELECT_BANK
(
0
);
outw
(
rx_cfg_setting
,
ioaddr
+
RCR
);
SMC_SELECT_BANK
(
2
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
smc
->
lock
,
flags
);
return
;
}
...
...
@@ -1917,11 +1935,11 @@ static void smc_reset(struct net_device *dev)
SMC_SELECT_BANK
(
3
);
/* Reset MII */
mdio_write
(
ioaddr
+
MGMT
,
smc
->
phy_id
,
0
,
0x8000
);
smc_mdio_write
(
dev
,
smc
->
mii_if
.
phy_id
,
0
,
0x8000
);
/* Restart MII autonegotiation */
mdio_write
(
ioaddr
+
MGMT
,
smc
->
phy_id
,
0
,
0x0000
);
mdio_write
(
ioaddr
+
MGMT
,
smc
->
phy_id
,
0
,
0x1200
);
smc_mdio_write
(
dev
,
smc
->
mii_if
.
phy_id
,
0
,
0x0000
);
smc_mdio_write
(
dev
,
smc
->
mii_if
.
phy_id
,
0
,
0x1200
);
}
/* Enable interrupts. */
...
...
@@ -1942,7 +1960,6 @@ static void media_check(u_long arg)
struct
net_device
*
dev
=
&
smc
->
dev
;
ioaddr_t
ioaddr
=
dev
->
base_addr
;
u_short
i
,
media
,
saved_bank
;
ioaddr_t
mii_addr
=
dev
->
base_addr
+
MGMT
;
u_short
link
;
saved_bank
=
inw
(
ioaddr
+
BANK_SELECT
);
...
...
@@ -1974,20 +1991,20 @@ static void media_check(u_long arg)
}
if
(
smc
->
cfg
&
CFG_MII_SELECT
)
{
if
(
smc
->
phy_id
<
0
)
if
(
smc
->
mii_if
.
phy_id
<
0
)
goto
reschedule
;
SMC_SELECT_BANK
(
3
);
link
=
mdio_read
(
mii_addr
,
smc
->
phy_id
,
1
);
link
=
smc_mdio_read
(
dev
,
smc
->
mii_if
.
phy_id
,
1
);
if
(
!
link
||
(
link
==
0xffff
))
{
printk
(
KERN_INFO
"%s: MII is missing!
\n
"
,
dev
->
name
);
smc
->
phy_id
=
-
1
;
smc
->
mii_if
.
phy_id
=
-
1
;
goto
reschedule
;
}
link
&=
0x0004
;
if
(
link
!=
smc
->
link_status
)
{
u_short
p
=
mdio_read
(
mii_addr
,
smc
->
phy_id
,
5
);
u_short
p
=
smc_mdio_read
(
dev
,
smc
->
mii_if
.
phy_id
,
5
);
printk
(
KERN_INFO
"%s: %s link beat
\n
"
,
dev
->
name
,
(
link
)
?
"found"
:
"lost"
);
if
(
link
)
{
...
...
@@ -2043,6 +2060,191 @@ static void media_check(u_long arg)
SMC_SELECT_BANK
(
saved_bank
);
}
static
int
smc_link_ok
(
struct
net_device
*
dev
)
{
ioaddr_t
ioaddr
=
dev
->
base_addr
;
struct
smc_private
*
smc
=
dev
->
priv
;
if
(
smc
->
cfg
&
CFG_MII_SELECT
)
{
return
mii_link_ok
(
&
smc
->
mii_if
);
}
else
{
SMC_SELECT_BANK
(
0
);
return
inw
(
ioaddr
+
EPH
)
&
EPH_LINK_OK
;
}
}
static
int
smc_netdev_get_ecmd
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
ecmd
)
{
u16
tmp
;
ioaddr_t
ioaddr
=
dev
->
base_addr
;
ecmd
->
supported
=
(
SUPPORTED_TP
|
SUPPORTED_AUI
|
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
);
SMC_SELECT_BANK
(
1
);
tmp
=
inw
(
ioaddr
+
CONFIG
);
ecmd
->
port
=
(
tmp
&
CFG_AUI_SELECT
)
?
PORT_AUI
:
PORT_TP
;
ecmd
->
transceiver
=
XCVR_INTERNAL
;
ecmd
->
speed
=
SPEED_10
;
ecmd
->
phy_address
=
ioaddr
+
MGMT
;
SMC_SELECT_BANK
(
0
);
tmp
=
inw
(
ioaddr
+
TCR
);
ecmd
->
duplex
=
(
tmp
&
TCR_FDUPLX
)
?
DUPLEX_FULL
:
DUPLEX_HALF
;
return
0
;
}
static
int
smc_netdev_set_ecmd
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
ecmd
)
{
u16
tmp
;
ioaddr_t
ioaddr
=
dev
->
base_addr
;
if
(
ecmd
->
speed
!=
SPEED_10
)
return
-
EINVAL
;
if
(
ecmd
->
duplex
!=
DUPLEX_HALF
&&
ecmd
->
duplex
!=
DUPLEX_FULL
)
return
-
EINVAL
;
if
(
ecmd
->
port
!=
PORT_TP
&&
ecmd
->
port
!=
PORT_AUI
)
return
-
EINVAL
;
if
(
ecmd
->
transceiver
!=
XCVR_INTERNAL
)
return
-
EINVAL
;
if
(
ecmd
->
port
==
PORT_AUI
)
smc_set_xcvr
(
dev
,
1
);
else
smc_set_xcvr
(
dev
,
0
);
SMC_SELECT_BANK
(
0
);
tmp
=
inw
(
ioaddr
+
TCR
);
if
(
ecmd
->
duplex
==
DUPLEX_FULL
)
tmp
|=
TCR_FDUPLX
;
else
tmp
&=
~
TCR_FDUPLX
;
outw
(
ioaddr
+
TCR
,
tmp
);
return
0
;
}
static
int
smc_ethtool_ioctl
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
u32
ethcmd
;
struct
smc_private
*
smc
=
dev
->
priv
;
if
(
get_user
(
ethcmd
,
(
u32
*
)
useraddr
))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GDRVINFO
:
{
struct
ethtool_drvinfo
info
=
{
ETHTOOL_GDRVINFO
};
strcpy
(
info
.
driver
,
DRV_NAME
);
strcpy
(
info
.
version
,
DRV_VERSION
);
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
/* get settings */
case
ETHTOOL_GSET
:
{
int
ret
;
struct
ethtool_cmd
ecmd
=
{
ETHTOOL_GSET
};
spin_lock_irq
(
&
smc
->
lock
);
if
(
smc
->
cfg
&
CFG_MII_SELECT
)
ret
=
mii_ethtool_gset
(
&
smc
->
mii_if
,
&
ecmd
);
else
ret
=
smc_netdev_get_ecmd
(
dev
,
&
ecmd
);
spin_unlock_irq
(
&
smc
->
lock
);
if
(
copy_to_user
(
useraddr
,
&
ecmd
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
return
ret
;
}
/* set settings */
case
ETHTOOL_SSET
:
{
int
ret
;
struct
ethtool_cmd
ecmd
;
if
(
copy_from_user
(
&
ecmd
,
useraddr
,
sizeof
(
ecmd
)))
return
-
EFAULT
;
spin_lock_irq
(
&
smc
->
lock
);
if
(
smc
->
cfg
&
CFG_MII_SELECT
)
ret
=
mii_ethtool_sset
(
&
smc
->
mii_if
,
&
ecmd
);
else
ret
=
smc_netdev_set_ecmd
(
dev
,
&
ecmd
);
spin_unlock_irq
(
&
smc
->
lock
);
return
ret
;
}
/* get link status */
case
ETHTOOL_GLINK
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
spin_lock_irq
(
&
smc
->
lock
);
edata
.
data
=
smc_link_ok
(
dev
);
spin_unlock_irq
(
&
smc
->
lock
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
#ifdef PCMCIA_DEBUG
/* get message-level */
case
ETHTOOL_GMSGLVL
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GMSGLVL
};
edata
.
data
=
pc_debug
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
/* set message-level */
case
ETHTOOL_SMSGLVL
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
pc_debug
=
edata
.
data
;
return
0
;
}
#endif
/* restart autonegotiation */
case
ETHTOOL_NWAY_RST
:
{
if
(
smc
->
cfg
&
CFG_MII_SELECT
)
return
mii_nway_restart
(
&
smc
->
mii_if
);
else
return
-
EOPNOTSUPP
;
}
default:
break
;
}
return
-
EOPNOTSUPP
;
}
static
int
smc_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
smc_private
*
smc
=
dev
->
priv
;
struct
mii_ioctl_data
*
mii
;
int
rc
=
0
;
mii
=
(
struct
mii_ioctl_data
*
)
&
rq
->
ifr_data
;
if
(
!
netif_running
(
dev
))
return
-
EINVAL
;
switch
(
cmd
)
{
case
SIOCETHTOOL
:
rc
=
smc_ethtool_ioctl
(
dev
,
(
void
*
)
rq
->
ifr_data
);
break
;
default:
spin_lock_irq
(
&
smc
->
lock
);
rc
=
generic_mii_ioctl
(
&
smc
->
mii_if
,
mii
,
cmd
,
NULL
);
spin_unlock_irq
(
&
smc
->
lock
);
break
;
}
return
rc
;
}
/*====================================================================*/
static
int
__init
init_smc91c92_cs
(
void
)
...
...
@@ -2069,3 +2271,4 @@ static void __exit exit_smc91c92_cs(void)
module_init
(
init_smc91c92_cs
);
module_exit
(
exit_smc91c92_cs
);
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