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
86635435
Commit
86635435
authored
Aug 17, 2003
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/garz/repo/linus-2.6
into redhat.com:/garz/repo/ethtool-2.6
parents
03e4e085
5db6f5c4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1072 additions
and
384 deletions
+1072
-384
drivers/net/tg3.c
drivers/net/tg3.c
+279
-377
include/linux/ethtool.h
include/linux/ethtool.h
+97
-2
include/linux/netdevice.h
include/linux/netdevice.h
+8
-1
net/core/Makefile
net/core/Makefile
+2
-2
net/core/dev.c
net/core/dev.c
+14
-2
net/core/ethtool.c
net/core/ethtool.c
+672
-0
No files found.
drivers/net/tg3.c
View file @
86635435
...
...
@@ -5051,16 +5051,20 @@ static void tg3_set_rx_mode(struct net_device *dev)
#define TG3_REGDUMP_LEN (32 * 1024)
static
u8
*
tg3_get_regs
(
struct
tg3
*
tp
)
static
int
tg3_get_regs_len
(
struct
net_device
*
dev
)
{
u8
*
orig_p
=
kmalloc
(
TG3_REGDUMP_LEN
,
GFP_KERNEL
);
u8
*
p
;
return
TG3_REGDUMP_LEN
;
}
static
void
tg3_get_regs
(
struct
net_device
*
dev
,
struct
ethtool_regs
*
regs
,
void
*
p
)
{
struct
tg3
*
tp
=
dev
->
priv
;
u8
*
orig_p
=
p
;
int
i
;
if
(
orig_p
==
NULL
)
return
NULL
;
regs
->
version
=
0
;
memset
(
orig_
p
,
0
,
TG3_REGDUMP_LEN
);
memset
(
p
,
0
,
TG3_REGDUMP_LEN
);
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
...
...
@@ -5114,388 +5118,263 @@ do { p = orig_p + (reg); \
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
return
orig_p
;
}
static
int
tg3_
ethtool_ioctl
(
struct
net_device
*
dev
,
void
*
useraddr
)
static
int
tg3_
get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
tg3
*
tp
=
dev
->
priv
;
struct
pci_dev
*
pci_dev
=
tp
->
pdev
;
u32
ethcmd
;
if
(
copy_from_user
(
&
ethcmd
,
useraddr
,
sizeof
(
ethcmd
)))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GDRVINFO
:{
struct
ethtool_drvinfo
info
=
{
ETHTOOL_GDRVINFO
};
strcpy
(
info
.
driver
,
DRV_MODULE_NAME
);
strcpy
(
info
.
version
,
DRV_MODULE_VERSION
);
memset
(
&
info
.
fw_version
,
0
,
sizeof
(
info
.
fw_version
));
strcpy
(
info
.
bus_info
,
pci_name
(
pci_dev
));
info
.
eedump_len
=
0
;
info
.
regdump_len
=
TG3_REGDUMP_LEN
;
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_GSET
:
{
struct
ethtool_cmd
cmd
=
{
ETHTOOL_GSET
};
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
||
tp
->
link_config
.
phy_is_low_power
)
return
-
EAGAIN
;
cmd
.
supported
=
(
SUPPORTED_Autoneg
);
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_10_100_ONLY
))
cmd
.
supported
|=
(
SUPPORTED_1000baseT_Half
|
SUPPORTED_1000baseT_Full
);
if
(
tp
->
phy_id
!=
PHY_ID_SERDES
)
cmd
.
supported
|=
(
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_MII
);
else
cmd
.
supported
|=
SUPPORTED_FIBRE
;
cmd
.
advertising
=
tp
->
link_config
.
advertising
;
cmd
.
speed
=
tp
->
link_config
.
active_speed
;
cmd
.
duplex
=
tp
->
link_config
.
active_duplex
;
cmd
.
port
=
0
;
cmd
.
phy_address
=
PHY_ADDR
;
cmd
.
transceiver
=
0
;
cmd
.
autoneg
=
tp
->
link_config
.
autoneg
;
cmd
.
maxtxpkt
=
0
;
cmd
.
maxrxpkt
=
0
;
if
(
copy_to_user
(
useraddr
,
&
cmd
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SSET
:
{
struct
ethtool_cmd
cmd
;
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
||
tp
->
link_config
.
phy_is_low_power
)
return
-
EAGAIN
;
if
(
copy_from_user
(
&
cmd
,
useraddr
,
sizeof
(
cmd
)))
return
-
EFAULT
;
/* Fiber PHY only supports 1000 full/half */
if
(
cmd
.
autoneg
==
AUTONEG_ENABLE
)
{
if
(
tp
->
phy_id
==
PHY_ID_SERDES
&&
(
cmd
.
advertising
&
(
ADVERTISED_10baseT_Half
|
ADVERTISED_10baseT_Full
|
ADVERTISED_100baseT_Half
|
ADVERTISED_100baseT_Full
)))
return
-
EINVAL
;
if
((
tp
->
tg3_flags
&
TG3_FLAG_10_100_ONLY
)
&&
(
cmd
.
advertising
&
(
ADVERTISED_1000baseT_Half
|
ADVERTISED_1000baseT_Full
)))
return
-
EINVAL
;
}
else
{
if
(
tp
->
phy_id
==
PHY_ID_SERDES
&&
(
cmd
.
speed
==
SPEED_10
||
cmd
.
speed
==
SPEED_100
))
return
-
EINVAL
;
if
((
tp
->
tg3_flags
&
TG3_FLAG_10_100_ONLY
)
&&
(
cmd
.
speed
==
SPEED_10
||
cmd
.
speed
==
SPEED_100
))
return
-
EINVAL
;
}
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
tp
->
link_config
.
autoneg
=
cmd
.
autoneg
;
if
(
cmd
.
autoneg
==
AUTONEG_ENABLE
)
{
tp
->
link_config
.
advertising
=
cmd
.
advertising
;
tp
->
link_config
.
speed
=
SPEED_INVALID
;
tp
->
link_config
.
duplex
=
DUPLEX_INVALID
;
}
else
{
tp
->
link_config
.
speed
=
cmd
.
speed
;
tp
->
link_config
.
duplex
=
cmd
.
duplex
;
}
tg3_setup_phy
(
tp
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
case
ETHTOOL_GREGS
:
{
struct
ethtool_regs
regs
;
u8
*
regbuf
;
int
ret
;
struct
tg3
*
tp
=
dev
->
priv
;
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
||
tp
->
link_config
.
phy_is_low_power
)
return
-
EAGAIN
;
if
(
copy_from_user
(
&
regs
,
useraddr
,
sizeof
(
regs
)))
return
-
EFAULT
;
if
(
regs
.
len
>
TG3_REGDUMP_LEN
)
regs
.
len
=
TG3_REGDUMP_LEN
;
regs
.
version
=
0
;
if
(
copy_to_user
(
useraddr
,
&
regs
,
sizeof
(
regs
)))
return
-
EFAULT
;
cmd
->
supported
=
(
SUPPORTED_Autoneg
);
regbuf
=
tg3_get_regs
(
tp
);
if
(
!
regbuf
)
return
-
ENOMEM
;
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_10_100_ONLY
))
cmd
->
supported
|=
(
SUPPORTED_1000baseT_Half
|
SUPPORTED_1000baseT_Full
)
;
useraddr
+=
offsetof
(
struct
ethtool_regs
,
data
);
ret
=
0
;
if
(
copy_to_user
(
useraddr
,
regbuf
,
regs
.
len
))
ret
=
-
EFAULT
;
kfree
(
regbuf
);
return
ret
;
}
case
ETHTOOL_GWOL
:
{
struct
ethtool_wolinfo
wol
=
{
ETHTOOL_GWOL
};
if
(
tp
->
phy_id
!=
PHY_ID_SERDES
)
cmd
->
supported
|=
(
SUPPORTED_100baseT_Half
|
SUPPORTED_100baseT_Full
|
SUPPORTED_10baseT_Half
|
SUPPORTED_10baseT_Full
|
SUPPORTED_MII
);
else
cmd
->
supported
|=
SUPPORTED_FIBRE
;
cmd
->
advertising
=
tp
->
link_config
.
advertising
;
cmd
->
speed
=
tp
->
link_config
.
active_speed
;
cmd
->
duplex
=
tp
->
link_config
.
active_duplex
;
cmd
->
port
=
0
;
cmd
->
phy_address
=
PHY_ADDR
;
cmd
->
transceiver
=
0
;
cmd
->
autoneg
=
tp
->
link_config
.
autoneg
;
cmd
->
maxtxpkt
=
0
;
cmd
->
maxrxpkt
=
0
;
return
0
;
}
static
int
tg3_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
tg3
*
tp
=
dev
->
priv
;
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
||
tp
->
link_config
.
phy_is_low_power
)
return
-
EAGAIN
;
wol
.
supported
=
WAKE_MAGIC
;
wol
.
wolopts
=
0
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)
wol
.
wolopts
=
WAKE_MAGIC
;
memset
(
&
wol
.
sopass
,
0
,
sizeof
(
wol
.
sopass
));
if
(
copy_to_user
(
useraddr
,
&
wol
,
sizeof
(
wol
)))
return
-
EFAULT
;
return
0
;
if
(
cmd
->
autoneg
==
AUTONEG_ENABLE
)
{
tp
->
link_config
.
advertising
=
cmd
->
advertising
;
tp
->
link_config
.
speed
=
SPEED_INVALID
;
tp
->
link_config
.
duplex
=
DUPLEX_INVALID
;
}
else
{
tp
->
link_config
.
speed
=
cmd
->
speed
;
tp
->
link_config
.
duplex
=
cmd
->
duplex
;
}
tg3_setup_phy
(
tp
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
static
void
tg3_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
struct
tg3
*
tp
=
dev
->
priv
;
strcpy
(
info
->
driver
,
DRV_MODULE_NAME
);
strcpy
(
info
->
version
,
DRV_MODULE_VERSION
);
strcpy
(
info
->
bus_info
,
pci_name
(
tp
->
pdev
));
}
static
void
tg3_get_wol
(
struct
net_device
*
dev
,
struct
ethtool_wolinfo
*
wol
)
{
struct
tg3
*
tp
=
dev
->
priv
;
wol
->
supported
=
WAKE_MAGIC
;
wol
->
wolopts
=
0
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)
wol
->
wolopts
=
WAKE_MAGIC
;
memset
(
&
wol
->
sopass
,
0
,
sizeof
(
wol
->
sopass
));
}
static
int
tg3_set_wol
(
struct
net_device
*
dev
,
struct
ethtool_wolinfo
*
wol
)
{
struct
tg3
*
tp
=
dev
->
priv
;
if
(
wol
->
wolopts
&
~
WAKE_MAGIC
)
return
-
EINVAL
;
if
((
wol
->
wolopts
&
WAKE_MAGIC
)
&&
tp
->
phy_id
==
PHY_ID_SERDES
&&
!
(
tp
->
tg3_flags
&
TG3_FLAG_SERDES_WOL_CAP
))
return
-
EINVAL
;
spin_lock_irq
(
&
tp
->
lock
);
if
(
wol
->
wolopts
&
WAKE_MAGIC
)
tp
->
tg3_flags
|=
TG3_FLAG_WOL_ENABLE
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_WOL_ENABLE
;
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
static
u32
tg3_get_msglevel
(
struct
net_device
*
dev
)
{
struct
tg3
*
tp
=
dev
->
priv
;
return
tp
->
msg_enable
;
}
static
void
tg3_set_msglevel
(
struct
net_device
*
dev
,
u32
value
)
{
struct
tg3
*
tp
=
dev
->
priv
;
tp
->
msg_enable
=
value
;
}
static
int
tg3_nway_reset
(
struct
net_device
*
dev
)
{
struct
tg3
*
tp
=
dev
->
priv
;
u32
bmcr
;
int
r
;
spin_lock_irq
(
&
tp
->
lock
);
tg3_readphy
(
tp
,
MII_BMCR
,
&
bmcr
);
tg3_readphy
(
tp
,
MII_BMCR
,
&
bmcr
);
r
=
-
EINVAL
;
if
(
bmcr
&
BMCR_ANENABLE
)
{
tg3_writephy
(
tp
,
MII_BMCR
,
bmcr
|
BMCR_ANRESTART
);
r
=
0
;
}
case
ETHTOOL_SWOL
:
{
struct
ethtool_wolinfo
wol
;
spin_unlock_irq
(
&
tp
->
lock
);
return
r
;
}
static
void
tg3_get_ringparam
(
struct
net_device
*
dev
,
struct
ethtool_ringparam
*
ering
)
{
struct
tg3
*
tp
=
dev
->
priv
;
ering
->
rx_max_pending
=
TG3_RX_RING_SIZE
-
1
;
ering
->
rx_mini_max_pending
=
0
;
ering
->
rx_jumbo_max_pending
=
TG3_RX_JUMBO_RING_SIZE
-
1
;
ering
->
rx_pending
=
tp
->
rx_pending
;
ering
->
rx_mini_pending
=
0
;
ering
->
rx_jumbo_pending
=
tp
->
rx_jumbo_pending
;
ering
->
tx_pending
=
tp
->
tx_pending
;
}
static
int
tg3_set_ringparam
(
struct
net_device
*
dev
,
struct
ethtool_ringparam
*
ering
)
{
struct
tg3
*
tp
=
dev
->
priv
;
if
((
ering
->
rx_pending
>
TG3_RX_RING_SIZE
-
1
)
||
(
ering
->
rx_jumbo_pending
>
TG3_RX_JUMBO_RING_SIZE
-
1
)
||
(
ering
->
tx_pending
>
TG3_TX_RING_SIZE
-
1
))
return
-
EINVAL
;
tg3_netif_stop
(
tp
);
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
tp
->
rx_pending
=
ering
->
rx_pending
;
tp
->
rx_jumbo_pending
=
ering
->
rx_jumbo_pending
;
tp
->
tx_pending
=
ering
->
tx_pending
;
if
(
copy_from_user
(
&
wol
,
useraddr
,
sizeof
(
wol
)))
return
-
EFAULT
;
if
(
wol
.
wolopts
&
~
WAKE_MAGIC
)
return
-
EINVAL
;
if
((
wol
.
wolopts
&
WAKE_MAGIC
)
&&
tp
->
phy_id
==
PHY_ID_SERDES
&&
!
(
tp
->
tg3_flags
&
TG3_FLAG_SERDES_WOL_CAP
))
tg3_halt
(
tp
);
tg3_init_rings
(
tp
);
tg3_init_hw
(
tp
);
netif_wake_queue
(
tp
->
dev
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
tg3_netif_start
(
tp
);
return
0
;
}
static
void
tg3_get_pauseparam
(
struct
net_device
*
dev
,
struct
ethtool_pauseparam
*
epause
)
{
struct
tg3
*
tp
=
dev
->
priv
;
epause
->
autoneg
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_AUTONEG
)
!=
0
;
epause
->
rx_pause
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_RX
)
!=
0
;
epause
->
tx_pause
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_TX
)
!=
0
;
}
static
int
tg3_set_pauseparam
(
struct
net_device
*
dev
,
struct
ethtool_pauseparam
*
epause
)
{
struct
tg3
*
tp
=
dev
->
priv
;
tg3_netif_stop
(
tp
);
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
if
(
epause
->
autoneg
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_AUTONEG
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_AUTONEG
;
if
(
epause
->
rx_pause
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_RX
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_RX
;
if
(
epause
->
tx_pause
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_TX
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_TX
;
tg3_halt
(
tp
);
tg3_init_rings
(
tp
);
tg3_init_hw
(
tp
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
tg3_netif_start
(
tp
);
return
0
;
}
static
u32
tg3_get_rx_csum
(
struct
net_device
*
dev
)
{
struct
tg3
*
tp
=
dev
->
priv
;
return
(
tp
->
tg3_flags
&
TG3_FLAG_RX_CHECKSUMS
)
!=
0
;
}
static
int
tg3_set_rx_csum
(
struct
net_device
*
dev
,
u32
data
)
{
struct
tg3
*
tp
=
dev
->
priv
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_BROKEN_CHECKSUMS
)
{
if
(
data
!=
0
)
return
-
EINVAL
;
spin_lock_irq
(
&
tp
->
lock
);
if
(
wol
.
wolopts
&
WAKE_MAGIC
)
tp
->
tg3_flags
|=
TG3_FLAG_WOL_ENABLE
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_WOL_ENABLE
;
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
case
ETHTOOL_GMSGLVL
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GMSGLVL
};
edata
.
data
=
tp
->
msg_enable
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SMSGLVL
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
tp
->
msg_enable
=
edata
.
data
;
return
0
;
}
case
ETHTOOL_NWAY_RST
:
{
u32
bmcr
;
int
r
;
spin_lock_irq
(
&
tp
->
lock
);
tg3_readphy
(
tp
,
MII_BMCR
,
&
bmcr
);
tg3_readphy
(
tp
,
MII_BMCR
,
&
bmcr
);
r
=
-
EINVAL
;
if
(
bmcr
&
BMCR_ANENABLE
)
{
tg3_writephy
(
tp
,
MII_BMCR
,
bmcr
|
BMCR_ANRESTART
);
r
=
0
;
}
spin_unlock_irq
(
&
tp
->
lock
);
return
r
;
}
case
ETHTOOL_GLINK
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
edata
.
data
=
netif_carrier_ok
(
tp
->
dev
)
?
1
:
0
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_GRINGPARAM
:
{
struct
ethtool_ringparam
ering
=
{
ETHTOOL_GRINGPARAM
};
ering
.
rx_max_pending
=
TG3_RX_RING_SIZE
-
1
;
ering
.
rx_mini_max_pending
=
0
;
ering
.
rx_jumbo_max_pending
=
TG3_RX_JUMBO_RING_SIZE
-
1
;
ering
.
rx_pending
=
tp
->
rx_pending
;
ering
.
rx_mini_pending
=
0
;
ering
.
rx_jumbo_pending
=
tp
->
rx_jumbo_pending
;
ering
.
tx_pending
=
tp
->
tx_pending
;
if
(
copy_to_user
(
useraddr
,
&
ering
,
sizeof
(
ering
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SRINGPARAM
:
{
struct
ethtool_ringparam
ering
;
if
(
copy_from_user
(
&
ering
,
useraddr
,
sizeof
(
ering
)))
return
-
EFAULT
;
if
((
ering
.
rx_pending
>
TG3_RX_RING_SIZE
-
1
)
||
(
ering
.
rx_jumbo_pending
>
TG3_RX_JUMBO_RING_SIZE
-
1
)
||
(
ering
.
tx_pending
>
TG3_TX_RING_SIZE
-
1
))
return
0
;
}
spin_lock_irq
(
&
tp
->
lock
);
if
(
data
)
tp
->
tg3_flags
|=
TG3_FLAG_RX_CHECKSUMS
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_RX_CHECKSUMS
;
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
static
int
tg3_set_tx_csum
(
struct
net_device
*
dev
,
u32
data
)
{
struct
tg3
*
tp
=
dev
->
priv
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_BROKEN_CHECKSUMS
)
{
if
(
data
!=
0
)
return
-
EINVAL
;
return
0
;
}
if
(
data
)
dev
->
features
|=
NETIF_F_IP_CSUM
;
else
dev
->
features
&=
~
NETIF_F_IP_CSUM
;
tg3_netif_stop
(
tp
);
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
tp
->
rx_pending
=
ering
.
rx_pending
;
tp
->
rx_jumbo_pending
=
ering
.
rx_jumbo_pending
;
tp
->
tx_pending
=
ering
.
tx_pending
;
tg3_halt
(
tp
);
tg3_init_hw
(
tp
);
netif_wake_queue
(
tp
->
dev
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
tg3_netif_start
(
tp
);
return
0
;
}
case
ETHTOOL_GPAUSEPARAM
:
{
struct
ethtool_pauseparam
epause
=
{
ETHTOOL_GPAUSEPARAM
};
epause
.
autoneg
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_AUTONEG
)
!=
0
;
epause
.
rx_pause
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_RX
)
!=
0
;
epause
.
tx_pause
=
(
tp
->
tg3_flags
&
TG3_FLAG_PAUSE_TX
)
!=
0
;
if
(
copy_to_user
(
useraddr
,
&
epause
,
sizeof
(
epause
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SPAUSEPARAM
:
{
struct
ethtool_pauseparam
epause
;
if
(
copy_from_user
(
&
epause
,
useraddr
,
sizeof
(
epause
)))
return
-
EFAULT
;
tg3_netif_stop
(
tp
);
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
if
(
epause
.
autoneg
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_AUTONEG
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_AUTONEG
;
if
(
epause
.
rx_pause
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_RX
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_RX
;
if
(
epause
.
tx_pause
)
tp
->
tg3_flags
|=
TG3_FLAG_PAUSE_TX
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_PAUSE_TX
;
tg3_halt
(
tp
);
tg3_init_hw
(
tp
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
tg3_netif_start
(
tp
);
return
0
;
}
case
ETHTOOL_GRXCSUM
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GRXCSUM
};
edata
.
data
=
(
tp
->
tg3_flags
&
TG3_FLAG_RX_CHECKSUMS
)
!=
0
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SRXCSUM
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_BROKEN_CHECKSUMS
)
{
if
(
edata
.
data
!=
0
)
return
-
EINVAL
;
return
0
;
}
spin_lock_irq
(
&
tp
->
lock
);
if
(
edata
.
data
)
tp
->
tg3_flags
|=
TG3_FLAG_RX_CHECKSUMS
;
else
tp
->
tg3_flags
&=
~
TG3_FLAG_RX_CHECKSUMS
;
spin_unlock_irq
(
&
tp
->
lock
);
return
0
;
}
case
ETHTOOL_GTXCSUM
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GTXCSUM
};
edata
.
data
=
(
tp
->
dev
->
features
&
NETIF_F_IP_CSUM
)
!=
0
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_STXCSUM
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_BROKEN_CHECKSUMS
)
{
if
(
edata
.
data
!=
0
)
return
-
EINVAL
;
return
0
;
}
if
(
edata
.
data
)
tp
->
dev
->
features
|=
NETIF_F_IP_CSUM
;
else
tp
->
dev
->
features
&=
~
NETIF_F_IP_CSUM
;
return
0
;
}
case
ETHTOOL_GSG
:
{
struct
ethtool_value
edata
=
{
ETHTOOL_GSG
};
edata
.
data
=
(
tp
->
dev
->
features
&
NETIF_F_SG
)
!=
0
;
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
case
ETHTOOL_SSG
:
{
struct
ethtool_value
edata
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
if
(
edata
.
data
)
tp
->
dev
->
features
|=
NETIF_F_SG
;
else
tp
->
dev
->
features
&=
~
NETIF_F_SG
;
return
0
;
}
};
return
-
EOPNOTSUPP
;
return
0
;
}
static
int
tg3_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
{
struct
mii_ioctl_data
*
data
=
(
struct
mii_ioctl_data
*
)
&
ifr
->
ifr_data
;
...
...
@@ -5503,8 +5382,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
int
err
;
switch
(
cmd
)
{
case
SIOCETHTOOL
:
return
tg3_ethtool_ioctl
(
dev
,
(
void
*
)
ifr
->
ifr_data
);
case
SIOCGMIIPHY
:
data
->
phy_id
=
PHY_ADDR
;
...
...
@@ -5568,6 +5445,30 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
}
#endif
static
struct
ethtool_ops
tg3_ethtool_ops
=
{
.
get_settings
=
tg3_get_settings
,
.
set_settings
=
tg3_set_settings
,
.
get_drvinfo
=
tg3_get_drvinfo
,
.
get_regs_len
=
tg3_get_regs_len
,
.
get_regs
=
tg3_get_regs
,
.
get_wol
=
tg3_get_wol
,
.
set_wol
=
tg3_set_wol
,
.
get_msglevel
=
tg3_get_msglevel
,
.
set_msglevel
=
tg3_set_msglevel
,
.
nway_reset
=
tg3_nway_reset
,
.
get_link
=
ethtool_op_get_link
,
.
get_ringparam
=
tg3_get_ringparam
,
.
set_ringparam
=
tg3_set_ringparam
,
.
get_pauseparam
=
tg3_get_pauseparam
,
.
set_pauseparam
=
tg3_set_pauseparam
,
.
get_rx_csum
=
tg3_get_rx_csum
,
.
set_rx_csum
=
tg3_set_rx_csum
,
.
get_tx_csum
=
ethtool_op_get_tx_csum
,
.
set_tx_csum
=
tg3_set_tx_csum
,
.
get_sg
=
ethtool_op_get_sg
,
.
set_sg
=
ethtool_op_set_sg
,
};
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static
void
__devinit
tg3_nvram_init
(
struct
tg3
*
tp
)
{
...
...
@@ -6880,6 +6781,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev
->
do_ioctl
=
tg3_ioctl
;
dev
->
tx_timeout
=
tg3_tx_timeout
;
dev
->
poll
=
tg3_poll
;
dev
->
ethtool_ops
=
&
tg3_ethtool_ops
;
dev
->
weight
=
64
;
dev
->
watchdog_timeo
=
TG3_TX_TIMEOUT
;
dev
->
change_mtu
=
tg3_change_mtu
;
...
...
include/linux/ethtool.h
View file @
86635435
...
...
@@ -97,7 +97,7 @@ struct ethtool_coalesce {
u32
rx_max_coalesced_frames
;
/* Same as above two parameters, except that these values
* apply while an IRQ is being service
s
by the host. Not
* apply while an IRQ is being service
d
by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
...
...
@@ -119,7 +119,7 @@ struct ethtool_coalesce {
u32
tx_max_coalesced_frames
;
/* Same as above two parameters, except that these values
* apply while an IRQ is being service
s
by the host. Not
* apply while an IRQ is being service
d
by the host. Not
* all cards support this feature and the values are ignored
* in that case.
*/
...
...
@@ -250,6 +250,101 @@ struct ethtool_stats {
u64
data
[
0
];
};
struct
net_device
;
/* Some generic methods drivers may use in their ethtool_ops */
u32
ethtool_op_get_link
(
struct
net_device
*
dev
);
u32
ethtool_op_get_tx_csum
(
struct
net_device
*
dev
);
u32
ethtool_op_get_sg
(
struct
net_device
*
dev
);
int
ethtool_op_set_sg
(
struct
net_device
*
dev
,
u32
data
);
/**
* ðtool_ops - Alter and report network device settings
* get_settings: Get device-specific settings
* set_settings: Set device-specific settings
* get_drvinfo: Report driver information
* get_regs: Get device registers
* get_wol: Report whether Wake-on-Lan is enabled
* set_wol: Turn Wake-on-Lan on or off
* get_msglevel: Report driver message level
* set_msglevel: Set driver message level
* nway_reset: Restart autonegotiation
* get_link: Get link status
* get_eeprom: Read data from the device EEPROM
* set_eeprom: Write data to the device EEPROM
* get_coalesce: Get interrupt coalescing parameters
* set_coalesce: Set interrupt coalescing parameters
* get_ringparam: Report ring sizes
* set_ringparam: Set ring sizes
* get_pauseparam: Report pause parameters
* set_pauseparam: Set pause paramters
* get_rx_csum: Report whether receive checksums are turned on or off
* set_rx_csum: Turn receive checksum on or off
* get_tx_csum: Report whether transmit checksums are turned on or off
* set_tx_csum: Turn transmit checksums on or off
* get_sg: Report whether scatter-gather is enabled
* set_sg: Turn scatter-gather on or off
* self_test: Run specified self-tests
* get_strings: Return a set of strings that describe the requested objects
* phys_id: Identify the device
* get_stats: Return statistics about the device
*
* Description:
*
* get_settings:
* @get_settings is passed an ðtool_cmd to fill in. It returns
* an negative errno or zero.
*
* set_settings:
* @set_settings is passed an ðtool_cmd and should attempt to set
* all the settings this device supports. It may return an error value
* if something goes wrong (otherwise 0).
*
* get_eeprom:
* Should fill in the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Fill in the data
* argument with the eeprom values from offset to offset + len. Update
* len to the amount read. Returns an error or zero.
*
* set_eeprom:
* Should validate the magic field. Don't need to check len for zero
* or wraparound but must check offset + len < size. Update len to
* the amount written. Returns an error or zero.
*/
struct
ethtool_ops
{
int
(
*
get_settings
)(
struct
net_device
*
,
struct
ethtool_cmd
*
);
int
(
*
set_settings
)(
struct
net_device
*
,
struct
ethtool_cmd
*
);
void
(
*
get_drvinfo
)(
struct
net_device
*
,
struct
ethtool_drvinfo
*
);
int
(
*
get_regs_len
)(
struct
net_device
*
);
void
(
*
get_regs
)(
struct
net_device
*
,
struct
ethtool_regs
*
,
void
*
);
void
(
*
get_wol
)(
struct
net_device
*
,
struct
ethtool_wolinfo
*
);
int
(
*
set_wol
)(
struct
net_device
*
,
struct
ethtool_wolinfo
*
);
u32
(
*
get_msglevel
)(
struct
net_device
*
);
void
(
*
set_msglevel
)(
struct
net_device
*
,
u32
);
int
(
*
nway_reset
)(
struct
net_device
*
);
u32
(
*
get_link
)(
struct
net_device
*
);
int
(
*
get_eeprom
)(
struct
net_device
*
,
struct
ethtool_eeprom
*
,
u8
*
);
int
(
*
set_eeprom
)(
struct
net_device
*
,
struct
ethtool_eeprom
*
,
u8
*
);
int
(
*
get_coalesce
)(
struct
net_device
*
,
struct
ethtool_coalesce
*
);
int
(
*
set_coalesce
)(
struct
net_device
*
,
struct
ethtool_coalesce
*
);
void
(
*
get_ringparam
)(
struct
net_device
*
,
struct
ethtool_ringparam
*
);
int
(
*
set_ringparam
)(
struct
net_device
*
,
struct
ethtool_ringparam
*
);
void
(
*
get_pauseparam
)(
struct
net_device
*
,
struct
ethtool_pauseparam
*
);
int
(
*
set_pauseparam
)(
struct
net_device
*
,
struct
ethtool_pauseparam
*
);
u32
(
*
get_rx_csum
)(
struct
net_device
*
);
int
(
*
set_rx_csum
)(
struct
net_device
*
,
u32
);
u32
(
*
get_tx_csum
)(
struct
net_device
*
);
int
(
*
set_tx_csum
)(
struct
net_device
*
,
u32
);
u32
(
*
get_sg
)(
struct
net_device
*
);
int
(
*
set_sg
)(
struct
net_device
*
,
u32
);
int
(
*
self_test_count
)(
struct
net_device
*
);
void
(
*
self_test
)(
struct
net_device
*
,
struct
ethtool_test
*
,
u64
*
);
void
(
*
get_strings
)(
struct
net_device
*
,
u32
stringset
,
u8
*
);
int
(
*
phys_id
)(
struct
net_device
*
,
u32
);
int
(
*
get_stats_count
)(
struct
net_device
*
);
void
(
*
get_ethtool_stats
)(
struct
net_device
*
,
struct
ethtool_stats
*
,
u64
*
);
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001
/* Get settings. */
#define ETHTOOL_SSET 0x00000002
/* Set settings. */
...
...
include/linux/netdevice.h
View file @
86635435
...
...
@@ -43,6 +43,11 @@
struct
divert_blk
;
struct
vlan_group
;
struct
ethtool_ops
;
/* source back-compat hook */
#define SET_ETHTOOL_OPS(netdev,ops) \
( (netdev)->ethtool_ops = (ops) )
#define HAVE_ALLOC_NETDEV
/* feature macro: alloc_xxxdev
functions are available. */
...
...
@@ -300,6 +305,8 @@ struct net_device
* See <net/iw_handler.h> for details. Jean II */
struct
iw_handler_def
*
wireless_handlers
;
struct
ethtool_ops
*
ethtool_ops
;
/*
* This marks the end of the "visible" part of the structure. All
* fields hereafter are internal to the system, and may change at
...
...
@@ -482,7 +489,6 @@ struct packet_type
struct
list_head
list
;
};
#include <linux/interrupt.h>
#include <linux/notifier.h>
...
...
@@ -630,6 +636,7 @@ extern int netif_rx(struct sk_buff *skb);
#define HAVE_NETIF_RECEIVE_SKB 1
extern
int
netif_receive_skb
(
struct
sk_buff
*
skb
);
extern
int
dev_ioctl
(
unsigned
int
cmd
,
void
*
);
extern
int
dev_ethtool
(
struct
ifreq
*
);
extern
unsigned
dev_get_flags
(
const
struct
net_device
*
);
extern
int
dev_change_flags
(
struct
net_device
*
,
unsigned
);
extern
int
dev_set_mtu
(
struct
net_device
*
,
int
);
...
...
net/core/Makefile
View file @
86635435
...
...
@@ -6,8 +6,8 @@ obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
obj-$(CONFIG_SYSCTL)
+=
sysctl_net_core.o
obj-y
+=
flow.o dev.o
net-sysfs.o dev_mcast.o dst.o neighbour
.o
\
rtnetlink.o utils.o link_watch.o filter.o
obj-y
+=
flow.o dev.o
ethtool.o net-sysfs.o dev_mcast.o dst
.o
\
neighbour.o
rtnetlink.o utils.o link_watch.o filter.o
obj-$(CONFIG_NETFILTER)
+=
netfilter.o
obj-$(CONFIG_NET_DIVERT)
+=
dv.o
...
...
net/core/dev.c
View file @
86635435
...
...
@@ -2368,7 +2368,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
cmd
==
SIOCBONDSLAVEINFOQUERY
||
cmd
==
SIOCBONDINFOQUERY
||
cmd
==
SIOCBONDCHANGEACTIVE
||
cmd
==
SIOCETHTOOL
||
cmd
==
SIOCGMIIPHY
||
cmd
==
SIOCGMIIREG
||
cmd
==
SIOCSMIIREG
||
...
...
@@ -2465,13 +2464,26 @@ int dev_ioctl(unsigned int cmd, void *arg)
}
return
ret
;
case
SIOCETHTOOL
:
dev_load
(
ifr
.
ifr_name
);
rtnl_lock
();
ret
=
dev_ethtool
(
&
ifr
);
rtnl_unlock
();
if
(
!
ret
)
{
if
(
colon
)
*
colon
=
':'
;
if
(
copy_to_user
(
arg
,
&
ifr
,
sizeof
(
struct
ifreq
)))
ret
=
-
EFAULT
;
}
return
ret
;
/*
* These ioctl calls:
* - require superuser power.
* - require strict serialization.
* - return a value
*/
case
SIOCETHTOOL
:
case
SIOCGMIIPHY
:
case
SIOCGMIIREG
:
if
(
!
capable
(
CAP_NET_ADMIN
))
...
...
net/core/ethtool.c
0 → 100644
View file @
86635435
/*
* net/core/ethtool.c - Ethtool ioctl handler
* Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
*
* This file is where we call all the ethtool_ops commands to get
* the information ethtool needs. We fall back to calling do_ioctl()
* for drivers which haven't been converted to ethtool_ops yet.
*
* It's GPL, stupid.
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
/*
* Some useful ethtool_ops methods that're device independent.
* If we find that all drivers want to do the same thing here,
* we can turn these into dev_() function calls.
*/
u32
ethtool_op_get_link
(
struct
net_device
*
dev
)
{
return
netif_carrier_ok
(
dev
)
?
1
:
0
;
}
u32
ethtool_op_get_tx_csum
(
struct
net_device
*
dev
)
{
return
(
dev
->
features
&
NETIF_F_IP_CSUM
)
!=
0
;
}
u32
ethtool_op_get_sg
(
struct
net_device
*
dev
)
{
return
(
dev
->
features
&
NETIF_F_SG
)
!=
0
;
}
int
ethtool_op_set_sg
(
struct
net_device
*
dev
,
u32
data
)
{
if
(
data
)
dev
->
features
|=
NETIF_F_SG
;
else
dev
->
features
&=
~
NETIF_F_SG
;
return
0
;
}
/* Handlers for each ethtool command */
static
int
ethtool_get_settings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_cmd
cmd
=
{
ETHTOOL_GSET
};
int
err
;
if
(
!
dev
->
ethtool_ops
->
get_settings
)
return
-
EOPNOTSUPP
;
err
=
dev
->
ethtool_ops
->
get_settings
(
dev
,
&
cmd
);
if
(
err
<
0
)
return
err
;
if
(
copy_to_user
(
useraddr
,
&
cmd
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_settings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_cmd
cmd
;
if
(
!
dev
->
ethtool_ops
->
set_settings
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
cmd
,
useraddr
,
sizeof
(
cmd
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_settings
(
dev
,
&
cmd
);
}
static
int
ethtool_get_drvinfo
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_drvinfo
info
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
if
(
!
ops
->
get_drvinfo
)
return
-
EOPNOTSUPP
;
memset
(
&
info
,
0
,
sizeof
(
info
));
info
.
cmd
=
ETHTOOL_GDRVINFO
;
ops
->
get_drvinfo
(
dev
,
&
info
);
if
(
ops
->
self_test_count
)
info
.
testinfo_len
=
ops
->
self_test_count
(
dev
);
if
(
ops
->
get_stats_count
)
info
.
n_stats
=
ops
->
get_stats_count
(
dev
);
if
(
ops
->
get_regs_len
)
info
.
regdump_len
=
ops
->
get_regs_len
(
dev
);
/* XXX: eeprom? */
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_get_regs
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_regs
regs
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
void
*
regbuf
;
int
reglen
,
ret
;
if
(
!
ops
->
get_regs
||
!
ops
->
get_regs_len
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
regs
,
useraddr
,
sizeof
(
regs
)))
return
-
EFAULT
;
reglen
=
ops
->
get_regs_len
(
dev
);
if
(
regs
.
len
>
reglen
)
regs
.
len
=
reglen
;
regbuf
=
kmalloc
(
reglen
,
GFP_USER
);
if
(
!
regbuf
)
return
-
ENOMEM
;
ops
->
get_regs
(
dev
,
&
regs
,
regbuf
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
regs
,
sizeof
(
regs
)))
goto
out
;
useraddr
+=
offsetof
(
struct
ethtool_regs
,
data
);
if
(
copy_to_user
(
useraddr
,
regbuf
,
reglen
))
goto
out
;
ret
=
0
;
out:
kfree
(
regbuf
);
return
ret
;
}
static
int
ethtool_get_wol
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_wolinfo
wol
=
{
ETHTOOL_GWOL
};
if
(
!
dev
->
ethtool_ops
->
get_wol
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_wol
(
dev
,
&
wol
);
if
(
copy_to_user
(
useraddr
,
&
wol
,
sizeof
(
wol
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_wol
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_wolinfo
wol
;
if
(
!
dev
->
ethtool_ops
->
set_wol
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
wol
,
useraddr
,
sizeof
(
wol
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_wol
(
dev
,
&
wol
);
}
static
int
ethtool_get_msglevel
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GMSGLVL
};
if
(
!
dev
->
ethtool_ops
->
get_msglevel
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_msglevel
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_msglevel
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_msglevel
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
dev
->
ethtool_ops
->
set_msglevel
(
dev
,
edata
.
data
);
return
0
;
}
static
int
ethtool_nway_reset
(
struct
net_device
*
dev
)
{
if
(
!
dev
->
ethtool_ops
->
nway_reset
)
return
-
EOPNOTSUPP
;
return
dev
->
ethtool_ops
->
nway_reset
(
dev
);
}
static
int
ethtool_get_link
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GLINK
};
if
(
!
dev
->
ethtool_ops
->
get_link
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_link
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_get_eeprom
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_eeprom
eeprom
;
u8
*
data
;
int
len
,
ret
;
if
(
!
dev
->
ethtool_ops
->
get_eeprom
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
eeprom
,
useraddr
,
sizeof
(
eeprom
)))
return
-
EFAULT
;
len
=
eeprom
.
len
;
/* Check for wrap and zero */
if
(
eeprom
.
offset
+
len
<=
eeprom
.
offset
)
return
-
EINVAL
;
data
=
kmalloc
(
len
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
if
(
copy_from_user
(
data
,
useraddr
+
sizeof
(
eeprom
),
len
))
return
-
EFAULT
;
ret
=
dev
->
ethtool_ops
->
get_eeprom
(
dev
,
&
eeprom
,
data
);
if
(
!
ret
)
goto
out
;
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
eeprom
,
sizeof
(
eeprom
)))
goto
out
;
if
(
copy_to_user
(
useraddr
+
sizeof
(
eeprom
),
data
,
eeprom
.
len
))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_set_eeprom
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_eeprom
eeprom
;
u8
*
data
;
int
len
,
ret
;
if
(
!
dev
->
ethtool_ops
->
set_eeprom
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
eeprom
,
useraddr
,
sizeof
(
eeprom
)))
return
-
EFAULT
;
len
=
eeprom
.
len
;
/* Check for wrap and zero */
if
(
eeprom
.
offset
+
len
<=
eeprom
.
offset
)
return
-
EINVAL
;
data
=
kmalloc
(
len
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
if
(
copy_from_user
(
data
,
useraddr
+
sizeof
(
eeprom
),
len
))
return
-
EFAULT
;
ret
=
dev
->
ethtool_ops
->
set_eeprom
(
dev
,
&
eeprom
,
data
);
if
(
ret
)
goto
out
;
if
(
copy_to_user
(
useraddr
+
sizeof
(
eeprom
),
data
,
len
))
ret
=
-
EFAULT
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_get_coalesce
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_coalesce
coalesce
=
{
ETHTOOL_GCOALESCE
};
if
(
!
dev
->
ethtool_ops
->
get_coalesce
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_coalesce
(
dev
,
&
coalesce
);
if
(
copy_to_user
(
useraddr
,
&
coalesce
,
sizeof
(
coalesce
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_coalesce
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_coalesce
coalesce
;
if
(
!
dev
->
ethtool_ops
->
get_coalesce
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
coalesce
,
useraddr
,
sizeof
(
coalesce
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_coalesce
(
dev
,
&
coalesce
);
}
static
int
ethtool_get_ringparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_ringparam
ringparam
=
{
ETHTOOL_GRINGPARAM
};
if
(
!
dev
->
ethtool_ops
->
get_ringparam
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_ringparam
(
dev
,
&
ringparam
);
if
(
copy_to_user
(
useraddr
,
&
ringparam
,
sizeof
(
ringparam
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_ringparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_ringparam
ringparam
;
if
(
!
dev
->
ethtool_ops
->
get_ringparam
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
ringparam
,
useraddr
,
sizeof
(
ringparam
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_ringparam
(
dev
,
&
ringparam
);
}
static
int
ethtool_get_pauseparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_pauseparam
pauseparam
=
{
ETHTOOL_GPAUSEPARAM
};
if
(
!
dev
->
ethtool_ops
->
get_pauseparam
)
return
-
EOPNOTSUPP
;
dev
->
ethtool_ops
->
get_pauseparam
(
dev
,
&
pauseparam
);
if
(
copy_to_user
(
useraddr
,
&
pauseparam
,
sizeof
(
pauseparam
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_pauseparam
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_pauseparam
pauseparam
;
if
(
!
dev
->
ethtool_ops
->
get_pauseparam
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
pauseparam
,
useraddr
,
sizeof
(
pauseparam
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_pauseparam
(
dev
,
&
pauseparam
);
}
static
int
ethtool_get_rx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GRXCSUM
};
if
(
!
dev
->
ethtool_ops
->
get_rx_csum
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_rx_csum
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_rx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_rx_csum
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
dev
->
ethtool_ops
->
set_rx_csum
(
dev
,
edata
.
data
);
return
0
;
}
static
int
ethtool_get_tx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GTXCSUM
};
if
(
!
dev
->
ethtool_ops
->
get_tx_csum
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_tx_csum
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_tx_csum
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_tx_csum
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_tx_csum
(
dev
,
edata
.
data
);
}
static
int
ethtool_get_sg
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
=
{
ETHTOOL_GSG
};
if
(
!
dev
->
ethtool_ops
->
get_sg
)
return
-
EOPNOTSUPP
;
edata
.
data
=
dev
->
ethtool_ops
->
get_sg
(
dev
);
if
(
copy_to_user
(
useraddr
,
&
edata
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
0
;
}
static
int
ethtool_set_sg
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_value
edata
;
if
(
!
dev
->
ethtool_ops
->
set_sg
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
edata
,
useraddr
,
sizeof
(
edata
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
set_sg
(
dev
,
edata
.
data
);
}
static
int
ethtool_self_test
(
struct
net_device
*
dev
,
char
*
useraddr
)
{
struct
ethtool_test
test
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u64
*
data
;
int
ret
;
if
(
!
ops
->
self_test
||
!
ops
->
self_test_count
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
test
,
useraddr
,
sizeof
(
test
)))
return
-
EFAULT
;
test
.
len
=
ops
->
self_test_count
(
dev
);
data
=
kmalloc
(
test
.
len
*
sizeof
(
u64
),
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
self_test
(
dev
,
&
test
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
test
,
sizeof
(
test
)))
goto
out
;
useraddr
+=
sizeof
(
test
);
if
(
copy_to_user
(
useraddr
,
data
,
test
.
len
*
sizeof
(
u64
)))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_get_strings
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_gstrings
gstrings
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u8
*
data
;
int
ret
;
if
(
!
ops
->
get_strings
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
gstrings
,
useraddr
,
sizeof
(
gstrings
)))
return
-
EFAULT
;
switch
(
gstrings
.
string_set
)
{
case
ETH_SS_TEST
:
if
(
ops
->
self_test_count
)
gstrings
.
len
=
ops
->
self_test_count
(
dev
);
else
return
-
EOPNOTSUPP
;
case
ETH_SS_STATS
:
if
(
ops
->
get_stats_count
)
gstrings
.
len
=
ops
->
get_stats_count
(
dev
);
else
return
-
EOPNOTSUPP
;
default:
return
-
EINVAL
;
}
data
=
kmalloc
(
gstrings
.
len
*
ETH_GSTRING_LEN
,
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
get_strings
(
dev
,
gstrings
.
string_set
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
gstrings
,
sizeof
(
gstrings
)))
goto
out
;
useraddr
+=
sizeof
(
gstrings
);
if
(
copy_to_user
(
useraddr
,
data
,
gstrings
.
len
*
ETH_GSTRING_LEN
))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
static
int
ethtool_phys_id
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_value
id
;
if
(
!
dev
->
ethtool_ops
->
phys_id
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
id
,
useraddr
,
sizeof
(
id
)))
return
-
EFAULT
;
return
dev
->
ethtool_ops
->
phys_id
(
dev
,
id
.
data
);
}
static
int
ethtool_get_stats
(
struct
net_device
*
dev
,
void
*
useraddr
)
{
struct
ethtool_stats
stats
;
struct
ethtool_ops
*
ops
=
dev
->
ethtool_ops
;
u64
*
data
;
int
ret
;
if
(
!
ops
->
get_ethtool_stats
||
!
ops
->
get_stats_count
)
return
-
EOPNOTSUPP
;
if
(
copy_from_user
(
&
stats
,
useraddr
,
sizeof
(
stats
)))
return
-
EFAULT
;
stats
.
n_stats
=
ops
->
get_stats_count
(
dev
);
data
=
kmalloc
(
stats
.
n_stats
*
sizeof
(
u64
),
GFP_USER
);
if
(
!
data
)
return
-
ENOMEM
;
ops
->
get_ethtool_stats
(
dev
,
&
stats
,
data
);
ret
=
-
EFAULT
;
if
(
copy_to_user
(
useraddr
,
&
stats
,
sizeof
(
stats
)))
goto
out
;
useraddr
+=
sizeof
(
stats
);
if
(
copy_to_user
(
useraddr
,
data
,
stats
.
n_stats
*
sizeof
(
u64
)))
goto
out
;
ret
=
0
;
out:
kfree
(
data
);
return
ret
;
}
/* The main entry point in this file. Called from net/core/dev.c */
int
dev_ethtool
(
struct
ifreq
*
ifr
)
{
struct
net_device
*
dev
=
__dev_get_by_name
(
ifr
->
ifr_name
);
void
*
useraddr
=
(
void
*
)
ifr
->
ifr_data
;
u32
ethcmd
;
/*
* XXX: This can be pushed down into the ethtool_* handlers that
* need it. Keep existing behaviour for the moment.
*/
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
!
dev
||
!
netif_device_present
(
dev
))
return
-
ENODEV
;
if
(
!
dev
->
ethtool_ops
)
goto
ioctl
;
if
(
copy_from_user
(
&
ethcmd
,
useraddr
,
sizeof
(
ethcmd
)))
return
-
EFAULT
;
switch
(
ethcmd
)
{
case
ETHTOOL_GSET
:
return
ethtool_get_settings
(
dev
,
useraddr
);
case
ETHTOOL_SSET
:
return
ethtool_set_settings
(
dev
,
useraddr
);
case
ETHTOOL_GDRVINFO
:
return
ethtool_get_drvinfo
(
dev
,
useraddr
);
case
ETHTOOL_GREGS
:
return
ethtool_get_regs
(
dev
,
useraddr
);
case
ETHTOOL_GWOL
:
return
ethtool_get_wol
(
dev
,
useraddr
);
case
ETHTOOL_SWOL
:
return
ethtool_set_wol
(
dev
,
useraddr
);
case
ETHTOOL_GMSGLVL
:
return
ethtool_get_msglevel
(
dev
,
useraddr
);
case
ETHTOOL_SMSGLVL
:
return
ethtool_set_msglevel
(
dev
,
useraddr
);
case
ETHTOOL_NWAY_RST
:
return
ethtool_nway_reset
(
dev
);
case
ETHTOOL_GLINK
:
return
ethtool_get_link
(
dev
,
useraddr
);
case
ETHTOOL_GEEPROM
:
return
ethtool_get_eeprom
(
dev
,
useraddr
);
case
ETHTOOL_SEEPROM
:
return
ethtool_set_eeprom
(
dev
,
useraddr
);
case
ETHTOOL_GCOALESCE
:
return
ethtool_get_coalesce
(
dev
,
useraddr
);
case
ETHTOOL_SCOALESCE
:
return
ethtool_set_coalesce
(
dev
,
useraddr
);
case
ETHTOOL_GRINGPARAM
:
return
ethtool_get_ringparam
(
dev
,
useraddr
);
case
ETHTOOL_SRINGPARAM
:
return
ethtool_set_ringparam
(
dev
,
useraddr
);
case
ETHTOOL_GPAUSEPARAM
:
return
ethtool_get_pauseparam
(
dev
,
useraddr
);
case
ETHTOOL_SPAUSEPARAM
:
return
ethtool_set_pauseparam
(
dev
,
useraddr
);
case
ETHTOOL_GRXCSUM
:
return
ethtool_get_rx_csum
(
dev
,
useraddr
);
case
ETHTOOL_SRXCSUM
:
return
ethtool_set_rx_csum
(
dev
,
useraddr
);
case
ETHTOOL_GTXCSUM
:
return
ethtool_get_tx_csum
(
dev
,
useraddr
);
case
ETHTOOL_STXCSUM
:
return
ethtool_set_tx_csum
(
dev
,
useraddr
);
case
ETHTOOL_GSG
:
return
ethtool_get_sg
(
dev
,
useraddr
);
case
ETHTOOL_SSG
:
return
ethtool_set_sg
(
dev
,
useraddr
);
case
ETHTOOL_TEST
:
return
ethtool_self_test
(
dev
,
useraddr
);
case
ETHTOOL_GSTRINGS
:
return
ethtool_get_strings
(
dev
,
useraddr
);
case
ETHTOOL_PHYS_ID
:
return
ethtool_phys_id
(
dev
,
useraddr
);
case
ETHTOOL_GSTATS
:
return
ethtool_get_stats
(
dev
,
useraddr
);
default:
return
-
EOPNOTSUPP
;
}
ioctl:
if
(
dev
->
do_ioctl
)
return
dev
->
do_ioctl
(
dev
,
ifr
,
SIOCETHTOOL
);
return
-
EOPNOTSUPP
;
}
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